--- /dev/null 2016-05-31 09:42:47.975716356 -0700 +++ new/src/jdk.vm.compiler/share/classes/org.graalvm.compiler.hotspot/src/org/graalvm/compiler/hotspot/phases/aot/ReplaceConstantNodesPhase.java 2016-12-09 00:49:49.151187433 -0800 @@ -0,0 +1,185 @@ +/* + * Copyright (c) 2016, 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 org.graalvm.compiler.hotspot.phases.aot; + +import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes; +import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes; + +import java.util.HashSet; + +import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant; +import jdk.vm.ci.hotspot.HotSpotObjectConstant; +import jdk.vm.ci.hotspot.HotSpotResolvedJavaType; +import jdk.vm.ci.hotspot.HotSpotResolvedObjectType; +import jdk.vm.ci.meta.Constant; +import jdk.vm.ci.meta.ConstantReflectionProvider; +import jdk.vm.ci.meta.ResolvedJavaType; + +import org.graalvm.compiler.core.common.type.ObjectStamp; +import org.graalvm.compiler.core.common.type.Stamp; +import org.graalvm.compiler.core.common.type.StampFactory; +import org.graalvm.compiler.debug.GraalError; +import org.graalvm.compiler.graph.Node; +import org.graalvm.compiler.hotspot.FingerprintUtil; +import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction; +import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode; +import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode; +import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode; +import org.graalvm.compiler.nodes.ConstantNode; +import org.graalvm.compiler.nodes.StructuredGraph; +import org.graalvm.compiler.nodes.ValueNode; +import org.graalvm.compiler.phases.BasePhase; +import org.graalvm.compiler.phases.tiers.PhaseContext; + +public class ReplaceConstantNodesPhase extends BasePhase { + + private static final HashSet> builtIns = new HashSet<>(); + + static { + builtIns.add(Boolean.class); + + Class characterCacheClass = Character.class.getDeclaredClasses()[0]; + assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName()); + builtIns.add(characterCacheClass); + + Class byteCacheClass = Byte.class.getDeclaredClasses()[0]; + assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName()); + builtIns.add(byteCacheClass); + + Class shortCacheClass = Short.class.getDeclaredClasses()[0]; + assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName()); + builtIns.add(shortCacheClass); + + Class integerCacheClass = Integer.class.getDeclaredClasses()[0]; + assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName()); + builtIns.add(integerCacheClass); + + Class longCacheClass = Long.class.getDeclaredClasses()[0]; + assert "java.lang.Long$LongCache".equals(longCacheClass.getName()); + builtIns.add(longCacheClass); + } + + private static boolean isReplacementNode(Node n) { + // @formatter:off + return n instanceof LoadConstantIndirectlyNode || + n instanceof LoadConstantIndirectlyFixedNode || + n instanceof ResolveConstantNode || + n instanceof InitializeKlassNode; + // @formatter:on + } + + private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) { + if (type.isArray()) { + if (type.getElementalType().isPrimitive()) { + return false; + } + return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) (type.getElementalType())) == 0; + } + return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0; + } + + private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) { + HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType(); + + if (type != null) { + if (checkForBadFingerprint(type)) { + throw new GraalError("Type with bad fingerprint: " + type); + } + + assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants"; + ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass(); + ValueNode replacement; + + if (type.isArray() && type.getComponentType().isPrimitive()) { + // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may + // omit the resolution call. + replacement = new LoadConstantIndirectlyNode(node); + } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) { + // If it's a supertype of or the same class that declares the top method, we are + // guaranteed to have it resolved already. If it's an interface, we just test for + // equality. + replacement = new LoadConstantIndirectlyNode(node); + } else if (builtIns.contains(type.mirror())) { + // Special case of klass constants that come from {@link BoxingSnippets}. + replacement = new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE); + } else { + replacement = new ResolveConstantNode(node); + } + + node.replaceAtUsages(graph.addOrUnique(replacement), n -> !isReplacementNode(n)); + } else { + throw new GraalError("Unsupported metaspace constant type: " + type); + } + } + + private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) { + HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant(); + HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType(); + if (type.mirror().equals(String.class)) { + assert !constant.isCompressed() : "No support for replacing compressed oop constants"; + ValueNode replacement = graph.unique(new ResolveConstantNode(node)); + node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode)); + } else { + throw new GraalError("Unsupported object constant type: " + type); + } + } + + private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) { + ResolvedJavaType type = node.getMethod().getDeclaringClass(); + Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull()); + ConstantReflectionProvider constantReflection = context.getConstantReflection(); + ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph); + ValueNode replacement = graph.unique(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint)); + node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode)); + } + + @Override + protected void run(StructuredGraph graph, PhaseContext context) { + // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass + // constants. + for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) { + handleLoadMethodCounters(graph, node, context); + } + + // Replace object and klass constants (including the ones added in the previous pass) with + // resolution nodes. + for (ConstantNode node : getConstantNodes(graph)) { + Constant constant = node.asConstant(); + if (constant instanceof HotSpotMetaspaceConstant) { + handleHotSpotMetaspaceConstant(graph, node); + } else if (constant instanceof HotSpotObjectConstant) { + handleHotSpotObjectConstant(graph, node); + } + } + } + + @Override + public boolean checkContract() { + return false; + } + +}