1 /*
2  * Copyright (c) 2017, 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.  Oracle designates this
8  * particular file as subject to the "Classpath" exception as provided
9  * by Oracle in the LICENSE file that accompanied this code.
10  *
11  * This code is distributed in the hope that it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14  * version 2 for more details (a copy is included in the LICENSE file that
15  * accompanied this code).
16  *
17  * You should have received a copy of the GNU General Public License version
18  * 2 along with this work; if not, write to the Free Software Foundation,
19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20  *
21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22  * or visit www.oracle.com if you need additional information or have any
23  * questions.
24  */
25 
26 package jdk.jfr.internal;
27 
28 import java.util.List;
29 
30 import jdk.internal.HotSpotIntrinsicCandidate;
31 import jdk.jfr.Event;
32 import jdk.jfr.internal.handlers.EventHandler;
33 
34 /**
35  * Interface against the JVM.
36  *
37  */
38 public final class JVM {
39     private static final JVM jvm = new JVM();
40 
41     // JVM signals file changes by doing Object#notify on this object
42     static final Object FILE_DELTA_CHANGE = new Object();
43 
44     static final long RESERVED_CLASS_ID_LIMIT = 500;
45 
46     private volatile boolean nativeOK;
47 
registerNatives()48     private static native void registerNatives();
49 
50     static {
registerNatives()51         registerNatives();
52         for (LogTag tag : LogTag.values()) {
subscribeLogLevel(tag, tag.id)53             subscribeLogLevel(tag, tag.id);
54         }
Options.ensureInitialized()55         Options.ensureInitialized();
56     }
57 
58     /**
59      * Get the one and only JVM.
60      *
61      * @return the JVM
62      */
getJVM()63     public static JVM getJVM() {
64         return jvm;
65     }
66 
JVM()67     private JVM() {
68     }
69 
70     /**
71      * Marks current chunk as final
72      * <p>
73      * This allows streaming clients to read the chunk header and
74      * close the stream when no more data will be written into
75      * the current repository.
76      */
markChunkFinal()77     public native void markChunkFinal();
78 
79     /**
80      * Begin recording events
81      *
82      * Requires that JFR has been started with {@link #createNativeJFR()}
83      */
beginRecording()84     public native void beginRecording();
85 
86     /**
87      * Return true if the JVM is recording
88      */
isRecording()89     public native boolean isRecording();
90 
91     /**
92      * End recording events, which includes flushing data in thread buffers
93      *
94      * Requires that JFR has been started with {@link #createNativeJFR()}
95      *
96      */
endRecording()97     public native void endRecording();
98 
99     /**
100      * Return ticks
101      *
102      * @return the time, in ticks
103      *
104      */
105     @HotSpotIntrinsicCandidate
counterTime()106     public static native long counterTime();
107 
108     /**
109      * Emits native periodic event.
110      *
111      * @param eventTypeId type id
112      *
113      * @param timestamp commit time for event
114      * @param when when it is being done {@link Periodic.When}
115      *
116      * @return true if the event was committed
117      */
emitEvent(long eventTypeId, long timestamp, long when)118     public native boolean emitEvent(long eventTypeId, long timestamp, long when);
119 
120     /**
121      * Return a list of all classes deriving from {@link jdk.internal.event.Event}
122      *
123      * @return list of event classes.
124      */
getAllEventClasses()125     public native List<Class<? extends jdk.internal.event.Event>> getAllEventClasses();
126 
127     /**
128      * Return a count of the number of unloaded classes deriving from {@link Event}
129      *
130      * @return number of unloaded event classes.
131      */
getUnloadedEventClassCount()132     public native long getUnloadedEventClassCount();
133 
134     /**
135      * Return a unique identifier for a class. The class is marked as being
136      * "in use" in JFR.
137      *
138      * @param clazz clazz
139      *
140      * @return a unique class identifier
141      */
142     @HotSpotIntrinsicCandidate
getClassId(Class<?> clazz)143     public static native long getClassId(Class<?> clazz);
144 
145     // temporary workaround until we solve intrinsics supporting epoch shift tagging
getClassIdNonIntrinsic(Class<?> clazz)146     public static native long getClassIdNonIntrinsic(Class<?> clazz);
147 
148     /**
149      * Return process identifier.
150      *
151      * @return process identifier
152      */
getPid()153     public native String getPid();
154 
155     /**
156      * Return unique identifier for stack trace.
157      *
158      * Requires that JFR has been started with {@link #createNativeJFR()}
159      *
160      * @param skipCount number of frames to skip
161      * @return a unique stack trace identifier
162      */
getStackTraceId(int skipCount)163     public native long getStackTraceId(int skipCount);
164 
165     /**
166      * Return identifier for thread
167      *
168      * @param t thread
169      * @return a unique thread identifier
170      */
getThreadId(Thread t)171     public native long getThreadId(Thread t);
172 
173     /**
174      * Frequency, ticks per second
175      *
176      * @return frequency
177      */
getTicksFrequency()178     public native long getTicksFrequency();
179 
180     /**
181      * Write message to log. Should swallow null or empty message, and be able
182      * to handle any Java character and not crash with very large message
183      *
184      * @param tagSetId the tagset id
185      * @param level on level
186      * @param message log message
187      *
188      */
log(int tagSetId, int level, String message)189     public static native void log(int tagSetId, int level, String message);
190 
191     /**
192      * Subscribe to LogLevel updates for LogTag
193      *
194      * @param lt the log tag to subscribe
195      * @param tagSetId the tagset id
196      */
subscribeLogLevel(LogTag lt, int tagSetId)197     public static native void subscribeLogLevel(LogTag lt, int tagSetId);
198 
199     /**
200      * Call to invoke event tagging and retransformation of the passed classes
201      *
202      * @param classes
203      *
204      * @throws IllegalStateException if wrong JVMTI phase.
205      */
retransformClasses(Class<?>[] classes)206     public native synchronized void retransformClasses(Class<?>[] classes);
207 
208     /**
209      * Enable event
210      *
211      * @param eventTypeId event type id
212      *
213      * @param enabled enable event
214      */
setEnabled(long eventTypeId, boolean enabled)215     public native void setEnabled(long eventTypeId, boolean enabled);
216 
217     /**
218      * Interval at which the JVM should notify on {@link #FILE_DELTA_CHANGE}
219      *
220      * @param delta number of bytes, reset after file rotation
221      */
setFileNotification(long delta)222     public native void setFileNotification(long delta);
223 
224     /**
225      * Set the number of global buffers to use
226      *
227      * @param count
228      *
229      * @throws IllegalArgumentException if count is not within a valid range
230      * @throws IllegalStateException if value can't be changed
231      */
setGlobalBufferCount(long count)232     public native void setGlobalBufferCount(long count) throws IllegalArgumentException, IllegalStateException;
233 
234     /**
235      * Set size of a global buffer
236      *
237      * @param size
238      *
239      * @throws IllegalArgumentException if buffer size is not within a valid
240      *         range
241      */
setGlobalBufferSize(long size)242     public native void setGlobalBufferSize(long size) throws IllegalArgumentException;
243 
244     /**
245      * Set overall memory size
246      *
247      * @param size
248      *
249      * @throws IllegalArgumentException if memory size is not within a valid
250      *         range
251      */
setMemorySize(long size)252     public native void setMemorySize(long size) throws IllegalArgumentException;
253 
254     /**
255      * Set interval for method samples, in milliseconds.
256      *
257      * Setting interval to 0 turns off the method sampler.
258      *
259      * @param intervalMillis the sampling interval
260      */
setMethodSamplingInterval(long type, long intervalMillis)261     public native void setMethodSamplingInterval(long type, long intervalMillis);
262 
263     /**
264      * Sets the file where data should be written.
265      *
266      * Requires that JFR has been started with {@link #createNativeJFR()}
267      *
268      * <pre>
269      * Recording  Previous  Current  Action
270      * ==============================================
271      *    true     null      null     Ignore, keep recording in-memory
272      *    true     null      file1    Start disk recording
273      *    true     file      null     Copy out metadata to disk and continue in-memory recording
274      *    true     file1     file2    Copy out metadata and start with new File (file2)
275      *    false     *        null     Ignore, but start recording to memory with {@link #beginRecording()}
276      *    false     *        file     Ignore, but start recording to disk with {@link #beginRecording()}
277      *
278      * </pre>
279      *
280      * recording can be set to true/false with {@link #beginRecording()}
281      * {@link #endRecording()}
282      *
283      * @param file the file where data should be written, or null if it should
284      *        not be copied out (in memory).
285      */
setOutput(String file)286     public native void setOutput(String file);
287 
288     /**
289      * Controls if a class deriving from jdk.jfr.Event should
290      * always be instrumented on class load.
291      *
292      * @param force, true to force initialization, false otherwise
293      */
setForceInstrumentation(boolean force)294     public native void setForceInstrumentation(boolean force);
295 
296     /**
297      * Turn on/off thread sampling.
298      *
299      * @param sampleThreads true if threads should be sampled, false otherwise.
300      *
301      * @throws IllegalStateException if state can't be changed.
302      */
setSampleThreads(boolean sampleThreads)303     public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException;
304 
305     /**
306      * Turn on/off compressed integers.
307      *
308      * @param compressed true if compressed integers should be used, false
309      *        otherwise.
310      *
311      * @throws IllegalStateException if state can't be changed.
312      */
setCompressedIntegers(boolean compressed)313     public native void setCompressedIntegers(boolean compressed) throws IllegalStateException;
314 
315     /**
316      * Set stack depth.
317      *
318      * @param depth
319      *
320      * @throws IllegalArgumentException if not within a valid range
321      * @throws IllegalStateException if depth can't be changed
322      */
setStackDepth(int depth)323     public native void setStackDepth(int depth) throws IllegalArgumentException, IllegalStateException;
324 
325     /**
326      * Turn on stack trace for an event
327      *
328      * @param eventTypeId the event id
329      *
330      * @param enabled if stack traces should be enabled
331      */
setStackTraceEnabled(long eventTypeId, boolean enabled)332     public native void setStackTraceEnabled(long eventTypeId, boolean enabled);
333 
334     /**
335      * Set thread buffer size.
336      *
337      * @param size
338      *
339      * @throws IllegalArgumentException if size is not within a valid range
340      * @throws IllegalStateException if size can't be changed
341      */
setThreadBufferSize(long size)342     public native void setThreadBufferSize(long size) throws IllegalArgumentException, IllegalStateException;
343 
344     /**
345      * Set threshold for event,
346      *
347      * Long.MAXIMUM_VALUE = no limit
348      *
349      * @param eventTypeId the id of the event type
350      * @param ticks threshold in ticks,
351      * @return true, if it could be set
352      */
setThreshold(long eventTypeId, long ticks)353     public native boolean setThreshold(long eventTypeId, long ticks);
354 
355     /**
356      * Store the metadata descriptor that is to be written at the end of a
357      * chunk, data should be written after GMT offset and size of metadata event
358      * should be adjusted
359      *
360      * Requires that JFR has been started with {@link #createNativeJFR()}
361      *
362      * @param bytes binary representation of metadata descriptor
363      */
storeMetadataDescriptor(byte[] bytes)364     public native void storeMetadataDescriptor(byte[] bytes);
365 
366     /**
367      * If the JVM supports JVM TI and retransformation has not been disabled this
368      * method will return true. This flag can not change during the lifetime of
369      * the JVM.
370      *
371      * @return if transform is allowed
372      */
getAllowedToDoEventRetransforms()373     public native boolean getAllowedToDoEventRetransforms();
374 
375     /**
376      * Set up native resources, data structures, threads etc. for JFR
377      *
378      * @param simulateFailure simulate a initialization failure and rollback in
379      *        native, used for testing purposes
380      *
381      * @throws IllegalStateException if native part of JFR could not be created.
382      *
383      */
createJFR(boolean simulateFailure)384     private native boolean createJFR(boolean simulateFailure) throws IllegalStateException;
385 
386     /**
387      * Destroys native part of JFR. If already destroy, call is ignored.
388      *
389      * Requires that JFR has been started with {@link #createNativeJFR()}
390      *
391      * @return if an instance was actually destroyed.
392      *
393      */
destroyJFR()394     private native boolean destroyJFR();
395 
createFailedNativeJFR()396     public boolean createFailedNativeJFR() throws IllegalStateException {
397         return createJFR(true);
398     }
399 
createNativeJFR()400     public void createNativeJFR() {
401         nativeOK = createJFR(false);
402     }
403 
destroyNativeJFR()404     public boolean destroyNativeJFR() {
405         boolean result = destroyJFR();
406         nativeOK = !result;
407         return result;
408     }
409 
hasNativeJFR()410     public boolean hasNativeJFR() {
411         return nativeOK;
412     }
413 
414     /**
415      * Cheap test to check if JFR functionality is available.
416      *
417      * @return
418      */
isAvailable()419     public native boolean isAvailable();
420 
421     /**
422      * To convert ticks to wall clock time.
423      */
getTimeConversionFactor()424     public native double getTimeConversionFactor();
425 
426     /**
427      * Return a unique identifier for a class. Compared to {@link #getClassId(Class)},
428      * this method does not tag the class as being "in-use".
429      *
430      * @param clazz class
431      *
432      * @return a unique class identifier
433      */
getTypeId(Class<?> clazz)434     public native long getTypeId(Class<?> clazz);
435 
436     /**
437      * Fast path fetching the EventWriter using VM intrinsics
438      *
439      * @return thread local EventWriter
440      */
441     @HotSpotIntrinsicCandidate
getEventWriter()442     public static native Object getEventWriter();
443 
444     /**
445      * Create a new EventWriter
446      *
447      * @return thread local EventWriter
448      */
newEventWriter()449     public static native EventWriter newEventWriter();
450 
451     /**
452      * Flushes the EventWriter for this thread.
453      */
flush(EventWriter writer, int uncommittedSize, int requestedSize)454     public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize);
455 
456     /**
457      * Flushes all thread buffers to disk and the constant pool data needed to read
458      * them.
459      * <p>
460      * When the method returns, the chunk header should be updated with valid
461      * pointers to the metadata event, last check point event, correct file size and
462      * the generation id.
463      *
464      */
flush()465     public native void flush();
466 
467     /**
468      * Sets the location of the disk repository, to be used at an emergency
469      * dump.
470      *
471      * @param dirText
472      */
setRepositoryLocation(String dirText)473     public native void setRepositoryLocation(String dirText);
474 
475    /**
476     * Access to VM termination support.
477     *
478     * @param errorMsg descriptive message to be include in VM termination sequence
479     */
abort(String errorMsg)480     public native void abort(String errorMsg);
481 
482     /**
483      * Adds a string to the string constant pool.
484      *
485      * If the same string is added twice, two entries will be created.
486      *
487      * @param id identifier associated with the string, not negative
488      *
489      * @param s string constant to be added, not null
490      *
491      * @return true, if the string was successfully added.
492      */
addStringConstant(long id, String s)493     public static native boolean addStringConstant(long id, String s);
494 
uncaughtException(Thread thread, Throwable t)495     public native void uncaughtException(Thread thread, Throwable t);
496 
497     /**
498      * Sets cutoff for event.
499      *
500      * Determines how long the event should be allowed to run.
501      *
502      * Long.MAXIMUM_VALUE = no limit
503      *
504      * @param eventTypeId the id of the event type
505      * @param cutoffTicks cutoff in ticks,
506      * @return true, if it could be set
507      */
setCutoff(long eventTypeId, long cutoffTicks)508     public native boolean setCutoff(long eventTypeId, long cutoffTicks);
509 
510     /**
511      * Emit old object sample events.
512      *
513      * @param cutoff the cutoff in ticks
514      * @param emitAll emit all samples in old object queue
515      * @param skipBFS don't use BFS when searching for path to GC root
516      */
emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS)517     public native void emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS);
518 
519     /**
520      * Test if a chunk rotation is warranted.
521      *
522      * @return if it is time to perform a chunk rotation
523      */
shouldRotateDisk()524     public native boolean shouldRotateDisk();
525 
526     /**
527      * Exclude a thread from the jfr system
528      *
529      */
exclude(Thread thread)530     public native void exclude(Thread thread);
531 
532     /**
533      * Include a thread back into the jfr system
534      *
535      */
include(Thread thread)536     public native void include(Thread thread);
537 
538     /**
539      * Test if a thread ius currently excluded from the jfr system.
540      *
541      * @return is thread currently excluded
542      */
isExcluded(Thread thread)543     public native boolean isExcluded(Thread thread);
544 
545     /**
546      * Get the start time in nanos from the header of the current chunk
547      *
548      * @return start time of the recording in nanos, -1 in case of in-memory
549      */
getChunkStartNanos()550     public native long getChunkStartNanos();
551 
552     /**
553      * Stores an EventHandler to the eventHandler field of an event class.
554      *
555      * @param eventClass the class, not {@code null}
556      *
557      * @param handler the handler, may be {@code null}
558      *
559      * @return if the field could be set
560      */
setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler)561     public native boolean setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler);
562 
563     /**
564      * Retrieves the EventHandler for an event class.
565      *
566      * @param eventClass the class, not {@code null}
567      *
568      * @return the handler, may be {@code null}
569      */
getHandler(Class<? extends jdk.internal.event.Event> eventClass)570     public native Object getHandler(Class<? extends jdk.internal.event.Event> eventClass);
571 
572     /**
573      * Returns the id for the Java types defined in metadata.xml.
574      *
575      * @param name the name of the type
576      *
577      * @return the id, or a negative value if it does not exists.
578      */
getTypeId(String name)579     public native long getTypeId(String name);
580 }
581