changeset 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 0eb807bd8942
children 34354e2e40a3
files c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotField.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/InvocationSocket.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntries.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntriesNative.java c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/server/ReplacingStreams.java
diffstat 6 files changed, 160 insertions(+), 25 deletions(-) [+]
line wrap: on
line diff
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotField.java	Mon Apr 11 18:01:44 2011 +0200
+++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotField.java	Tue Apr 12 16:58:56 2011 +0200
@@ -59,7 +59,7 @@
     @Override
     public CiConstant constantValue(CiConstant receiver) {
         if (receiver == null) {
-            if (constant == null && holder.isResolved() && holder.javaClass() == C1XOptions.class) {
+            if (constant == null && holder.isResolved() && holder.isSubtypeOf(compiler.getVMEntries().getType(C1XOptions.class))) {
                 Field f;
                 try {
                     f = C1XOptions.class.getField(name);
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java	Mon Apr 11 18:01:44 2011 +0200
+++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java	Tue Apr 12 16:58:56 2011 +0200
@@ -157,11 +157,7 @@
 
     @Override
     public RiType getRiType(CiConstant constant) {
-        Object o = constant.asObject();
-        if (o == null) {
-            return null;
-        }
-        return getRiType(o.getClass());
+        return compiler.getVMEntries().getRiType(constant);
     }
 
     @Override
@@ -232,7 +228,7 @@
 
     @Override
     public boolean compareConstantObjects(CiConstant x, CiConstant y) {
-        return x.asObject() == y.asObject();
+        return compiler.getVMEntries().compareConstantObjects(x, y);
     }
 
     @Override
@@ -255,6 +251,6 @@
 
     @Override
     public int getArrayLength(CiConstant array) {
-        return Array.getLength(array.asObject());
+        return compiler.getVMEntries().getArrayLength(array);
     }
 }
--- 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();
     }
-
 }
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntries.java	Mon Apr 11 18:01:44 2011 +0200
+++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntries.java	Tue Apr 12 16:58:56 2011 +0200
@@ -88,5 +88,12 @@
     RiType RiType_uniqueConcreteSubtype(HotSpotTypeResolved hotSpotTypeResolved);
 
     RiType RiType_superType(HotSpotTypeResolved hotSpotTypeResolved);
+
+    int getArrayLength(CiConstant array);
+
+    boolean compareConstantObjects(CiConstant x, CiConstant y);
+
+    RiType getRiType(CiConstant constant);
+
     // Checkstyle: resume
 }
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntriesNative.java	Mon Apr 11 18:01:44 2011 +0200
+++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntriesNative.java	Tue Apr 12 16:58:56 2011 +0200
@@ -21,6 +21,8 @@
 
 package com.sun.hotspot.c1x;
 
+import java.lang.reflect.*;
+
 import com.sun.cri.ci.*;
 import com.sun.cri.ri.*;
 import com.sun.hotspot.c1x.server.*;
@@ -117,5 +119,24 @@
     @Override
     public native RiMethod RiMethod_uniqueConcreteMethod(long vmId);
 
+    @Override
+    public int getArrayLength(CiConstant array) {
+        return Array.getLength(array.asObject());
+    }
+
+    @Override
+    public boolean compareConstantObjects(CiConstant x, CiConstant y) {
+        return x.asObject() == y.asObject();
+    }
+
+    @Override
+    public RiType getRiType(CiConstant constant) {
+        Object o = constant.asObject();
+        if (o == null) {
+            return null;
+        }
+        return getType(o.getClass());
+    }
+
     // Checkstyle: resume
 }
--- a/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/server/ReplacingStreams.java	Mon Apr 11 18:01:44 2011 +0200
+++ b/c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/server/ReplacingStreams.java	Tue Apr 12 16:58:56 2011 +0200
@@ -46,6 +46,7 @@
         invocation = new InvocationSocket(output, input);
 
         addStaticObject(CiValue.IllegalValue);
+        addStaticObject(HotSpotProxy.DUMMY_CONSTANT_OBJ);
     }
 
     public void setInvocationSocket(InvocationSocket invocation) {
@@ -167,12 +168,26 @@
 
             // is the object a constant of object type?
             if (obj.getClass() == CiConstant.class) {
-                System.out.println("CiConstant " + obj);
                 CiConstant constant = (CiConstant) obj;
+                if (constant.kind != CiKind.Object) {
+                    return obj;
+                }
+                Object contents = constant.asObject();
+                if (contents == null) {
+                    return obj;
+                }
                 // don't replace if the object already is a placeholder
-                if (constant.kind == CiKind.Object && !(constant.asObject() instanceof Placeholder) && constant.asObject() != null) {
-                    return CiConstant.forObject(createDummyPlaceholder(constant.asObject()));
+                if (contents instanceof Placeholder || contents instanceof Long) {
+                    return obj;
                 }
+                placeholder = objectMap.get(contents);
+                if (placeholder != null) {
+                    return CiConstant.forObject(placeholder);
+                }
+                if (contents instanceof Remote) {
+                    return CiConstant.forObject(createRemoteCallPlaceholder(contents));
+                }
+                return CiConstant.forObject(createDummyPlaceholder(contents));
             }
             return obj;
         }