ReplaceConstantNodesPhase.java revision 12657:6ef01bd40ce2
1/*
2 * Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation.
8 *
9 * This code is distributed in the hope that it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12 * version 2 for more details (a copy is included in the LICENSE file that
13 * accompanied this code).
14 *
15 * You should have received a copy of the GNU General Public License version
16 * 2 along with this work; if not, write to the Free Software Foundation,
17 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18 *
19 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20 * or visit www.oracle.com if you need additional information or have any
21 * questions.
22 */
23package org.graalvm.compiler.hotspot.phases.aot;
24
25import static org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode.getLoadMethodCountersNodes;
26import static org.graalvm.compiler.nodes.ConstantNode.getConstantNodes;
27
28import java.util.HashSet;
29
30import jdk.vm.ci.hotspot.HotSpotMetaspaceConstant;
31import jdk.vm.ci.hotspot.HotSpotObjectConstant;
32import jdk.vm.ci.hotspot.HotSpotResolvedJavaType;
33import jdk.vm.ci.hotspot.HotSpotResolvedObjectType;
34import jdk.vm.ci.meta.Constant;
35import jdk.vm.ci.meta.ConstantReflectionProvider;
36import jdk.vm.ci.meta.ResolvedJavaType;
37
38import org.graalvm.compiler.core.common.type.ObjectStamp;
39import org.graalvm.compiler.core.common.type.Stamp;
40import org.graalvm.compiler.core.common.type.StampFactory;
41import org.graalvm.compiler.debug.GraalError;
42import org.graalvm.compiler.graph.Node;
43import org.graalvm.compiler.hotspot.FingerprintUtil;
44import org.graalvm.compiler.hotspot.meta.HotSpotConstantLoadAction;
45import org.graalvm.compiler.hotspot.nodes.aot.InitializeKlassNode;
46import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyFixedNode;
47import org.graalvm.compiler.hotspot.nodes.aot.LoadConstantIndirectlyNode;
48import org.graalvm.compiler.hotspot.nodes.aot.LoadMethodCountersNode;
49import org.graalvm.compiler.hotspot.nodes.aot.ResolveConstantNode;
50import org.graalvm.compiler.hotspot.nodes.aot.ResolveMethodAndLoadCountersNode;
51import org.graalvm.compiler.nodes.ConstantNode;
52import org.graalvm.compiler.nodes.StructuredGraph;
53import org.graalvm.compiler.nodes.ValueNode;
54import org.graalvm.compiler.phases.BasePhase;
55import org.graalvm.compiler.phases.tiers.PhaseContext;
56
57public class ReplaceConstantNodesPhase extends BasePhase<PhaseContext> {
58
59    private static final HashSet<Class<?>> builtIns = new HashSet<>();
60
61    static {
62        builtIns.add(Boolean.class);
63
64        Class<?> characterCacheClass = Character.class.getDeclaredClasses()[0];
65        assert "java.lang.Character$CharacterCache".equals(characterCacheClass.getName());
66        builtIns.add(characterCacheClass);
67
68        Class<?> byteCacheClass = Byte.class.getDeclaredClasses()[0];
69        assert "java.lang.Byte$ByteCache".equals(byteCacheClass.getName());
70        builtIns.add(byteCacheClass);
71
72        Class<?> shortCacheClass = Short.class.getDeclaredClasses()[0];
73        assert "java.lang.Short$ShortCache".equals(shortCacheClass.getName());
74        builtIns.add(shortCacheClass);
75
76        Class<?> integerCacheClass = Integer.class.getDeclaredClasses()[0];
77        assert "java.lang.Integer$IntegerCache".equals(integerCacheClass.getName());
78        builtIns.add(integerCacheClass);
79
80        Class<?> longCacheClass = Long.class.getDeclaredClasses()[0];
81        assert "java.lang.Long$LongCache".equals(longCacheClass.getName());
82        builtIns.add(longCacheClass);
83    }
84
85    private static boolean isReplacementNode(Node n) {
86        // @formatter:off
87        return n instanceof LoadConstantIndirectlyNode      ||
88               n instanceof LoadConstantIndirectlyFixedNode ||
89               n instanceof ResolveConstantNode             ||
90               n instanceof InitializeKlassNode;
91        // @formatter:on
92    }
93
94    private static boolean checkForBadFingerprint(HotSpotResolvedJavaType type) {
95        if (type.isArray()) {
96            if (type.getElementalType().isPrimitive()) {
97                return false;
98            }
99            return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) (type.getElementalType())) == 0;
100        }
101        return FingerprintUtil.getFingerprint((HotSpotResolvedObjectType) type) == 0;
102    }
103
104    private static void handleHotSpotMetaspaceConstant(StructuredGraph graph, ConstantNode node) {
105        HotSpotMetaspaceConstant metaspaceConstant = (HotSpotMetaspaceConstant) node.asConstant();
106        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) metaspaceConstant.asResolvedJavaType();
107
108        if (type != null) {
109            if (checkForBadFingerprint(type)) {
110                throw new GraalError("Type with bad fingerprint: " + type);
111            }
112
113            assert !metaspaceConstant.isCompressed() : "No support for replacing compressed metaspace constants";
114            ResolvedJavaType topMethodHolder = graph.method().getDeclaringClass();
115            ValueNode replacement;
116
117            if (type.isArray() && type.getComponentType().isPrimitive()) {
118                // Special case for primitive arrays. The AOT runtime pre-resolves them, so we may
119                // omit the resolution call.
120                replacement = new LoadConstantIndirectlyNode(node);
121            } else if (type.equals(topMethodHolder) || (type.isAssignableFrom(topMethodHolder) && !type.isInterface())) {
122                // If it's a supertype of or the same class that declares the top method, we are
123                // guaranteed to have it resolved already. If it's an interface, we just test for
124                // equality.
125                replacement = new LoadConstantIndirectlyNode(node);
126            } else if (builtIns.contains(type.mirror())) {
127                // Special case of klass constants that come from {@link BoxingSnippets}.
128                replacement = new ResolveConstantNode(node, HotSpotConstantLoadAction.INITIALIZE);
129            } else {
130                replacement = new ResolveConstantNode(node);
131            }
132
133            node.replaceAtUsages(graph.addOrUnique(replacement), n -> !isReplacementNode(n));
134        } else {
135            throw new GraalError("Unsupported metaspace constant type: " + type);
136        }
137    }
138
139    private static void handleHotSpotObjectConstant(StructuredGraph graph, ConstantNode node) {
140        HotSpotObjectConstant constant = (HotSpotObjectConstant) node.asJavaConstant();
141        HotSpotResolvedJavaType type = (HotSpotResolvedJavaType) constant.getType();
142        if (type.mirror().equals(String.class)) {
143            assert !constant.isCompressed() : "No support for replacing compressed oop constants";
144            ValueNode replacement = graph.unique(new ResolveConstantNode(node));
145            node.replaceAtUsages(replacement, n -> !(n instanceof ResolveConstantNode));
146        } else {
147            throw new GraalError("Unsupported object constant type: " + type);
148        }
149    }
150
151    private static void handleLoadMethodCounters(StructuredGraph graph, LoadMethodCountersNode node, PhaseContext context) {
152        ResolvedJavaType type = node.getMethod().getDeclaringClass();
153        Stamp hubStamp = context.getStampProvider().createHubStamp((ObjectStamp) StampFactory.objectNonNull());
154        ConstantReflectionProvider constantReflection = context.getConstantReflection();
155        ConstantNode klassHint = ConstantNode.forConstant(hubStamp, constantReflection.asObjectHub(type), context.getMetaAccess(), graph);
156        ValueNode replacement = graph.unique(new ResolveMethodAndLoadCountersNode(node.getMethod(), klassHint));
157        node.replaceAtUsages(replacement, n -> !(n instanceof ResolveMethodAndLoadCountersNode));
158    }
159
160    @Override
161    protected void run(StructuredGraph graph, PhaseContext context) {
162        // Replace LoadMethodCountersNode with ResolveMethodAndLoadCountersNode, expose klass
163        // constants.
164        for (LoadMethodCountersNode node : getLoadMethodCountersNodes(graph)) {
165            handleLoadMethodCounters(graph, node, context);
166        }
167
168        // Replace object and klass constants (including the ones added in the previous pass) with
169        // resolution nodes.
170        for (ConstantNode node : getConstantNodes(graph)) {
171            Constant constant = node.asConstant();
172            if (constant instanceof HotSpotMetaspaceConstant) {
173                handleHotSpotMetaspaceConstant(graph, node);
174            } else if (constant instanceof HotSpotObjectConstant) {
175                handleHotSpotObjectConstant(graph, node);
176            }
177        }
178    }
179
180    @Override
181    public boolean checkContract() {
182        return false;
183    }
184
185}
186