changeset 18381:53bd20792127

Merge.
author Doug Simon <doug.simon@oracle.com>
date Sat, 15 Nov 2014 16:39:23 +0100
parents 601dfbdcc5bf (diff) ed0fce2e999a (current diff)
children 322d928a373e
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/ObjectGetClassNode.java
diffstat 8 files changed, 320 insertions(+), 71 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.compiler.common/src/com/oracle/graal/compiler/common/remote/LinkedIdentityHashMap.java	Sat Nov 15 16:39:23 2014 +0100
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package com.oracle.graal.compiler.common.remote;
+
+import java.util.*;
+import java.util.function.*;
+
+import com.oracle.graal.compiler.common.remote.Context.Mode;
+
+/**
+ * A map that combines {@link IdentityHashMap} with {@link LinkedHashMap} for the purpose of
+ * ensuring a deterministic execution order during {@link Mode#Capturing}.
+ */
+final class LinkedIdentityHashMap<K, V> implements Map<K, V> {
+
+    private final LinkedHashMap<Id<K>, V> map;
+
+    public LinkedIdentityHashMap() {
+        map = new LinkedHashMap<>();
+    }
+
+    public LinkedIdentityHashMap(Map<K, V> m) {
+        map = new LinkedHashMap<>(m.size());
+        putAll(m);
+    }
+
+    public LinkedIdentityHashMap(int expectedMaxSize) {
+        map = new LinkedHashMap<>(expectedMaxSize);
+    }
+
+    /**
+     * Wrapper for an object that gives uses the object's identity for the purpose of equality
+     * comparisons and computing a hash code.
+     */
+    public static class Id<T> {
+        final T object;
+
+        public Id(T object) {
+            assert object != null;
+            this.object = object;
+        }
+
+        @SuppressWarnings("unchecked")
+        @Override
+        public boolean equals(Object obj) {
+            return ((Id<T>) obj).object == object;
+        }
+
+        @Override
+        public int hashCode() {
+            return System.identityHashCode(object);
+        }
+    }
+
+    public int size() {
+        return map.size();
+    }
+
+    public boolean isEmpty() {
+        return map.isEmpty();
+    }
+
+    public boolean containsKey(Object key) {
+        return map.containsKey(id(key));
+    }
+
+    @SuppressWarnings("unchecked")
+    private Id<K> id(Object key) {
+        if (key == null) {
+            return null;
+        }
+        return new Id<>((K) key);
+    }
+
+    public boolean containsValue(Object value) {
+        return map.containsValue(value);
+    }
+
+    public V get(Object key) {
+        return map.get(id(key));
+    }
+
+    public V put(K key, V value) {
+        return map.put(id(key), value);
+    }
+
+    public V remove(Object key) {
+        return map.remove(id(key));
+    }
+
+    @SuppressWarnings("unchecked")
+    public void putAll(Map<? extends K, ? extends V> m) {
+        if (m != null && m.getClass() == getClass()) {
+            LinkedIdentityHashMap<K, V> that = (LinkedIdentityHashMap<K, V>) m;
+            map.putAll(that.map);
+
+        } else {
+            for (K key : m.keySet()) {
+                map.put(id(key), m.get(key));
+            }
+        }
+    }
+
+    public void clear() {
+        map.clear();
+    }
+
+    final class KeySet extends AbstractSet<K> {
+        @Override
+        public int size() {
+            return map.size();
+        }
+
+        @Override
+        public void clear() {
+            map.clear();
+        }
+
+        @Override
+        public Iterator<K> iterator() {
+            return new Iterator<K>() {
+                final Iterator<Id<K>> i = map.keySet().iterator();
+
+                public boolean hasNext() {
+                    return i.hasNext();
+                }
+
+                public K next() {
+                    return i.next().object;
+                }
+
+                public void remove() {
+                    i.remove();
+                }
+            };
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            return containsKey(o);
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            return LinkedIdentityHashMap.this.remove(o) != null;
+        }
+
+        public Spliterator<K> spliterator() {
+            return Spliterators.spliterator(this, Spliterator.SIZED | Spliterator.ORDERED | Spliterator.DISTINCT);
+        }
+
+        public void forEach(Consumer<? super K> action) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    public Set<K> keySet() {
+        return new KeySet();
+    }
+
+    public Collection<V> values() {
+        return map.values();
+    }
+
+    final class EntrySet extends AbstractSet<Map.Entry<K, V>> {
+        @Override
+        public int size() {
+            return map.size();
+        }
+
+        @Override
+        public void clear() {
+            map.clear();
+        }
+
+        @Override
+        public Iterator<Map.Entry<K, V>> iterator() {
+            return new Iterator<Map.Entry<K, V>>() {
+                final Iterator<Map.Entry<Id<K>, V>> i = map.entrySet().iterator();
+
+                public boolean hasNext() {
+                    return i.hasNext();
+                }
+
+                public Map.Entry<K, V> next() {
+                    Map.Entry<Id<K>, V> e = i.next();
+                    return new Map.Entry<K, V>() {
+
+                        public K getKey() {
+                            return e.getKey().object;
+                        }
+
+                        public V getValue() {
+                            return e.getValue();
+                        }
+
+                        public V setValue(V value) {
+                            return e.setValue(value);
+                        }
+                    };
+                }
+
+                public void remove() {
+                    i.remove();
+                }
+            };
+        }
+
+        @Override
+        public boolean contains(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        @Override
+        public boolean remove(Object o) {
+            throw new UnsupportedOperationException();
+        }
+
+        public Spliterator<Map.Entry<K, V>> spliterator() {
+            throw new UnsupportedOperationException();
+        }
+
+        public void forEach(Consumer<? super Map.Entry<K, V>> action) {
+            throw new UnsupportedOperationException();
+        }
+    }
+
+    public Set<Map.Entry<K, V>> entrySet() {
+        return new EntrySet();
+    }
+}
--- a/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.compiler.test/src/com/oracle/graal/compiler/test/GraalCompilerTest.java	Sat Nov 15 16:39:23 2014 +0100
@@ -702,8 +702,8 @@
         return OUTPUT_DIR;
     }
 
-    protected String dissasembleToFile(CompilationResult original, ResolvedJavaMethod installedCodeOwner, String fileSuffix) {
-        String dis = getCodeCache().disassemble(original, null);
+    protected String dissasembleToFile(CompilationResult result, ResolvedJavaMethod installedCodeOwner, String fileSuffix) {
+        String dis = getCodeCache().disassemble(result, null);
         File disFile = new File(getOutputDir(), installedCodeOwner.format("%H.%n_%p").replace(", ", "__") + "." + fileSuffix);
         try (PrintStream ps = new PrintStream(new FileOutputStream(disFile))) {
             ps.println(dis);
@@ -713,18 +713,18 @@
         }
     }
 
-    protected void checkCompilationResultsEqual(Context c, String prefix, CompilationResult original, CompilationResult derived, ResolvedJavaMethod installedCodeOwner) {
-        if (!derived.equals(original)) {
+    protected void checkCompilationResultsEqual(Context c, String prefix, CompilationResult expected, CompilationResult actual, ResolvedJavaMethod installedCodeOwner) {
+        if (!actual.equals(expected)) {
             Mode mode = c.getMode();
             // Temporarily force capturing mode as dumping/printing/disassembling
             // may need to execute proxy methods that have not yet been executed
             c.setMode(Mode.Capturing);
             try {
-                String originalDisFile = dissasembleToFile(original, installedCodeOwner, "original");
-                String derivedDisFile = dissasembleToFile(derived, installedCodeOwner, "derived");
-                String message = String.format("%s compilation result differs from original compilation result", prefix);
-                if (originalDisFile != null && derivedDisFile != null) {
-                    message += String.format(" [diff %s %s]", originalDisFile, derivedDisFile);
+                String expectedDisFile = dissasembleToFile(expected, installedCodeOwner, "expected");
+                String actualDisFile = dissasembleToFile(actual, installedCodeOwner, "actual");
+                String message = String.format("%s compilation result differs from expected compilation result", prefix);
+                if (expectedDisFile != null && actualDisFile != null) {
+                    message += String.format(" [diff %s %s]", expectedDisFile, actualDisFile);
                 }
                 if (TEST_REPLAY_MISMATCH_IS_FAILURE) {
                     Assert.fail(message);
@@ -737,50 +737,35 @@
         }
     }
 
-    protected void testRecompile(Context c, Mode mode, CompilationResult originalResultInContext, ResolvedJavaMethod installedCodeOwner) {
+    protected CompilationResult testRecompile(Context c, Mode mode, CompilationResult expectedResult, ResolvedJavaMethod installedCodeOwner) {
         try (Debug.Scope s = Debug.scope(mode.name(), new DebugDumpScope(mode.name(), true))) {
 
             StructuredGraph graphToCompile = parseForCompile(installedCodeOwner);
+
             lastCompiledGraph = graphToCompile;
 
             CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graphToCompile.method(), false);
             Request<CompilationResult> request = c.get(new GraalCompiler.Request<>(graphToCompile, null, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null,
                             getDefaultGraphBuilderSuite(), OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), new CompilationResult(),
                             CompilationResultBuilderFactory.Default));
-            checkCompilationResultsEqual(c, mode.name(), originalResultInContext, GraalCompiler.compile(request), installedCodeOwner);
+            CompilationResult result = GraalCompiler.compile(request);
+            if (expectedResult != null) {
+                checkCompilationResultsEqual(c, mode.name(), expectedResult, result, installedCodeOwner);
+            }
+            return result;
         } catch (Throwable e) {
             throw Debug.handle(e);
         }
     }
 
     protected void testReplayCompile(ResolvedJavaMethod installedCodeOwner) {
-        CompilationResult originalResult;
-
-        // Repeat the compilation without a context to account for any side-effects the
-        // initial compilation may have had. For example, if dumping was enabled then
-        // the dumping code may have changed profiles in methods that are inlined
-        // by the test method being compiled.
-        try (Debug.Scope s = Debug.scope("Repeating", new DebugDumpScope("Repeating", true))) {
-            StructuredGraph graphToCompile = parseForCompile(installedCodeOwner);
-            lastCompiledGraph = graphToCompile;
-            CallingConvention cc = getCallingConvention(getCodeCache(), Type.JavaCallee, graphToCompile.method(), false);
-            originalResult = GraalCompiler.compileGraph(graphToCompile, null, cc, installedCodeOwner, getProviders(), getBackend(), getCodeCache().getTarget(), null, getDefaultGraphBuilderSuite(),
-                            OptimisticOptimizations.ALL, getProfilingInfo(graphToCompile), getSpeculationLog(), getSuites(), new CompilationResult(), CompilationResultBuilderFactory.Default);
-        } catch (Throwable e) {
-            throw Debug.handle(e);
-        }
-
         try (Context c = new Context()) {
-            // Need to use an 'in context' copy of the original result when comparing for
-            // equality against other 'in context' results so that proxies are compared
-            // against proxies
-            CompilationResult originalResultInContext = c.get(originalResult);
 
             // Capturing compilation
-            testRecompile(c, Mode.Capturing, originalResultInContext, installedCodeOwner);
+            CompilationResult expected = testRecompile(c, Mode.Capturing, null, installedCodeOwner);
 
             // Replay compilation
-            testRecompile(c, Mode.Replaying, originalResultInContext, installedCodeOwner);
+            testRecompile(c, Mode.Replaying, expected, installedCodeOwner);
         }
     }
 
--- a/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.graph/src/com/oracle/graal/graph/Node.java	Sat Nov 15 16:39:23 2014 +0100
@@ -31,13 +31,14 @@
 import sun.misc.*;
 
 import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.remote.*;
 import com.oracle.graal.graph.Graph.NodeEventListener;
 import com.oracle.graal.graph.iterators.*;
 import com.oracle.graal.graph.spi.*;
 import com.oracle.graal.nodeinfo.*;
 
 /**
- * This class is the base class for all nodes, it represent a node which can be inserted in a
+ * This class is the base class for all nodes. It represents a node that can be inserted in a
  * {@link Graph}.
  * <p>
  * Once a node has been added to a graph, it has a graph-unique {@link #id()}. Edges in the
@@ -48,6 +49,11 @@
  * <p>
  * Nodes which are be value numberable should implement the {@link ValueNumberable} interface.
  *
+ * <h1>Replay Compilation</h1>
+ *
+ * To enable deterministic replay compilation, node hash set creation within a compilation scope
+ * must {@link #newNodeHashSet()} or {@link #newNodeHashSet(Collection)}.
+ *
  * <h1>Assertions and Verification</h1>
  *
  * The Node class supplies the {@link #assertTrue(boolean, String, Object...)} and
@@ -193,6 +199,22 @@
     }
 
     /**
+     * Creates a {@link Node} hash set. The return set will be a {@link LinkedHashSet} if the
+     * current thread has an active compilation replay scope. This is requires to make replay
+     * compilations deterministic.
+     */
+    public static <E extends Node> HashSet<E> newNodeHashSet() {
+        return Context.getCurrent() == null ? new HashSet<>() : new LinkedHashSet<>();
+    }
+
+    /**
+     * @see #newNodeHashSet()
+     */
+    public static <E extends Node> HashSet<E> newNodeHashSet(Collection<? extends E> c) {
+        return Context.getCurrent() == null ? new HashSet<>(c) : new LinkedHashSet<>(c);
+    }
+
+    /**
      * Gets the graph context of this node.
      */
     public Graph graph() {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/TailDuplicationPhase.java	Sat Nov 15 16:39:23 2014 +0100
@@ -434,7 +434,7 @@
 
             // build the intersection
             belowBound.intersect(aboveBound);
-            HashSet<Node> result = new HashSet<>();
+            HashSet<Node> result = Node.newNodeHashSet();
             for (Node node : belowBound) {
                 result.add(node);
             }
@@ -491,7 +491,7 @@
         }
 
         private void processUsages(Node duplicated, HashSet<Node> duplicatedNodes, MergeNode newBottomMerge, Deque<Node> worklist) {
-            HashSet<Node> unique = new HashSet<>();
+            HashSet<Node> unique = Node.newNodeHashSet();
             duplicated.usages().snapshotTo(unique);
             Node newOutsideClone = null;
             for (Node usage : unique) {
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/ValueAnchorCleanupPhase.java	Sat Nov 15 16:39:23 2014 +0100
@@ -42,11 +42,11 @@
         private final HashSet<Node> anchoredValues;
 
         public State() {
-            anchoredValues = new HashSet<>();
+            anchoredValues = Node.newNodeHashSet();
         }
 
         public State(State other) {
-            anchoredValues = new HashSet<>(other.anchoredValues);
+            anchoredValues = Node.newNodeHashSet(other.anchoredValues);
         }
 
         @Override
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/inlining/walker/InliningData.java	Sat Nov 15 16:39:23 2014 +0100
@@ -22,37 +22,28 @@
  */
 package com.oracle.graal.phases.common.inlining.walker;
 
-import com.oracle.graal.api.code.Assumptions;
-import com.oracle.graal.api.code.BailoutException;
-import com.oracle.graal.api.meta.JavaTypeProfile;
-import com.oracle.graal.api.meta.ResolvedJavaMethod;
-import com.oracle.graal.api.meta.ResolvedJavaType;
-import com.oracle.graal.compiler.common.GraalInternalError;
-import com.oracle.graal.compiler.common.type.ObjectStamp;
-import com.oracle.graal.debug.Debug;
-import com.oracle.graal.debug.DebugMetric;
-import com.oracle.graal.graph.Graph;
-import com.oracle.graal.graph.Node;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.AbstractNewObjectNode;
-import com.oracle.graal.nodes.java.MethodCallTargetNode;
-import com.oracle.graal.nodes.virtual.AllocatedObjectNode;
-import com.oracle.graal.nodes.virtual.VirtualObjectNode;
-import com.oracle.graal.phases.OptimisticOptimizations;
-import com.oracle.graal.phases.common.CanonicalizerPhase;
-import com.oracle.graal.phases.common.inlining.InliningUtil;
-import com.oracle.graal.phases.common.inlining.info.*;
-import com.oracle.graal.phases.common.inlining.info.elem.Inlineable;
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableGraph;
-import com.oracle.graal.phases.common.inlining.info.elem.InlineableMacroNode;
-import com.oracle.graal.phases.common.inlining.policy.InliningPolicy;
-import com.oracle.graal.phases.tiers.HighTierContext;
-import com.oracle.graal.phases.util.Providers;
+import static com.oracle.graal.compiler.common.GraalOptions.*;
+import static com.oracle.graal.phases.common.inlining.walker.CallsiteHolderDummy.*;
 
 import java.util.*;
 
-import static com.oracle.graal.compiler.common.GraalOptions.*;
-import static com.oracle.graal.phases.common.inlining.walker.CallsiteHolderDummy.DUMMY_CALLSITE_HOLDER;
+import com.oracle.graal.api.code.*;
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.compiler.common.*;
+import com.oracle.graal.compiler.common.type.*;
+import com.oracle.graal.debug.*;
+import com.oracle.graal.graph.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.virtual.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.phases.common.*;
+import com.oracle.graal.phases.common.inlining.*;
+import com.oracle.graal.phases.common.inlining.info.*;
+import com.oracle.graal.phases.common.inlining.info.elem.*;
+import com.oracle.graal.phases.common.inlining.policy.*;
+import com.oracle.graal.phases.tiers.*;
+import com.oracle.graal.phases.util.*;
 
 /**
  * <p>
@@ -368,7 +359,7 @@
         InlineInfo calleeInfo = calleeInvocation.callee();
         try {
             try (Debug.Scope scope = Debug.scope("doInline", callerGraph)) {
-                Set<Node> canonicalizedNodes = new HashSet<>();
+                Set<Node> canonicalizedNodes = Node.newNodeHashSet();
                 calleeInfo.invoke().asNode().usages().snapshotTo(canonicalizedNodes);
                 Collection<Node> parameterUsages = calleeInfo.inline(new Providers(context), callerAssumptions);
                 canonicalizedNodes.addAll(parameterUsages);
--- a/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeEventListener.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.phases.common/src/com/oracle/graal/phases/common/util/HashSetNodeEventListener.java	Sat Nov 15 16:39:23 2014 +0100
@@ -40,7 +40,7 @@
      * Creates a {@link NodeEventListener} that collects nodes from all events.
      */
     public HashSetNodeEventListener() {
-        this.nodes = new HashSet<>();
+        this.nodes = Node.newNodeHashSet();
         this.filter = EnumSet.allOf(NodeEvent.class);
     }
 
--- a/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Fri Nov 14 09:32:59 2014 -0800
+++ b/graal/com.oracle.graal.printer/src/com/oracle/graal/printer/IdealGraphPrinter.java	Sat Nov 15 16:39:23 2014 +0100
@@ -84,7 +84,7 @@
     @Override
     public void print(Graph graph, String title, SchedulePhase predefinedSchedule) {
         beginGraph(title);
-        Set<Node> noBlockNodes = new HashSet<>();
+        Set<Node> noBlockNodes = Node.newNodeHashSet();
         SchedulePhase schedule = predefinedSchedule;
         if (schedule == null && tryToSchedule) {
             if (PrintIdealGraphSchedule.getValue()) {
@@ -249,7 +249,7 @@
         endSuccessors();
         beginBlockNodes();
 
-        Set<Node> nodes = new HashSet<>();
+        Set<Node> nodes = Node.newNodeHashSet();
 
         if (nodeToBlock != null) {
             for (Node n : graph.getNodes()) {
@@ -270,7 +270,7 @@
                 }
             }
 
-            Set<Node> snapshot = new HashSet<>(nodes);
+            Set<Node> snapshot = Node.newNodeHashSet(nodes);
             // add all framestates and phis to their blocks
             for (Node node : snapshot) {
                 if (node instanceof StateSplit && ((StateSplit) node).stateAfter() != null) {