changeset 11615:3f706be38bf9

Truffle: compilation final array support.
author Andreas Woess <andreas.woess@jku.at>
date Thu, 12 Sep 2013 19:22:28 +0200
parents 57674ff0f7e2
children dc35a8134f4a
files graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java
diffstat 5 files changed, 154 insertions(+), 26 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Sep 12 19:01:40 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluator.java	Thu Sep 12 19:22:28 2013 +0200
@@ -66,7 +66,6 @@
 public class PartialEvaluator {
 
     private final MetaAccessProvider metaAccessProvider;
-    private final ResolvedJavaType nodeClass;
     private final ResolvedJavaMethod executeHelperMethod;
     private final CanonicalizerPhase canonicalizer;
     private final ResolvedJavaType[] skippedExceptionTypes;
@@ -77,8 +76,7 @@
 
     public PartialEvaluator(MetaAccessProvider metaAccessProvider, Replacements replacements, TruffleCache truffleCache) {
         this.metaAccessProvider = metaAccessProvider;
-        this.nodeClass = metaAccessProvider.lookupJavaType(com.oracle.truffle.api.nodes.Node.class);
-        CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(metaAccessProvider, nodeClass);
+        CustomCanonicalizer customCanonicalizer = new PartialEvaluatorCanonicalizer(metaAccessProvider);
         this.canonicalizer = new CanonicalizerPhase(!AOTCompilation.getValue(), customCanonicalizer);
         this.skippedExceptionTypes = TruffleCompilerImpl.getSkippedExceptionTypes(metaAccessProvider);
         this.replacements = replacements;
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Thu Sep 12 19:01:40 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/PartialEvaluatorCanonicalizer.java	Thu Sep 12 19:22:28 2013 +0200
@@ -27,7 +27,6 @@
 import com.oracle.graal.api.meta.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
-import com.oracle.graal.nodes.type.*;
 import com.oracle.graal.phases.common.*;
 import com.oracle.truffle.api.*;
 import com.oracle.truffle.api.nodes.Node.Child;
@@ -35,40 +34,30 @@
 final class PartialEvaluatorCanonicalizer implements CanonicalizerPhase.CustomCanonicalizer {
 
     private final MetaAccessProvider metaAccessProvider;
-    private final ResolvedJavaType nodeClass;
 
-    PartialEvaluatorCanonicalizer(MetaAccessProvider metaAccessProvider, ResolvedJavaType nodeClass) {
+    PartialEvaluatorCanonicalizer(MetaAccessProvider metaAccessProvider) {
         this.metaAccessProvider = metaAccessProvider;
-        this.nodeClass = nodeClass;
     }
 
     @Override
     public ValueNode canonicalize(ValueNode node) {
         if (node instanceof LoadFieldNode) {
             LoadFieldNode loadFieldNode = (LoadFieldNode) node;
-            if (!loadFieldNode.isStatic() &&
-                            loadFieldNode.object().isConstant() &&
-                            !loadFieldNode.object().isNullConstant() &&
-                            ((loadFieldNode.kind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) || Modifier.isFinal(loadFieldNode.field().getModifiers()) || loadFieldNode.field().getAnnotation(
-                                            CompilerDirectives.CompilationFinal.class) != null)) {
-                Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
-                return ConstantNode.forConstant(constant, metaAccessProvider, node.graph());
-            }
-        } else if (node instanceof LoadIndexedNode) {
-            LoadIndexedNode loadIndexedNode = (LoadIndexedNode) node;
-            Stamp stamp = loadIndexedNode.array().stamp();
-            if (stamp.kind() == Kind.Object && loadIndexedNode.array().isConstant() && !loadIndexedNode.array().isNullConstant() && loadIndexedNode.index().isConstant()) {
-                ObjectStamp objectStamp = (ObjectStamp) stamp;
-                ResolvedJavaType type = objectStamp.type();
-                if (type != null && type.isArray() && this.nodeClass.isAssignableFrom(type.getComponentType())) {
-                    Object array = loadIndexedNode.array().asConstant().asObject();
-                    int index = loadIndexedNode.index().asConstant().asInt();
-                    Object value = Array.get(array, index);
-                    return ConstantNode.forObject(value, metaAccessProvider, node.graph());
+            if (!loadFieldNode.isStatic() && loadFieldNode.object().isConstant() && !loadFieldNode.object().isNullConstant()) {
+                if (Modifier.isFinal(loadFieldNode.field().getModifiers()) || (loadFieldNode.kind() == Kind.Object && loadFieldNode.field().getAnnotation(Child.class) != null) ||
+                                loadFieldNode.field().getAnnotation(CompilerDirectives.CompilationFinal.class) != null) {
+                    Constant constant = loadFieldNode.field().readValue(loadFieldNode.object().asConstant());
+                    assert verifyFieldValue(loadFieldNode.field(), constant);
+                    return ConstantNode.forConstant(constant, metaAccessProvider, node.graph());
                 }
             }
         }
 
         return node;
     }
+
+    private static boolean verifyFieldValue(ResolvedJavaField field, Constant constant) {
+        assert field.getAnnotation(Child.class) == null || constant.isNull() || constant.asObject() instanceof com.oracle.truffle.api.nodes.Node : "@Child field value must be a Node: " + field;
+        return true;
+    }
 }
--- a/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Thu Sep 12 19:01:40 2013 +0200
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/TruffleCache.java	Thu Sep 12 19:22:28 2013 +0200
@@ -180,6 +180,8 @@
 
     private static void contractGraph(StructuredGraph newGraph, ConditionalEliminationPhase conditionalEliminationPhase, ConvertDeoptimizeToGuardPhase convertDeoptimizeToGuardPhase,
                     CanonicalizerPhase canonicalizerPhase, EarlyReadEliminationPhase readEliminationPhase, PhaseContext context) {
+        new ReplaceLoadFinalPhase().apply(newGraph);
+
         // Canonicalize / constant propagate.
         canonicalizerPhase.apply(newGraph, context);
 
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/nodes/LoadIndexedFinalNode.java	Thu Sep 12 19:22:28 2013 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2013, 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.truffle.nodes;
+
+import java.lang.reflect.*;
+
+import sun.misc.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.nodes.spi.*;
+import com.oracle.graal.nodes.type.*;
+
+/**
+ * @see LoadIndexedNode
+ */
+public final class LoadIndexedFinalNode extends AccessIndexedNode implements Canonicalizable {
+
+    /**
+     * Creates a new {@link LoadIndexedFinalNode}.
+     * 
+     * @param array the instruction producing the array
+     * @param index the instruction producing the index
+     * @param elementKind the element type
+     */
+    public LoadIndexedFinalNode(ValueNode array, ValueNode index, Kind elementKind) {
+        super(createStamp(array, elementKind), array, index, elementKind);
+    }
+
+    @Override
+    public ValueNode canonical(CanonicalizerTool tool) {
+        if (array().isConstant() && !array().isNullConstant() && index().isConstant()) {
+            Object array = array().asConstant().asObject();
+            long index = index().asConstant().asLong();
+            if (index >= 0 && index < Array.getLength(array)) {
+                int arrayBaseOffset = Unsafe.getUnsafe().arrayBaseOffset(array.getClass());
+                int arrayIndexScale = Unsafe.getUnsafe().arrayIndexScale(array.getClass());
+                Constant constant = tool.runtime().readUnsafeConstant(elementKind(), array, arrayBaseOffset + index * arrayIndexScale, elementKind() == Kind.Object);
+                return ConstantNode.forConstant(constant, tool.runtime(), graph());
+            }
+        }
+        return this;
+    }
+
+    private static Stamp createStamp(ValueNode array, Kind kind) {
+        ResolvedJavaType type = ObjectStamp.typeOrNull(array);
+        if (kind == Kind.Object && type != null) {
+            return StampFactory.declared(type.getComponentType());
+        } else {
+            return StampFactory.forKind(kind);
+        }
+    }
+
+    @Override
+    public boolean inferStamp() {
+        return updateStamp(createStamp(array(), elementKind()));
+    }
+
+    @Override
+    public void lower(LoweringTool tool) {
+        LoadIndexedNode loadIndexedNode = graph().add(new LoadIndexedNode(array(), index(), elementKind()));
+        graph().replaceFixedWithFixed(this, loadIndexedNode);
+        loadIndexedNode.lower(tool);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.graal.truffle/src/com/oracle/graal/truffle/phases/ReplaceLoadFinalPhase.java	Thu Sep 12 19:22:28 2013 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2013, 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.truffle.phases;
+
+import java.lang.reflect.*;
+
+import com.oracle.graal.api.meta.*;
+import com.oracle.graal.nodes.*;
+import com.oracle.graal.nodes.java.*;
+import com.oracle.graal.phases.*;
+import com.oracle.graal.truffle.nodes.*;
+import com.oracle.truffle.api.*;
+import com.oracle.truffle.api.nodes.Node.Children;
+
+public class ReplaceLoadFinalPhase extends Phase {
+
+    @Override
+    protected void run(StructuredGraph graph) {
+        for (LoadIndexedNode loadIndexedNode : graph.getNodes(LoadIndexedNode.class)) {
+            if (loadIndexedNode.array() instanceof LoadFieldNode) {
+                LoadFieldNode loadFieldNode = (LoadFieldNode) loadIndexedNode.array();
+                if (!loadFieldNode.isStatic() && isCompilationFinal(loadFieldNode.field())) {
+                    graph.replaceFixedWithFixed(loadIndexedNode, graph.add(new LoadIndexedFinalNode(loadIndexedNode.array(), loadIndexedNode.index(), loadIndexedNode.elementKind())));
+                }
+            }
+        }
+    }
+
+    private static boolean isCompilationFinal(ResolvedJavaField field) {
+        assert (field.getAnnotation(Children.class) == null && field.getAnnotation(CompilerDirectives.CompilationFinal.class) == null) || Modifier.isFinal(field.getModifiers()) : "field needs to be declared as final";
+        return Modifier.isFinal(field.getModifiers()) && (field.getAnnotation(Children.class) != null || field.getAnnotation(CompilerDirectives.CompilationFinal.class) != null);
+    }
+}