changeset 21925:64475dbf6aec

Move instantiation checks from methods substitutions to the lowering of DynamicNewInstanceNode and DynamicNewArrayNode, so that Unsafe.allocateInstance and Array.newInstance can be intrinsified to a single node.
author Christian Wimmer <christian.wimmer@oracle.com>
date Wed, 10 Jun 2015 17:23:19 -0700
parents f6fd9fb11816
children 607a5d806916
files graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java
diffstat 8 files changed, 82 insertions(+), 118 deletions(-) [+]
line wrap: on
line diff
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java	Wed Jun 10 17:23:19 2015 -0700
@@ -22,12 +22,10 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import sun.misc.*;
 import sun.reflect.*;
 
 import com.oracle.graal.api.replacements.*;
 import com.oracle.graal.nodes.spi.*;
-import com.oracle.graal.replacements.*;
 import com.oracle.jvmci.code.*;
 import com.oracle.jvmci.hotspot.*;
 import com.oracle.jvmci.meta.*;
@@ -40,7 +38,6 @@
     public void registerReplacements(MetaAccessProvider metaAccess, LoweringProvider loweringProvider, SnippetReflectionProvider snippetReflection, Replacements replacements, TargetDescription target) {
         replacements.registerSubstitutions(System.class, SystemSubstitutions.class);
         replacements.registerSubstitutions(Thread.class, ThreadSubstitutions.class);
-        replacements.registerSubstitutions(Unsafe.class, UnsafeSubstitutions.class);
         replacements.registerSubstitutions(Reflection.class, ReflectionSubstitutions.class);
         replacements.registerSubstitutions(CompilerToVMImpl.class, CompilerToVMImplSubstitutions.class);
     }
--- a/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java	Wed Jun 10 17:23:19 2015 -0700
@@ -22,15 +22,7 @@
  */
 package com.oracle.graal.hotspot.replacements;
 
-import com.oracle.jvmci.code.Register;
-import com.oracle.jvmci.code.CodeUtil;
-import com.oracle.jvmci.code.TargetDescription;
-import com.oracle.jvmci.meta.NamedLocationIdentity;
-import com.oracle.jvmci.meta.ResolvedJavaType;
-import com.oracle.jvmci.meta.LocationIdentity;
-import com.oracle.jvmci.meta.ForeignCallDescriptor;
-import com.oracle.jvmci.meta.Kind;
-import static com.oracle.jvmci.code.UnsignedMath.*;
+import static com.oracle.graal.replacements.ReplacementsUtil.*;
 import static com.oracle.graal.compiler.common.GraalOptions.*;
 import static com.oracle.graal.hotspot.nodes.CStringNode.*;
 import static com.oracle.graal.hotspot.replacements.HotSpotReplacementsUtil.*;
@@ -39,6 +31,7 @@
 import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
 import static com.oracle.graal.replacements.SnippetTemplate.*;
 import static com.oracle.graal.replacements.nodes.ExplodeLoopNode.*;
+import static com.oracle.jvmci.code.UnsignedMath.*;
 import static com.oracle.jvmci.hotspot.HotSpotMetaAccessProvider.*;
 
 import com.oracle.graal.api.replacements.*;
@@ -65,9 +58,11 @@
 import com.oracle.graal.replacements.SnippetTemplate.SnippetInfo;
 import com.oracle.graal.replacements.nodes.*;
 import com.oracle.graal.word.*;
+import com.oracle.jvmci.code.*;
 import com.oracle.jvmci.common.*;
 import com.oracle.jvmci.debug.*;
 import com.oracle.jvmci.hotspot.*;
+import com.oracle.jvmci.meta.*;
 import com.oracle.jvmci.options.*;
 
 /**
@@ -167,6 +162,10 @@
 
     @Snippet
     public static Object allocateInstanceDynamic(Class<?> type, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
+        if (probability(SLOW_PATH_PROBABILITY, type == null || DynamicNewInstanceNode.throwsInstantiationException(type))) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+
         KlassPointer hub = ClassGetHubNode.readClass(type);
         if (probability(FAST_PATH_PROBABILITY, !hub.isNull())) {
             if (probability(FAST_PATH_PROBABILITY, isInstanceKlassFullyInitialized(hub))) {
@@ -240,7 +239,17 @@
     public static native Object dynamicNewInstanceStubCall(@ConstantNodeParameter ForeignCallDescriptor descriptor, Class<?> elementType);
 
     @Snippet
-    public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister) {
+    public static Object allocateArrayDynamic(Class<?> elementType, int length, @ConstantParameter boolean fillContents, @ConstantParameter Register threadRegister,
+                    @ConstantParameter Kind knownElementKind) {
+        /*
+         * We only need the dynamic check for void when we have no static information from
+         * knownElementKind.
+         */
+        staticAssert(knownElementKind != Kind.Void, "unsupported knownElementKind");
+        if (knownElementKind == Kind.Illegal && probability(SLOW_PATH_PROBABILITY, elementType == null || DynamicNewArrayNode.throwsIllegalArgumentException(elementType))) {
+            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
+        }
+
         Word hub = loadWordFromObject(elementType, arrayKlassOffset(), CLASS_ARRAY_KLASS_LOCATION);
         if (probability(BranchProbabilityNode.NOT_FREQUENT_PROBABILITY, hub.equal(Word.zero()) || !belowThan(length, MAX_ARRAY_FAST_PATH_ALLOCATION_LENGTH))) {
             return dynamicNewArrayStub(DYNAMIC_NEW_ARRAY, elementType, length);
@@ -478,6 +487,11 @@
             args.add("length", length.isAlive() ? length : graph.addOrUniqueWithInputs(length));
             args.addConst("fillContents", newArrayNode.fillContents());
             args.addConst("threadRegister", registers.getThreadRegister());
+            /*
+             * We use Kind.Illegal as a marker value instead of null because constant snippet
+             * parameters cannot be null.
+             */
+            args.addConst("knownElementKind", newArrayNode.getKnownElementKind() == null ? Kind.Illegal : newArrayNode.getKnownElementKind());
 
             SnippetTemplate template = template(args);
             template.instantiate(providers.getMetaAccess(), newArrayNode, DEFAULT_REPLACER, args);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java	Wed Jun 10 17:23:19 2015 -0700
@@ -23,8 +23,6 @@
 //JaCoCo Exclude
 package com.oracle.graal.nodes.java;
 
-import java.util.*;
-
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -37,7 +35,7 @@
  * compile-time constant.
  */
 @NodeInfo
-public class DynamicNewArrayNode extends AbstractNewArrayNode {
+public class DynamicNewArrayNode extends AbstractNewArrayNode implements Canonicalizable {
     public static final NodeClass<DynamicNewArrayNode> TYPE = NodeClass.create(DynamicNewArrayNode.class);
 
     @Input ValueNode elementType;
@@ -48,10 +46,6 @@
      */
     protected final Kind knownElementKind;
 
-    public DynamicNewArrayNode(ValueNode elementType, ValueNode length) {
-        this(TYPE, elementType, length, true, null);
-    }
-
     public DynamicNewArrayNode(ValueNode elementType, ValueNode length, boolean fillContents, Kind knownElementKind) {
         this(TYPE, elementType, length, fillContents, knownElementKind);
     }
@@ -60,6 +54,7 @@
         super(c, StampFactory.objectNonNull(), length, fillContents);
         this.elementType = elementType;
         this.knownElementKind = knownElementKind;
+        assert knownElementKind != Kind.Void && knownElementKind != Kind.Illegal;
     }
 
     public ValueNode getElementType() {
@@ -70,33 +65,33 @@
         return knownElementKind;
     }
 
-    protected NewArrayNode forConstantType(ResolvedJavaType type) {
-        ValueNode len = length();
-        NewArrayNode ret = graph().add(new NewArrayNode(type, len.isAlive() ? len : graph().addOrUniqueWithInputs(len), fillContents()));
-        if (stateBefore() != null) {
-            ret.setStateBefore(stateBefore());
-        }
-        return ret;
+    @Override
+    public void simplify(SimplifierTool tool) {
+        /*
+         * Do not call the super implementation: we must not eliminate unused allocations because
+         * throwing a NullPointerException or IllegalArgumentException is a possible side effect of
+         * an unused allocation.
+         */
     }
 
     @Override
-    public void simplify(SimplifierTool tool) {
-        if (isAlive() && elementType.isConstant()) {
-            ResolvedJavaType javaType = tool.getConstantReflection().asJavaType(elementType.asConstant());
-            if (javaType != null && !javaType.equals(tool.getMetaAccess().lookupJavaType(void.class))) {
-                NewArrayNode newArray = forConstantType(javaType);
-                List<Node> snapshot = inputs().snapshot();
-                graph().replaceFixedWithFixed(this, newArray);
-                for (Node input : snapshot) {
-                    tool.removeIfUnused(input);
-                }
-                tool.addToWorkList(newArray);
+    public Node canonical(CanonicalizerTool tool) {
+        if (elementType.isConstant()) {
+            ResolvedJavaType type = tool.getConstantReflection().asJavaType(elementType.asConstant());
+            if (type != null && !throwsIllegalArgumentException(type)) {
+                return new NewArrayNode(type, length(), fillContents());
             }
         }
+        return this;
     }
 
-    @NodeIntrinsic
-    public static native Object newArray(Class<?> componentType, int length);
+    public static boolean throwsIllegalArgumentException(Class<?> elementType) {
+        return elementType == void.class;
+    }
+
+    public static boolean throwsIllegalArgumentException(ResolvedJavaType elementType) {
+        return elementType.getKind() == Kind.Void;
+    }
 
     @NodeIntrinsic
     private static native Object newArray(Class<?> componentType, int length, @ConstantNodeParameter boolean fillContents, @ConstantNodeParameter Kind knownElementKind);
--- a/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java	Wed Jun 10 17:23:19 2015 -0700
@@ -22,6 +22,8 @@
  */
 package com.oracle.graal.nodes.java;
 
+import java.lang.reflect.*;
+
 import com.oracle.graal.compiler.common.type.*;
 import com.oracle.graal.graph.*;
 import com.oracle.graal.graph.spi.*;
@@ -40,21 +42,34 @@
         this.clazz = clazz;
     }
 
+    public ValueNode getInstanceType() {
+        return clazz;
+    }
+
+    @Override
+    public void simplify(SimplifierTool tool) {
+        /*
+         * Do not call the super implementation: we must not eliminate unused allocations because
+         * throwing an InstantiationException is a possible side effect of an unused allocation.
+         */
+    }
+
     @Override
     public Node canonical(CanonicalizerTool tool) {
         if (clazz.isConstant()) {
             ResolvedJavaType type = tool.getConstantReflection().asJavaType(clazz.asConstant());
-            if (type != null && type.isInitialized() && !type.isArray() && !type.isInterface() && !type.isPrimitive()) {
+            if (type != null && type.isInitialized() && !throwsInstantiationException(type, tool.getMetaAccess())) {
                 return new NewInstanceNode(type, fillContents());
             }
         }
         return this;
     }
 
-    public ValueNode getInstanceType() {
-        return clazz;
+    public static boolean throwsInstantiationException(Class<?> type) {
+        return type.isPrimitive() || type.isArray() || type.isInterface() || Modifier.isAbstract(type.getModifiers()) || type == Class.class;
     }
 
-    @NodeIntrinsic
-    public static native Object allocateInstance(Class<?> clazz, @ConstantNodeParameter boolean fillContents);
+    public static boolean throwsInstantiationException(ResolvedJavaType type, MetaAccessProvider metaAccess) {
+        return type.isPrimitive() || type.isArray() || type.isInterface() || Modifier.isAbstract(type.getModifiers()) || type.equals(metaAccess.lookupJavaType(Class.class));
+    }
 }
--- a/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java	Wed Jun 10 17:23:19 2015 -0700
@@ -28,12 +28,11 @@
 
 import sun.misc.*;
 
-import com.oracle.graal.replacements.*;
 import com.oracle.jvmci.code.*;
 import com.oracle.jvmci.meta.*;
 
 /**
- * Tests the VM independent {@link UnsafeSubstitutions}.
+ * Tests the VM independent intrinsification of {@link Unsafe} methods.
  */
 public class UnsafeSubstitutionsTest extends MethodSubstitutionTest {
 
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java	Wed Jun 10 17:23:19 2015 -0700
@@ -22,9 +22,6 @@
  */
 package com.oracle.graal.replacements;
 
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-
-import com.oracle.graal.api.directives.*;
 import com.oracle.graal.nodes.*;
 import com.oracle.graal.nodes.java.*;
 import com.oracle.jvmci.meta.*;
@@ -36,18 +33,6 @@
  */
 public class ArraySubstitutions {
 
-    public static Object newInstance(Class<?> componentType, int length) throws NegativeArraySizeException {
-        // The error cases must be handled here since DynamicNewArrayNode can only deoptimize the
-        // caller in response to exceptions.
-        if (probability(SLOW_PATH_PROBABILITY, length < 0)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
-        }
-        if (probability(SLOW_PATH_PROBABILITY, componentType == void.class)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
-        }
-        return DynamicNewArrayNode.newArray(GraalDirectives.guardingNonNull(componentType), length);
-    }
-
     public static int getLength(Object array) {
         if (!array.getClass().isArray()) {
             DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Thu Jun 11 01:21:44 2015 +0200
+++ b/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java	Wed Jun 10 17:23:19 2015 -0700
@@ -124,7 +124,12 @@
 
     private static void registerArrayPlugins(InvocationPlugins plugins) {
         Registration r = new Registration(plugins, Array.class);
-        r.registerMethodSubstitution(ArraySubstitutions.class, "newInstance", Class.class, int.class);
+        r.register2("newInstance", Class.class, int.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unused, ValueNode componentType, ValueNode length) {
+                b.addPush(Kind.Object, new DynamicNewArrayNode(componentType, length, true, null));
+                return true;
+            }
+        });
         r.registerMethodSubstitution(ArraySubstitutions.class, "getLength", Object.class);
     }
 
@@ -169,6 +174,15 @@
                 }
             });
         }
+
+        r.register2("allocateInstance", Receiver.class, Class.class, new InvocationPlugin() {
+            public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver unsafe, ValueNode clazz) {
+                // Emits a null-check for the otherwise unused receiver
+                unsafe.get();
+                b.addPush(Kind.Object, new DynamicNewInstanceNode(clazz, true));
+                return true;
+            }
+        });
     }
 
     private static void registerIntegerLongPlugins(InvocationPlugins plugins, Kind kind) {
--- a/graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java	Thu Jun 11 01:21:44 2015 +0200
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,55 +0,0 @@
-/*
- * Copyright (c) 2011, 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.replacements;
-
-import static com.oracle.graal.nodes.extended.BranchProbabilityNode.*;
-
-import java.lang.reflect.*;
-
-import sun.misc.*;
-
-import com.oracle.graal.api.replacements.*;
-import com.oracle.graal.nodes.*;
-import com.oracle.graal.nodes.java.*;
-import com.oracle.jvmci.meta.*;
-
-/**
- * Substitutions for {@link sun.misc.Unsafe} methods.
- */
-@ClassSubstitution(sun.misc.Unsafe.class)
-public class UnsafeSubstitutions {
-
-    @MethodSubstitution(isStatic = false)
-    public static Object allocateInstance(@SuppressWarnings("unused") final Unsafe thisObj, Class<?> clazz) {
-        if (probability(SLOW_PATH_PROBABILITY, clazz.isPrimitive())) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
-        }
-        if (probability(SLOW_PATH_PROBABILITY, clazz.isArray() || clazz.isInterface() || Modifier.isAbstract(clazz.getModifiers()))) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
-        }
-        if (probability(SLOW_PATH_PROBABILITY, clazz == Class.class)) {
-            DeoptimizeNode.deopt(DeoptimizationAction.None, DeoptimizationReason.RuntimeConstraint);
-        }
-        return DynamicNewInstanceNode.allocateInstance(clazz, true);
-    }
-}