70 import jdk.vm.ci.meta.ResolvedJavaMethod; |
68 import jdk.vm.ci.meta.ResolvedJavaMethod; |
71 import sun.misc.Unsafe; |
69 import sun.misc.Unsafe; |
72 |
70 |
73 public class AMD64GraphBuilderPlugins implements TargetGraphBuilderPlugins { |
71 public class AMD64GraphBuilderPlugins implements TargetGraphBuilderPlugins { |
74 @Override |
72 @Override |
75 public void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, Architecture architecture, boolean explicitUnsafeNullChecks, |
73 public void register(Plugins plugins, Replacements replacements, Architecture architecture, boolean explicitUnsafeNullChecks, |
76 boolean registerMathPlugins, boolean emitJDK9StringSubstitutions, boolean useFMAIntrinsics) { |
74 boolean registerMathPlugins, boolean emitJDK9StringSubstitutions, boolean useFMAIntrinsics) { |
77 register(plugins, replacementsBytecodeProvider, (AMD64) architecture, explicitUnsafeNullChecks, emitJDK9StringSubstitutions, useFMAIntrinsics); |
75 register(plugins, replacements, (AMD64) architecture, explicitUnsafeNullChecks, emitJDK9StringSubstitutions, useFMAIntrinsics); |
78 } |
76 } |
79 |
77 |
80 public static void register(Plugins plugins, BytecodeProvider replacementsBytecodeProvider, AMD64 arch, boolean explicitUnsafeNullChecks, boolean emitJDK9StringSubstitutions, |
78 public static void register(Plugins plugins, Replacements replacements, AMD64 arch, boolean explicitUnsafeNullChecks, |
|
79 boolean emitJDK9StringSubstitutions, |
81 boolean useFMAIntrinsics) { |
80 boolean useFMAIntrinsics) { |
82 InvocationPlugins invocationPlugins = plugins.getInvocationPlugins(); |
81 InvocationPlugins invocationPlugins = plugins.getInvocationPlugins(); |
83 invocationPlugins.defer(new Runnable() { |
82 invocationPlugins.defer(new Runnable() { |
84 @Override |
83 @Override |
85 public void run() { |
84 public void run() { |
86 registerThreadPlugins(invocationPlugins, arch); |
85 registerThreadPlugins(invocationPlugins, arch); |
87 registerIntegerLongPlugins(invocationPlugins, IntegerSubstitutions.class, JavaKind.Int, arch, replacementsBytecodeProvider); |
86 registerIntegerLongPlugins(invocationPlugins, AMD64IntegerSubstitutions.class, JavaKind.Int, arch, replacements); |
88 registerIntegerLongPlugins(invocationPlugins, LongSubstitutions.class, JavaKind.Long, arch, replacementsBytecodeProvider); |
87 registerIntegerLongPlugins(invocationPlugins, AMD64LongSubstitutions.class, JavaKind.Long, arch, replacements); |
89 registerPlatformSpecificUnsafePlugins(invocationPlugins, replacementsBytecodeProvider, explicitUnsafeNullChecks, |
88 registerPlatformSpecificUnsafePlugins(invocationPlugins, replacements, explicitUnsafeNullChecks, |
90 new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object, JavaKind.Boolean, JavaKind.Byte, JavaKind.Short, JavaKind.Char, JavaKind.Float, JavaKind.Double}); |
89 new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object, JavaKind.Boolean, JavaKind.Byte, JavaKind.Short, JavaKind.Char, JavaKind.Float, JavaKind.Double}); |
91 registerUnsafePlugins(invocationPlugins, replacementsBytecodeProvider, explicitUnsafeNullChecks); |
90 registerUnsafePlugins(invocationPlugins, replacements, explicitUnsafeNullChecks); |
92 registerStringPlugins(invocationPlugins, replacementsBytecodeProvider); |
91 registerStringPlugins(invocationPlugins, replacements); |
93 if (emitJDK9StringSubstitutions) { |
92 if (emitJDK9StringSubstitutions) { |
94 registerStringLatin1Plugins(invocationPlugins, replacementsBytecodeProvider); |
93 registerStringLatin1Plugins(invocationPlugins, replacements); |
95 registerStringUTF16Plugins(invocationPlugins, replacementsBytecodeProvider); |
94 registerStringUTF16Plugins(invocationPlugins, replacements); |
96 } |
95 } |
97 registerMathPlugins(invocationPlugins, useFMAIntrinsics, arch, replacementsBytecodeProvider); |
96 registerMathPlugins(invocationPlugins, useFMAIntrinsics, arch, replacements); |
98 registerArraysEqualsPlugins(invocationPlugins, replacementsBytecodeProvider); |
97 registerArraysEqualsPlugins(invocationPlugins, replacements); |
99 } |
98 } |
100 }); |
99 }); |
101 } |
100 } |
102 |
101 |
103 private static void registerThreadPlugins(InvocationPlugins plugins, AMD64 arch) { |
102 private static void registerThreadPlugins(InvocationPlugins plugins, AMD64 arch) { |
104 if (JavaVersionUtil.JAVA_SPEC > 8) { |
103 if (JavaVersionUtil.JAVA_SPEC > 8) { |
105 // Pause instruction introduced with SSE2 |
104 // Pause instruction introduced with SSE2 |
106 if (arch.getFeatures().contains(AMD64.CPUFeature.SSE2)) { |
105 assert (arch.getFeatures().contains(AMD64.CPUFeature.SSE2)); |
107 Registration r = new Registration(plugins, Thread.class); |
106 Registration r = new Registration(plugins, Thread.class); |
108 r.register0("onSpinWait", new InvocationPlugin() { |
107 r.register0("onSpinWait", new InvocationPlugin() { |
109 @Override |
|
110 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { |
|
111 b.append(new PauseNode()); |
|
112 return true; |
|
113 } |
|
114 }); |
|
115 } |
|
116 } |
|
117 } |
|
118 |
|
119 private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, AMD64 arch, BytecodeProvider bytecodeProvider) { |
|
120 Class<?> declaringClass = kind.toBoxedJavaClass(); |
|
121 Class<?> type = kind.toJavaClass(); |
|
122 Registration r = new Registration(plugins, declaringClass, bytecodeProvider); |
|
123 r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type); |
|
124 if (arch.getFeatures().contains(AMD64.CPUFeature.LZCNT) && arch.getFlags().contains(AMD64.Flag.UseCountLeadingZerosInstruction)) { |
|
125 r.setAllowOverwrite(true); |
|
126 r.register1("numberOfLeadingZeros", type, new InvocationPlugin() { |
|
127 @Override |
108 @Override |
128 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { |
109 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver) { |
129 ValueNode folded = AMD64CountLeadingZerosNode.tryFold(value); |
110 b.append(new PauseNode()); |
130 if (folded != null) { |
|
131 b.addPush(JavaKind.Int, folded); |
|
132 } else { |
|
133 b.addPush(JavaKind.Int, new AMD64CountLeadingZerosNode(value)); |
|
134 } |
|
135 return true; |
111 return true; |
136 } |
112 } |
137 }); |
113 }); |
138 } |
114 } |
139 |
115 } |
|
116 |
|
117 private static void registerIntegerLongPlugins(InvocationPlugins plugins, Class<?> substituteDeclaringClass, JavaKind kind, AMD64 arch, Replacements replacements) { |
|
118 Class<?> declaringClass = kind.toBoxedJavaClass(); |
|
119 Class<?> type = kind.toJavaClass(); |
|
120 Registration r = new Registration(plugins, declaringClass, replacements); |
|
121 r.registerMethodSubstitution(substituteDeclaringClass, "numberOfLeadingZeros", type); |
140 r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type); |
122 r.registerMethodSubstitution(substituteDeclaringClass, "numberOfTrailingZeros", type); |
141 if (arch.getFeatures().contains(AMD64.CPUFeature.BMI1) && arch.getFlags().contains(AMD64.Flag.UseCountTrailingZerosInstruction)) { |
123 |
142 r.setAllowOverwrite(true); |
124 r.registerConditional1(arch.getFeatures().contains(AMD64.CPUFeature.POPCNT), |
143 r.register1("numberOfTrailingZeros", type, new InvocationPlugin() { |
125 "bitCount", type, new InvocationPlugin() { |
144 |
126 @Override |
145 @Override |
127 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { |
146 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { |
128 b.push(JavaKind.Int, b.append(new BitCountNode(value).canonical(null))); |
147 ValueNode folded = AMD64CountTrailingZerosNode.tryFold(value); |
129 return true; |
148 if (folded != null) { |
130 } |
149 b.addPush(JavaKind.Int, folded); |
131 }); |
150 } else { |
132 } |
151 b.addPush(JavaKind.Int, new AMD64CountTrailingZerosNode(value)); |
133 |
152 } |
134 private static void registerMathPlugins(InvocationPlugins plugins, boolean useFMAIntrinsics, AMD64 arch, Replacements replacements) { |
153 return true; |
135 Registration r = new Registration(plugins, Math.class, replacements); |
154 } |
|
155 }); |
|
156 } |
|
157 |
|
158 if (arch.getFeatures().contains(AMD64.CPUFeature.POPCNT)) { |
|
159 r.register1("bitCount", type, new InvocationPlugin() { |
|
160 @Override |
|
161 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode value) { |
|
162 b.push(JavaKind.Int, b.append(new BitCountNode(value).canonical(null))); |
|
163 return true; |
|
164 } |
|
165 }); |
|
166 } |
|
167 |
|
168 } |
|
169 |
|
170 private static void registerMathPlugins(InvocationPlugins plugins, boolean useFMAIntrinsics, AMD64 arch, BytecodeProvider bytecodeProvider) { |
|
171 Registration r = new Registration(plugins, Math.class, bytecodeProvider); |
|
172 registerUnaryMath(r, "log", LOG); |
136 registerUnaryMath(r, "log", LOG); |
173 registerUnaryMath(r, "log10", LOG10); |
137 registerUnaryMath(r, "log10", LOG10); |
174 registerUnaryMath(r, "exp", EXP); |
138 registerUnaryMath(r, "exp", EXP); |
175 registerBinaryMath(r, "pow", POW); |
139 registerBinaryMath(r, "pow", POW); |
176 registerUnaryMath(r, "sin", SIN); |
140 registerUnaryMath(r, "sin", SIN); |
177 registerUnaryMath(r, "cos", COS); |
141 registerUnaryMath(r, "cos", COS); |
178 registerUnaryMath(r, "tan", TAN); |
142 registerUnaryMath(r, "tan", TAN); |
179 |
143 |
180 if (arch.getFeatures().contains(CPUFeature.SSE4_1)) { |
144 boolean roundEnabled = arch.getFeatures().contains(CPUFeature.SSE4_1); |
181 registerRound(r, "rint", RoundingMode.NEAREST); |
145 registerRound(roundEnabled, r, "rint", RoundingMode.NEAREST); |
182 registerRound(r, "ceil", RoundingMode.UP); |
146 registerRound(roundEnabled, r, "ceil", RoundingMode.UP); |
183 registerRound(r, "floor", RoundingMode.DOWN); |
147 registerRound(roundEnabled, r, "floor", RoundingMode.DOWN); |
184 } |
148 |
185 |
149 if (JavaVersionUtil.JAVA_SPEC > 8) { |
186 if (useFMAIntrinsics && JavaVersionUtil.JAVA_SPEC > 8 && arch.getFeatures().contains(CPUFeature.FMA)) { |
150 registerFMA(r, useFMAIntrinsics && arch.getFeatures().contains(CPUFeature.FMA)); |
187 registerFMA(r); |
151 } |
188 } |
152 } |
189 } |
153 |
190 |
154 private static void registerFMA(Registration r, boolean isEnabled) { |
191 private static void registerFMA(Registration r) { |
155 r.registerConditional3(isEnabled, "fma", |
192 r.register3("fma", |
|
193 Double.TYPE, |
156 Double.TYPE, |
194 Double.TYPE, |
157 Double.TYPE, |
195 Double.TYPE, |
158 Double.TYPE, |
196 new InvocationPlugin() { |
159 new InvocationPlugin() { |
197 @Override |
160 @Override |
241 return true; |
204 return true; |
242 } |
205 } |
243 }); |
206 }); |
244 } |
207 } |
245 |
208 |
246 private static void registerRound(Registration r, String name, RoundingMode mode) { |
209 private static void registerRound(boolean isEnabled, Registration r, String name, RoundingMode mode) { |
247 r.register1(name, Double.TYPE, new InvocationPlugin() { |
210 r.registerConditional1(isEnabled, name, Double.TYPE, new InvocationPlugin() { |
248 @Override |
211 @Override |
249 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { |
212 public boolean apply(GraphBuilderContext b, ResolvedJavaMethod targetMethod, Receiver receiver, ValueNode arg) { |
250 b.push(JavaKind.Double, b.append(new AMD64RoundNode(arg, mode))); |
213 b.push(JavaKind.Double, b.append(new AMD64RoundNode(arg, mode))); |
251 return true; |
214 return true; |
252 } |
215 } |
253 }); |
216 }); |
254 } |
217 } |
255 |
218 |
256 private static void registerStringPlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { |
219 private static void registerStringPlugins(InvocationPlugins plugins, Replacements replacements) { |
257 if (JavaVersionUtil.JAVA_SPEC <= 8) { |
220 if (JavaVersionUtil.JAVA_SPEC <= 8) { |
258 Registration r; |
221 Registration r; |
259 r = new Registration(plugins, String.class, replacementsBytecodeProvider); |
222 r = new Registration(plugins, String.class, replacements); |
260 r.setAllowOverwrite(true); |
223 r.setAllowOverwrite(true); |
261 r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class, |
224 r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", char[].class, int.class, |
262 int.class, char[].class, int.class, int.class, int.class); |
225 int.class, char[].class, int.class, int.class, int.class); |
263 r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", Receiver.class, int.class, int.class); |
226 r.registerMethodSubstitution(AMD64StringSubstitutions.class, "indexOf", Receiver.class, int.class, int.class); |
264 r.registerMethodSubstitution(AMD64StringSubstitutions.class, "compareTo", Receiver.class, String.class); |
227 r.registerMethodSubstitution(AMD64StringSubstitutions.class, "compareTo", Receiver.class, String.class); |
265 } |
228 } |
266 } |
229 } |
267 |
230 |
268 private static void registerStringLatin1Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { |
231 private static void registerStringLatin1Plugins(InvocationPlugins plugins, Replacements replacements) { |
269 Registration r = new Registration(plugins, "java.lang.StringLatin1", replacementsBytecodeProvider); |
232 Registration r = new Registration(plugins, "java.lang.StringLatin1", replacements); |
270 r.setAllowOverwrite(true); |
233 r.setAllowOverwrite(true); |
271 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class); |
234 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareTo", byte[].class, byte[].class); |
272 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class); |
235 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "compareToUTF16", byte[].class, byte[].class); |
273 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "inflate", byte[].class, int.class, char[].class, int.class, int.class); |
236 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "inflate", byte[].class, int.class, char[].class, int.class, int.class); |
274 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "inflate", byte[].class, int.class, byte[].class, int.class, int.class); |
237 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "inflate", byte[].class, int.class, byte[].class, int.class, int.class); |
275 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "indexOf", byte[].class, int.class, int.class); |
238 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "indexOf", byte[].class, int.class, int.class); |
276 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "indexOf", byte[].class, int.class, byte[].class, int.class, int.class); |
239 r.registerMethodSubstitution(AMD64StringLatin1Substitutions.class, "indexOf", byte[].class, int.class, byte[].class, int.class, int.class); |
277 } |
240 } |
278 |
241 |
279 private static void registerStringUTF16Plugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider) { |
242 private static void registerStringUTF16Plugins(InvocationPlugins plugins, Replacements replacements) { |
280 Registration r = new Registration(plugins, "java.lang.StringUTF16", replacementsBytecodeProvider); |
243 Registration r = new Registration(plugins, "java.lang.StringUTF16", replacements); |
281 r.setAllowOverwrite(true); |
244 r.setAllowOverwrite(true); |
282 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class); |
245 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareTo", byte[].class, byte[].class); |
283 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class); |
246 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compareToLatin1", byte[].class, byte[].class); |
284 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compress", char[].class, int.class, byte[].class, int.class, int.class); |
247 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compress", char[].class, int.class, byte[].class, int.class, int.class); |
285 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compress", byte[].class, int.class, byte[].class, int.class, int.class); |
248 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "compress", byte[].class, int.class, byte[].class, int.class, int.class); |
286 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfCharUnsafe", byte[].class, int.class, int.class, int.class); |
249 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfCharUnsafe", byte[].class, int.class, int.class, int.class); |
287 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class); |
250 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfUnsafe", byte[].class, int.class, byte[].class, int.class, int.class); |
288 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfLatin1Unsafe", byte[].class, int.class, byte[].class, int.class, int.class); |
251 r.registerMethodSubstitution(AMD64StringUTF16Substitutions.class, "indexOfLatin1Unsafe", byte[].class, int.class, byte[].class, int.class, int.class); |
289 } |
252 } |
290 |
253 |
291 private static void registerUnsafePlugins(InvocationPlugins plugins, BytecodeProvider replacementsBytecodeProvider, boolean explicitUnsafeNullChecks) { |
254 private static void registerUnsafePlugins(InvocationPlugins plugins, Replacements replacements, boolean explicitUnsafeNullChecks) { |
292 registerUnsafePlugins(new Registration(plugins, Unsafe.class), explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true); |
255 registerUnsafePlugins(new Registration(plugins, Unsafe.class), explicitUnsafeNullChecks, new JavaKind[]{JavaKind.Int, JavaKind.Long, JavaKind.Object}, true); |
293 if (JavaVersionUtil.JAVA_SPEC > 8) { |
256 if (JavaVersionUtil.JAVA_SPEC > 8) { |
294 registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacementsBytecodeProvider), explicitUnsafeNullChecks, |
257 registerUnsafePlugins(new Registration(plugins, "jdk.internal.misc.Unsafe", replacements), explicitUnsafeNullChecks, |
295 new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Object}, |
258 new JavaKind[]{JavaKind.Boolean, JavaKind.Byte, JavaKind.Char, JavaKind.Short, JavaKind.Int, JavaKind.Long, JavaKind.Object}, |
296 JavaVersionUtil.JAVA_SPEC <= 11); |
259 JavaVersionUtil.JAVA_SPEC <= 11); |
297 } |
260 } |
298 } |
261 } |
299 |
262 |