# HG changeset patch # User Christian Wimmer # Date 1433982199 25200 # Node ID 64475dbf6aec387877149a8902907fd5514ca26f # Parent f6fd9fb118160756b491a05824575a500f7d09fd 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. diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/HotSpotSubstitutions.java --- 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); } diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.hotspot/src/com/oracle/graal/hotspot/replacements/NewObjectSnippets.java --- 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); diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewArrayNode.java --- 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 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 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); diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.nodes/src/com/oracle/graal/nodes/java/DynamicNewInstanceNode.java --- 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)); + } } diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.replacements.test/src/com/oracle/graal/replacements/test/UnsafeSubstitutionsTest.java --- 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 { diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/ArraySubstitutions.java --- 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); diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/StandardGraphBuilderPlugins.java --- 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) { diff -r f6fd9fb11816 -r 64475dbf6aec graal/com.oracle.graal.replacements/src/com/oracle/graal/replacements/UnsafeSubstitutions.java --- 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); - } -}