| /* |
| * 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<PhaseContext> { |
| |
| private static final HashSet<Class<?>> 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; |
| } |
| |
| } |