1 /*
2  * Copyright (c) 2015, 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  */
23 
24 
25 package org.graalvm.compiler.hotspot.meta;
26 
27 import static org.graalvm.compiler.core.common.GraalOptions.ImmutableCode;
28 
29 import org.graalvm.compiler.core.common.type.StampPair;
30 import org.graalvm.compiler.nodes.ConstantNode;
31 import org.graalvm.compiler.nodes.ValueNode;
32 import org.graalvm.compiler.nodes.extended.GuardingNode;
33 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderContext;
34 import org.graalvm.compiler.nodes.graphbuilderconf.GraphBuilderTool;
35 import org.graalvm.compiler.nodes.graphbuilderconf.InlineInvokePlugin;
36 import org.graalvm.compiler.nodes.graphbuilderconf.NodePlugin;
37 import org.graalvm.compiler.nodes.graphbuilderconf.TypePlugin;
38 import org.graalvm.compiler.nodes.util.ConstantFoldUtil;
39 import org.graalvm.compiler.word.Word;
40 import org.graalvm.compiler.word.WordOperationPlugin;
41 
42 import jdk.vm.ci.meta.JavaConstant;
43 import jdk.vm.ci.meta.JavaKind;
44 import jdk.vm.ci.meta.JavaType;
45 import jdk.vm.ci.meta.JavaTypeProfile;
46 import jdk.vm.ci.meta.ResolvedJavaField;
47 import jdk.vm.ci.meta.ResolvedJavaMethod;
48 import jdk.vm.ci.meta.ResolvedJavaType;
49 
50 /**
51  * This plugin handles the HotSpot-specific customizations of bytecode parsing:
52  * <p>
53  * {@link Word}-type rewriting for {@link GraphBuilderContext#parsingIntrinsic intrinsic} functions
54  * (snippets and method substitutions), by forwarding to the {@link WordOperationPlugin}. Note that
55  * we forward the {@link NodePlugin} and {@link TypePlugin} methods, but not the
56  * {@link InlineInvokePlugin} methods implemented by {@link WordOperationPlugin}. The latter is not
57  * necessary because HotSpot only uses the {@link Word} type in methods that are force-inlined,
58  * i.e., there are never non-inlined invokes that involve the {@link Word} type.
59  * <p>
60  * Constant folding of field loads.
61  */
62 public final class HotSpotNodePlugin implements NodePlugin, TypePlugin {
63     protected final WordOperationPlugin wordOperationPlugin;
64 
HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin)65     public HotSpotNodePlugin(WordOperationPlugin wordOperationPlugin) {
66         this.wordOperationPlugin = wordOperationPlugin;
67     }
68 
69     @Override
canChangeStackKind(GraphBuilderContext b)70     public boolean canChangeStackKind(GraphBuilderContext b) {
71         if (b.parsingIntrinsic()) {
72             return wordOperationPlugin.canChangeStackKind(b);
73         }
74         return false;
75     }
76 
77     @Override
interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull)78     public StampPair interceptType(GraphBuilderTool b, JavaType declaredType, boolean nonNull) {
79         if (b.parsingIntrinsic()) {
80             return wordOperationPlugin.interceptType(b, declaredType, nonNull);
81         }
82         return null;
83     }
84 
85     @Override
handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args)86     public boolean handleInvoke(GraphBuilderContext b, ResolvedJavaMethod method, ValueNode[] args) {
87         if (b.parsingIntrinsic() && wordOperationPlugin.handleInvoke(b, method, args)) {
88             return true;
89         }
90         return false;
91     }
92 
93     @Override
handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field)94     public boolean handleLoadField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field) {
95         if (!ImmutableCode.getValue(b.getOptions()) || b.parsingIntrinsic()) {
96             if (object.isConstant()) {
97                 JavaConstant asJavaConstant = object.asJavaConstant();
98                 if (tryReadField(b, field, asJavaConstant)) {
99                     return true;
100                 }
101             }
102         }
103         if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadField(b, object, field)) {
104             return true;
105         }
106         return false;
107     }
108 
109     @Override
handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field)110     public boolean handleLoadStaticField(GraphBuilderContext b, ResolvedJavaField field) {
111         if (!ImmutableCode.getValue(b.getOptions()) || b.parsingIntrinsic()) {
112             if (tryReadField(b, field, null)) {
113                 return true;
114             }
115         }
116         if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadStaticField(b, field)) {
117             return true;
118         }
119         return false;
120     }
121 
tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object)122     private static boolean tryReadField(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) {
123         return tryConstantFold(b, field, object);
124     }
125 
tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object)126     private static boolean tryConstantFold(GraphBuilderContext b, ResolvedJavaField field, JavaConstant object) {
127         ConstantNode result = ConstantFoldUtil.tryConstantFold(b.getConstantFieldProvider(), b.getConstantReflection(), b.getMetaAccess(), field, object, b.getOptions());
128         if (result != null) {
129             result = b.getGraph().unique(result);
130             b.push(field.getJavaKind(), result);
131             return true;
132         }
133         return false;
134     }
135 
136     @Override
handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value)137     public boolean handleStoreField(GraphBuilderContext b, ValueNode object, ResolvedJavaField field, ValueNode value) {
138         if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreField(b, object, field, value)) {
139             return true;
140         }
141         return false;
142     }
143 
144     @Override
handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value)145     public boolean handleStoreStaticField(GraphBuilderContext b, ResolvedJavaField field, ValueNode value) {
146         if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreStaticField(b, field, value)) {
147             return true;
148         }
149         return false;
150     }
151 
152     @Override
handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind)153     public boolean handleLoadIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, JavaKind elementKind) {
154         if (b.parsingIntrinsic() && wordOperationPlugin.handleLoadIndexed(b, array, index, boundsCheck, elementKind)) {
155             return true;
156         }
157         return false;
158     }
159 
160     @Override
handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value)161     public boolean handleStoreIndexed(GraphBuilderContext b, ValueNode array, ValueNode index, GuardingNode boundsCheck, GuardingNode storeCheck, JavaKind elementKind, ValueNode value) {
162         if (b.parsingIntrinsic() && wordOperationPlugin.handleStoreIndexed(b, array, index, boundsCheck, storeCheck, elementKind, value)) {
163             return true;
164         }
165         return false;
166     }
167 
168     @Override
handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile)169     public boolean handleCheckCast(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
170         if (b.parsingIntrinsic() && wordOperationPlugin.handleCheckCast(b, object, type, profile)) {
171             return true;
172         }
173         return false;
174     }
175 
176     @Override
handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile)177     public boolean handleInstanceOf(GraphBuilderContext b, ValueNode object, ResolvedJavaType type, JavaTypeProfile profile) {
178         if (b.parsingIntrinsic() && wordOperationPlugin.handleInstanceOf(b, object, type, profile)) {
179             return true;
180         }
181         return false;
182     }
183 }
184