1 /*
2 * Copyright (c) 2016, 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.serviceprovider;
26
27 import static java.lang.Thread.currentThread;
28
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.util.Arrays;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.ServiceConfigurationError;
35 import java.util.ServiceLoader;
36 import java.util.concurrent.atomic.AtomicLong;
37
38 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
39 import jdk.vm.ci.runtime.JVMCI;
40 import jdk.vm.ci.services.JVMCIPermission;
41 import jdk.vm.ci.services.Services;
42
43 /**
44 * Interface to functionality that abstracts over which JDK version Graal is running on.
45 */
46 public final class GraalServices {
47
48 private GraalServices() {
49 }
50
51 /**
52 * Gets an {@link Iterable} of the providers available for a given service.
53 *
54 * @throws SecurityException if on JDK8 and a security manager is present and it denies
55 * {@link JVMCIPermission}
56 */
57 public static <S> Iterable<S> load(Class<S> service) {
58 Iterable<S> iterable = ServiceLoader.load(service);
81 };
82 }
83 };
84 }
85
86 /**
87 * Opens all JVMCI packages to the module of a given class. This relies on JVMCI already having
88 * opened all its packages to the module defining {@link GraalServices}.
89 *
90 * @param other all JVMCI packages will be opened to the module defining this class
91 */
92 static void openJVMCITo(Class<?> other) {
93 Module jvmciModule = JVMCI_MODULE;
94 Module otherModule = other.getModule();
95 if (jvmciModule != otherModule) {
96 for (String pkg : jvmciModule.getPackages()) {
97 if (!jvmciModule.isOpen(pkg, otherModule)) {
98 // JVMCI initialization opens all JVMCI packages
99 // to Graal which is a prerequisite for Graal to
100 // open JVMCI packages to other modules.
101 JVMCI.initialize();
102
103 jvmciModule.addOpens(pkg, otherModule);
104 }
105 }
106 }
107 }
108
109 /**
110 * Gets the provider for a given service for which at most one provider must be available.
111 *
112 * @param service the service whose provider is being requested
113 * @param required specifies if an {@link InternalError} should be thrown if no provider of
114 * {@code service} is available
115 * @return the requested provider if available else {@code null}
116 * @throws SecurityException if on JDK8 and a security manager is present and it denies
117 * {@link JVMCIPermission}
118 */
119 public static <S> S loadSingle(Class<S> service, boolean required) {
120 assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName();
121 Iterable<S> providers = load(service);
162 * trusted code.
163 */
164 public static boolean isToStringTrusted(Class<?> c) {
165 Module module = c.getModule();
166 Module jvmciModule = JVMCI_MODULE;
167 assert jvmciModule.getPackages().contains("jdk.vm.ci.runtime");
168 if (module == jvmciModule || jvmciModule.isOpen(JVMCI_RUNTIME_PACKAGE, module)) {
169 // Can access non-statically-exported package in JVMCI
170 return true;
171 }
172 return false;
173 }
174
175 /**
176 * An implementation of {@link SpeculationReason} based on direct, unencoded values.
177 */
178 static final class DirectSpeculationReason implements SpeculationReason {
179 final int groupId;
180 final String groupName;
181 final Object[] context;
182
183 DirectSpeculationReason(int groupId, String groupName, Object[] context) {
184 this.groupId = groupId;
185 this.groupName = groupName;
186 this.context = context;
187 }
188
189 @Override
190 public boolean equals(Object obj) {
191 if (obj instanceof DirectSpeculationReason) {
192 DirectSpeculationReason that = (DirectSpeculationReason) obj;
193 return this.groupId == that.groupId && Arrays.equals(this.context, that.context);
194 }
195 return false;
196 }
197
198 @Override
199 public int hashCode() {
200 return groupId + Arrays.hashCode(this.context);
201 }
202
203 @Override
204 public String toString() {
205 return String.format("%s@%d%s", groupName, groupId, Arrays.toString(context));
206 }
207 }
208
209 static SpeculationReason createSpeculationReason(int groupId, String groupName, Object... context) {
210 return new DirectSpeculationReason(groupId, groupName, context);
211 }
212
213 /**
214 * Gets a unique identifier for this execution such as a process ID or a
215 * {@linkplain #getGlobalTimeStamp() fixed timestamp}.
216 */
217 public static String getExecutionID() {
218 return Long.toString(ProcessHandle.current().pid());
219 }
220
221 private static final AtomicLong globalTimeStamp = new AtomicLong();
222
223 /**
224 * Gets a time stamp for the current process. This method will always return the same value for
225 * the current VM execution.
226 */
|
1 /*
2 * Copyright (c) 2016, 2019, 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.serviceprovider;
26
27 import static java.lang.Thread.currentThread;
28
29 import java.io.IOException;
30 import java.io.InputStream;
31 import java.util.Arrays;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.ServiceConfigurationError;
35 import java.util.ServiceLoader;
36 import java.util.concurrent.atomic.AtomicLong;
37 import java.util.function.Supplier;
38
39 import org.graalvm.compiler.serviceprovider.SpeculationReasonGroup.SpeculationContextObject;
40
41 import jdk.vm.ci.code.BytecodePosition;
42 import jdk.vm.ci.meta.ResolvedJavaField;
43 import jdk.vm.ci.meta.ResolvedJavaMethod;
44 import jdk.vm.ci.meta.ResolvedJavaType;
45 import jdk.vm.ci.meta.SpeculationLog.SpeculationReason;
46 import jdk.vm.ci.meta.SpeculationLog.SpeculationReasonEncoding;
47 import jdk.vm.ci.runtime.JVMCI;
48 import jdk.vm.ci.services.JVMCIPermission;
49 import jdk.vm.ci.services.Services;
50
51 /**
52 * Interface to functionality that abstracts over which JDK version Graal is running on.
53 */
54 public final class GraalServices {
55
56 private GraalServices() {
57 }
58
59 /**
60 * Gets an {@link Iterable} of the providers available for a given service.
61 *
62 * @throws SecurityException if on JDK8 and a security manager is present and it denies
63 * {@link JVMCIPermission}
64 */
65 public static <S> Iterable<S> load(Class<S> service) {
66 Iterable<S> iterable = ServiceLoader.load(service);
89 };
90 }
91 };
92 }
93
94 /**
95 * Opens all JVMCI packages to the module of a given class. This relies on JVMCI already having
96 * opened all its packages to the module defining {@link GraalServices}.
97 *
98 * @param other all JVMCI packages will be opened to the module defining this class
99 */
100 static void openJVMCITo(Class<?> other) {
101 Module jvmciModule = JVMCI_MODULE;
102 Module otherModule = other.getModule();
103 if (jvmciModule != otherModule) {
104 for (String pkg : jvmciModule.getPackages()) {
105 if (!jvmciModule.isOpen(pkg, otherModule)) {
106 // JVMCI initialization opens all JVMCI packages
107 // to Graal which is a prerequisite for Graal to
108 // open JVMCI packages to other modules.
109 JVMCI.getRuntime();
110
111 jvmciModule.addOpens(pkg, otherModule);
112 }
113 }
114 }
115 }
116
117 /**
118 * Gets the provider for a given service for which at most one provider must be available.
119 *
120 * @param service the service whose provider is being requested
121 * @param required specifies if an {@link InternalError} should be thrown if no provider of
122 * {@code service} is available
123 * @return the requested provider if available else {@code null}
124 * @throws SecurityException if on JDK8 and a security manager is present and it denies
125 * {@link JVMCIPermission}
126 */
127 public static <S> S loadSingle(Class<S> service, boolean required) {
128 assert !service.getName().startsWith("jdk.vm.ci") : "JVMCI services must be loaded via " + Services.class.getName();
129 Iterable<S> providers = load(service);
170 * trusted code.
171 */
172 public static boolean isToStringTrusted(Class<?> c) {
173 Module module = c.getModule();
174 Module jvmciModule = JVMCI_MODULE;
175 assert jvmciModule.getPackages().contains("jdk.vm.ci.runtime");
176 if (module == jvmciModule || jvmciModule.isOpen(JVMCI_RUNTIME_PACKAGE, module)) {
177 // Can access non-statically-exported package in JVMCI
178 return true;
179 }
180 return false;
181 }
182
183 /**
184 * An implementation of {@link SpeculationReason} based on direct, unencoded values.
185 */
186 static final class DirectSpeculationReason implements SpeculationReason {
187 final int groupId;
188 final String groupName;
189 final Object[] context;
190 private SpeculationReasonEncoding encoding;
191
192 DirectSpeculationReason(int groupId, String groupName, Object[] context) {
193 this.groupId = groupId;
194 this.groupName = groupName;
195 this.context = context;
196 }
197
198 @Override
199 public boolean equals(Object obj) {
200 if (obj instanceof DirectSpeculationReason) {
201 DirectSpeculationReason that = (DirectSpeculationReason) obj;
202 return this.groupId == that.groupId && Arrays.equals(this.context, that.context);
203 }
204 return false;
205 }
206
207 @Override
208 public int hashCode() {
209 return groupId + Arrays.hashCode(this.context);
210 }
211
212 @Override
213 public String toString() {
214 return String.format("%s@%d%s", groupName, groupId, Arrays.toString(context));
215 }
216
217 @Override
218 public SpeculationReasonEncoding encode(Supplier<SpeculationReasonEncoding> encodingSupplier) {
219 if (encoding == null) {
220 encoding = encodingSupplier.get();
221 encoding.addInt(groupId);
222 for (Object o : context) {
223 if (o == null) {
224 encoding.addInt(0);
225 } else {
226 addNonNullObject(encoding, o);
227 }
228 }
229 }
230 return encoding;
231 }
232
233 static void addNonNullObject(SpeculationReasonEncoding encoding, Object o) {
234 Class<? extends Object> c = o.getClass();
235 if (c == String.class) {
236 encoding.addString((String) o);
237 } else if (c == Byte.class) {
238 encoding.addByte((Byte) o);
239 } else if (c == Short.class) {
240 encoding.addShort((Short) o);
241 } else if (c == Character.class) {
242 encoding.addShort((Character) o);
243 } else if (c == Integer.class) {
244 encoding.addInt((Integer) o);
245 } else if (c == Long.class) {
246 encoding.addLong((Long) o);
247 } else if (c == Float.class) {
248 encoding.addInt(Float.floatToRawIntBits((Float) o));
249 } else if (c == Double.class) {
250 encoding.addLong(Double.doubleToRawLongBits((Double) o));
251 } else if (o instanceof Enum) {
252 encoding.addInt(((Enum<?>) o).ordinal());
253 } else if (o instanceof ResolvedJavaMethod) {
254 encoding.addMethod((ResolvedJavaMethod) o);
255 } else if (o instanceof ResolvedJavaType) {
256 encoding.addType((ResolvedJavaType) o);
257 } else if (o instanceof ResolvedJavaField) {
258 encoding.addField((ResolvedJavaField) o);
259 } else if (o instanceof SpeculationContextObject) {
260 SpeculationContextObject sco = (SpeculationContextObject) o;
261 // These are compiler objects which all have the same class
262 // loader so the class name uniquely identifies the class.
263 encoding.addString(o.getClass().getName());
264 sco.accept(new EncodingAdapter(encoding));
265 } else if (o.getClass() == BytecodePosition.class) {
266 BytecodePosition p = (BytecodePosition) o;
267 while (p != null) {
268 encoding.addInt(p.getBCI());
269 encoding.addMethod(p.getMethod());
270 p = p.getCaller();
271 }
272 } else {
273 throw new IllegalArgumentException("Unsupported type for encoding: " + c.getName());
274 }
275 }
276 }
277
278 static class EncodingAdapter implements SpeculationContextObject.Visitor {
279 private final SpeculationReasonEncoding encoding;
280
281 EncodingAdapter(SpeculationReasonEncoding encoding) {
282 this.encoding = encoding;
283 }
284
285 @Override
286 public void visitBoolean(boolean v) {
287 encoding.addByte(v ? 1 : 0);
288 }
289
290 @Override
291 public void visitByte(byte v) {
292 encoding.addByte(v);
293 }
294
295 @Override
296 public void visitChar(char v) {
297 encoding.addShort(v);
298 }
299
300 @Override
301 public void visitShort(short v) {
302 encoding.addInt(v);
303 }
304
305 @Override
306 public void visitInt(int v) {
307 encoding.addInt(v);
308 }
309
310 @Override
311 public void visitLong(long v) {
312 encoding.addLong(v);
313 }
314
315 @Override
316 public void visitFloat(float v) {
317 encoding.addInt(Float.floatToRawIntBits(v));
318 }
319
320 @Override
321 public void visitDouble(double v) {
322 encoding.addLong(Double.doubleToRawLongBits(v));
323 }
324
325 @Override
326 public void visitObject(Object v) {
327 if (v == null) {
328 encoding.addInt(0);
329 } else {
330 DirectSpeculationReason.addNonNullObject(encoding, v);
331 }
332 }
333 }
334
335 static SpeculationReason createSpeculationReason(int groupId, String groupName, Object... context) {
336 return new DirectSpeculationReason(groupId, groupName, context);
337 }
338
339 /**
340 * Gets a unique identifier for this execution such as a process ID or a
341 * {@linkplain #getGlobalTimeStamp() fixed timestamp}.
342 */
343 public static String getExecutionID() {
344 return Long.toString(ProcessHandle.current().pid());
345 }
346
347 private static final AtomicLong globalTimeStamp = new AtomicLong();
348
349 /**
350 * Gets a time stamp for the current process. This method will always return the same value for
351 * the current VM execution.
352 */
|