changeset 18365:a8bc8724657e

expanded support for shared globals (i.e., values that must be retrieved from static fields instead of being copied in replay/remote compilation)
author Doug Simon <doug.simon@oracle.com>
date Thu, 13 Nov 2014 16:48:17 +0100
parents ad3c2cacdd1a
children c09fc2864097
files graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/remote/Context.java
diffstat 1 files changed, 85 insertions(+), 17 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/remote/Context.java	Thu Nov 13 15:07:10 2014 +0100
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/remote/Context.java	Thu Nov 13 16:48:17 2014 +0100
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.compiler.common.remote;
 
+import static java.lang.reflect.Modifier.*;
+
 import java.lang.reflect.*;
 import java.nio.*;
 import java.util.*;
@@ -31,6 +33,7 @@
 import com.oracle.graal.api.code.Register.RegisterCategory;
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
 
 /**
  * Manages a context for replay or remote compilation.
@@ -92,16 +95,10 @@
     ));
     // @formatter:on
 
-    private static void registerStaticField(Class<?> declaringClass, String staticFieldName) {
+    private static void registerSharedGlobal(Class<?> declaringClass, String staticFieldName) {
         try {
-            Field f = declaringClass.getDeclaredField(staticFieldName);
-            assert Modifier.isStatic(f.getModifiers()) : f;
-            assert Modifier.isFinal(f.getModifiers()) : f;
-            assert !f.getType().isPrimitive() : f;
-            f.setAccessible(true);
-            Object obj = f.get(null);
-            Field existing = SpecialStaticFields.put(obj, f);
-            assert existing == null;
+            SharedGlobal global = new SharedGlobal(declaringClass.getDeclaredField(staticFieldName));
+            SharedGlobals.put(global.get(), global);
         } catch (NoSuchFieldException e) {
             // ignore non-existing fields
         } catch (Exception e) {
@@ -109,15 +106,86 @@
         }
     }
 
+    private static void registerSharedGlobals(Class<?> declaringClass, Class<?> staticFieldType) {
+        assert !staticFieldType.isPrimitive();
+        try {
+            for (Field f : declaringClass.getDeclaredFields()) {
+                if (isStatic(f.getModifiers()) && isFinal(f.getModifiers()) && !f.getType().isPrimitive()) {
+                    SharedGlobal global = new SharedGlobal(f);
+                    if (staticFieldType.isAssignableFrom(f.getType())) {
+                        SharedGlobals.put(global.get(), global);
+                    } else {
+                        Class<?> componentType = f.getType().getComponentType();
+                        if (componentType != null && staticFieldType.isAssignableFrom(componentType)) {
+                            Object[] vals = global.get();
+                            for (int i = 0; i < vals.length; i++) {
+                                SharedGlobal g = new SharedGlobal(f, i);
+                                Object obj = g.get();
+                                SharedGlobals.put(obj, g);
+                            }
+                        }
+                    }
+                }
+            }
+        } catch (Exception e) {
+            throw new GraalInternalError(e);
+        }
+    }
+
+    /**
+     * A shared global is a non-primitive value in a static final variable whose identity is
+     * important to the compiler. That is, equality tests against these values are performed with
+     * {@code ==} or these values are keys in identity hash maps.
+     */
+    static class SharedGlobal {
+        final Field staticField;
+        final Integer index;
+
+        public SharedGlobal(Field staticField) {
+            this(staticField, null);
+        }
+
+        public SharedGlobal(Field staticField, Integer index) {
+            int mods = staticField.getModifiers();
+            assert isStatic(mods) && isFinal(mods) && !staticField.getType().isPrimitive() : staticField;
+            staticField.setAccessible(true);
+            this.staticField = staticField;
+            this.index = index;
+        }
+
+        @SuppressWarnings("unchecked")
+        public <T> T get() {
+            try {
+                Object value = staticField.get(null);
+                if (index != null) {
+                    value = ((Object[]) value)[index.intValue()];
+                }
+                return (T) value;
+            } catch (Exception e) {
+                throw new GraalInternalError(e);
+            }
+        }
+
+        @Override
+        public String toString() {
+            String res = staticField.getDeclaringClass().getName() + "." + staticField.getName();
+            if (index != null) {
+                res += "[" + index + "]";
+            }
+            return res;
+        }
+    }
+
     /**
      * Objects that should not be copied but retrieved from final static fields.
      */
-    private static final Map<Object, Field> SpecialStaticFields = new IdentityHashMap<>();
+    private static final Map<Object, SharedGlobal> SharedGlobals = new IdentityHashMap<>();
     static {
-        registerStaticField(ByteOrder.class, "BIG_ENDIAN");
-        registerStaticField(ByteOrder.class, "LITTLE_ENDIAN");
-        registerStaticField(ArrayList.class, "EMPTY_ELEMENTDATA");
-        registerStaticField(ArrayList.class, "DEFAULTCAPACITY_EMPTY_ELEMENTDATA");
+        registerSharedGlobal(ByteOrder.class, "BIG_ENDIAN");
+        registerSharedGlobal(ByteOrder.class, "LITTLE_ENDIAN");
+        registerSharedGlobal(ArrayList.class, "EMPTY_ELEMENTDATA");
+        registerSharedGlobal(ArrayList.class, "DEFAULTCAPACITY_EMPTY_ELEMENTDATA");
+        registerSharedGlobals(StampFactory.class, Stamp.class);
     }
 
     /**
@@ -231,7 +299,7 @@
     private Object copyFieldOrElement(Deque<Object> worklist, Map<Object, Object> copies, Object srcValue) {
         Object dstValue = srcValue;
         if (srcValue != null && !Proxy.isProxyClass(srcValue.getClass())) {
-            if (isAssignableTo(srcValue.getClass(), DontCopyClasses) || SpecialStaticFields.containsKey(srcValue)) {
+            if (isAssignableTo(srcValue.getClass(), DontCopyClasses) || SharedGlobals.containsKey(srcValue)) {
                 pool.put(srcValue, srcValue);
                 return srcValue;
             }
@@ -264,7 +332,7 @@
      * In addition, copies in {@link #pool} are re-used.
      */
     private Object copy(Object root) {
-        assert !(isAssignableTo(root.getClass(), DontCopyClasses) || SpecialStaticFields.containsKey(root));
+        assert !(isAssignableTo(root.getClass(), DontCopyClasses) || SharedGlobals.containsKey(root));
         // System.out.printf("----- %s ------%n", s(obj));
         assert pool.get(root) == null;
         Deque<Object> worklist = new IdentityLinkedList<>();
@@ -313,7 +381,7 @@
             return (T) proxy;
         } else {
             Object value;
-            if (isAssignableTo(obj.getClass(), DontCopyClasses) || SpecialStaticFields.containsKey(obj)) {
+            if (isAssignableTo(obj.getClass(), DontCopyClasses) || SharedGlobals.containsKey(obj)) {
                 value = obj;
             } else {
                 value = pool.get(obj);