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