# HG changeset patch # User Lukas Stadler # Date 1302620336 -7200 # Node ID 160aacf936ad0b66bc76e3f741bf726a575ac4ce # Parent 0eb807bd894206143db2cd731af351f22e126ded removed last instances of RiType.javaClass, small changes to InvocationSocket and ReplacingStreams to make remote compilation work diff -r 0eb807bd8942 -r 160aacf936ad c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotField.java --- 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); diff -r 0eb807bd8942 -r 160aacf936ad c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/HotSpotRuntime.java --- 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); } } diff -r 0eb807bd8942 -r 160aacf936ad c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/InvocationSocket.java --- 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 cachedMethodNames = new HashSet(); + private static final HashSet forbiddenMethodNames = new HashSet(); + + 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 counts = new HashMap(); + 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 sorted = new TreeMap(); + for (Map.Entry entry : counts.entrySet()) { + sorted.put(entry.getValue(), entry.getKey()); + } + for (Map.Entry 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 cache = new HashMap(); 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(); } - } diff -r 0eb807bd8942 -r 160aacf936ad c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntries.java --- 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 } diff -r 0eb807bd8942 -r 160aacf936ad c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/VMEntriesNative.java --- 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 } diff -r 0eb807bd8942 -r 160aacf936ad c1x4hotspotsrc/HotSpotVM/src/com/sun/hotspot/c1x/server/ReplacingStreams.java --- 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; }