1 /*
2  * Copyright (c) 2014, 2018, 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  */
23 
24 
25 package org.graalvm.compiler.hotspot.replacements;
26 
27 import static org.graalvm.compiler.nodeinfo.NodeCycles.CYCLES_1;
28 import static org.graalvm.compiler.nodeinfo.NodeSize.SIZE_1;
29 
30 import org.graalvm.compiler.core.common.calc.CanonicalCondition;
31 import org.graalvm.compiler.core.common.type.Stamp;
32 import org.graalvm.compiler.graph.Node;
33 import org.graalvm.compiler.graph.NodeClass;
34 import org.graalvm.compiler.graph.spi.Canonicalizable;
35 import org.graalvm.compiler.graph.spi.CanonicalizerTool;
36 import org.graalvm.compiler.hotspot.nodes.type.KlassPointerStamp;
37 import org.graalvm.compiler.hotspot.word.KlassPointer;
38 import org.graalvm.compiler.nodeinfo.NodeInfo;
39 import org.graalvm.compiler.nodes.ConstantNode;
40 import org.graalvm.compiler.nodes.NodeView;
41 import org.graalvm.compiler.nodes.PiNode;
42 import org.graalvm.compiler.nodes.ValueNode;
43 import org.graalvm.compiler.nodes.calc.ConvertNode;
44 import org.graalvm.compiler.nodes.calc.FloatingNode;
45 import org.graalvm.compiler.nodes.extended.GetClassNode;
46 import org.graalvm.compiler.nodes.extended.GuardingNode;
47 import org.graalvm.compiler.nodes.extended.LoadHubNode;
48 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
49 import org.graalvm.compiler.nodes.memory.ReadNode;
50 import org.graalvm.compiler.nodes.memory.address.AddressNode;
51 import org.graalvm.compiler.nodes.spi.Lowerable;
52 import org.graalvm.compiler.nodes.spi.LoweringTool;
53 import jdk.internal.vm.compiler.word.LocationIdentity;
54 
55 import jdk.vm.ci.meta.Constant;
56 import jdk.vm.ci.meta.ConstantReflectionProvider;
57 import jdk.vm.ci.meta.JavaConstant;
58 import jdk.vm.ci.meta.JavaKind;
59 import jdk.vm.ci.meta.MetaAccessProvider;
60 import jdk.vm.ci.meta.ResolvedJavaMethod;
61 import jdk.vm.ci.meta.ResolvedJavaType;
62 
63 /**
64  * Read {@code Class::_klass} to get the hub for a {@link java.lang.Class}. This node mostly exists
65  * to replace {@code _klass._java_mirror._klass} with {@code _klass}. The constant folding could be
66  * handled by
67  * {@link ReadNode#canonicalizeRead(ValueNode, AddressNode, LocationIdentity, CanonicalizerTool)}.
68  */
69 @NodeInfo(cycles = CYCLES_1, size = SIZE_1)
70 public final class ClassGetHubNode extends FloatingNode implements Lowerable, Canonicalizable, ConvertNode {
71     public static final NodeClass<ClassGetHubNode> TYPE = NodeClass.create(ClassGetHubNode.class);
72     @Input protected ValueNode clazz;
73 
ClassGetHubNode(ValueNode clazz)74     public ClassGetHubNode(ValueNode clazz) {
75         super(TYPE, KlassPointerStamp.klass());
76         this.clazz = clazz;
77     }
78 
create(ValueNode clazz, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable)79     public static ValueNode create(ValueNode clazz, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable) {
80         return canonical(null, metaAccess, constantReflection, allUsagesAvailable, KlassPointerStamp.klass(), clazz);
81     }
82 
83     @SuppressWarnings("unused")
intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode clazz)84     public static boolean intrinsify(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode clazz) {
85         ValueNode clazzValue = create(clazz, b.getMetaAccess(), b.getConstantReflection(), false);
86         b.push(JavaKind.Object, b.append(clazzValue));
87         return true;
88     }
89 
canonical(ClassGetHubNode classGetHubNode, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable, Stamp stamp, ValueNode clazz)90     public static ValueNode canonical(ClassGetHubNode classGetHubNode, MetaAccessProvider metaAccess, ConstantReflectionProvider constantReflection, boolean allUsagesAvailable, Stamp stamp,
91                     ValueNode clazz) {
92         ClassGetHubNode self = classGetHubNode;
93         if (allUsagesAvailable && self != null && self.hasNoUsages()) {
94             return null;
95         } else {
96             if (clazz.isConstant() && !clazz.isNullConstant()) {
97                 if (metaAccess != null) {
98                     ResolvedJavaType exactType = constantReflection.asJavaType(clazz.asJavaConstant());
99                     if (exactType.isPrimitive()) {
100                         return ConstantNode.forConstant(stamp, JavaConstant.NULL_POINTER, metaAccess);
101                     } else {
102                         return ConstantNode.forConstant(stamp, constantReflection.asObjectHub(exactType), metaAccess);
103                     }
104                 }
105             }
106             if (clazz instanceof GetClassNode) {
107                 GetClassNode getClass = (GetClassNode) clazz;
108                 return new LoadHubNode(KlassPointerStamp.klassNonNull(), getClass.getObject());
109             }
110             if (clazz instanceof HubGetClassNode) {
111                 // Replace: _klass._java_mirror._klass -> _klass
112                 return ((HubGetClassNode) clazz).getHub();
113             }
114             if (self == null) {
115                 self = new ClassGetHubNode(clazz);
116             }
117             return self;
118         }
119     }
120 
121     @Override
canonical(CanonicalizerTool tool)122     public Node canonical(CanonicalizerTool tool) {
123         return canonical(this, tool.getMetaAccess(), tool.getConstantReflection(), tool.allUsagesAvailable(), stamp(NodeView.DEFAULT), clazz);
124     }
125 
126     @Override
lower(LoweringTool tool)127     public void lower(LoweringTool tool) {
128         tool.getLowerer().lower(this, tool);
129     }
130 
131     @NodeIntrinsic
readClass(Class<?> clazzNonNull)132     public static native KlassPointer readClass(Class<?> clazzNonNull);
133 
134     @NodeIntrinsic(PiNode.class)
piCastNonNull(Object object, GuardingNode anchor)135     public static native KlassPointer piCastNonNull(Object object, GuardingNode anchor);
136 
137     @Override
getValue()138     public ValueNode getValue() {
139         return clazz;
140     }
141 
142     @Override
convert(Constant c, ConstantReflectionProvider constantReflection)143     public Constant convert(Constant c, ConstantReflectionProvider constantReflection) {
144         ResolvedJavaType exactType = constantReflection.asJavaType(c);
145         if (exactType.isPrimitive()) {
146             return JavaConstant.NULL_POINTER;
147         } else {
148             return constantReflection.asObjectHub(exactType);
149         }
150     }
151 
152     @Override
reverse(Constant c, ConstantReflectionProvider constantReflection)153     public Constant reverse(Constant c, ConstantReflectionProvider constantReflection) {
154         assert !c.equals(JavaConstant.NULL_POINTER);
155         ResolvedJavaType objectType = constantReflection.asJavaType(c);
156         return constantReflection.asJavaClass(objectType);
157     }
158 
159     @Override
isLossless()160     public boolean isLossless() {
161         return false;
162     }
163 
164     /**
165      * There is more than one {@link java.lang.Class} value that has a NULL hub.
166      */
167     @Override
mayNullCheckSkipConversion()168     public boolean mayNullCheckSkipConversion() {
169         return false;
170     }
171 
172     @Override
preservesOrder(CanonicalCondition op, Constant value, ConstantReflectionProvider constantReflection)173     public boolean preservesOrder(CanonicalCondition op, Constant value, ConstantReflectionProvider constantReflection) {
174         assert op == CanonicalCondition.EQ;
175         ResolvedJavaType exactType = constantReflection.asJavaType(value);
176         return !exactType.isPrimitive();
177     }
178 
179 }
180