# HG changeset patch # User Doug Simon # Date 1415893697 -3600 # Node ID a8bc8724657efb00e71cbbbe2b6510d1bfabb7ae # Parent ad3c2cacdd1aac6b1acd60778751c3836749fbac expanded support for shared globals (i.e., values that must be retrieved from static fields instead of being copied in replay/remote compilation) diff -r ad3c2cacdd1a -r a8bc8724657e graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/remote/Context.java --- 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 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 SpecialStaticFields = new IdentityHashMap<>(); + private static final Map 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 worklist, Map 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 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);