/* * 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; } }