1 /*
2  * Copyright (c) 2017, 2021, 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.vm.annotation.IntrinsicCandidate;
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     @IntrinsicCandidate
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     @IntrinsicCandidate
getClassId(Class<?> clazz)143     public static native long getClassId(Class<?> clazz);
144 
145     /**
146      * Return process identifier.
147      *
148      * @return process identifier
149      */
getPid()150     public native String getPid();
151 
152     /**
153      * Return unique identifier for stack trace.
154      *
155      * Requires that JFR has been started with {@link #createNativeJFR()}
156      *
157      * @param skipCount number of frames to skip
158      * @return a unique stack trace identifier
159      */
getStackTraceId(int skipCount)160     public native long getStackTraceId(int skipCount);
161 
162     /**
163      * Return identifier for thread
164      *
165      * @param t thread
166      * @return a unique thread identifier
167      */
getThreadId(Thread t)168     public native long getThreadId(Thread t);
169 
170     /**
171      * Frequency, ticks per second
172      *
173      * @return frequency
174      */
getTicksFrequency()175     public native long getTicksFrequency();
176 
177     /**
178      * Write message to log. Should swallow null or empty message, and be able
179      * to handle any Java character and not crash with very large message
180      *
181      * @param tagSetId the tagset id
182      * @param level on level
183      * @param message log message
184      *
185      */
log(int tagSetId, int level, String message)186     public static native void log(int tagSetId, int level, String message);
187 
188     /**
189      * Log an event to jfr+event or jfr+event+system.
190      * <p>
191      * Caller should ensure that message is not null or too large to handle.
192      *
193      * @param level log level
194      * @param lines lines to log
195      * @param system if lines should be written to jfr+event+system
196      */
logEvent(int level, String[] lines, boolean system)197     public static native void logEvent(int level, String[] lines, boolean system);
198 
199     /**
200      * Subscribe to LogLevel updates for LogTag
201      *
202      * @param lt the log tag to subscribe
203      * @param tagSetId the tagset id
204      */
subscribeLogLevel(LogTag lt, int tagSetId)205     public static native void subscribeLogLevel(LogTag lt, int tagSetId);
206 
207     /**
208      * Call to invoke event tagging and retransformation of the passed classes
209      *
210      * @param classes
211      *
212      * @throws IllegalStateException if wrong JVMTI phase.
213      */
retransformClasses(Class<?>[] classes)214     public native synchronized void retransformClasses(Class<?>[] classes);
215 
216     /**
217      * Enable event
218      *
219      * @param eventTypeId event type id
220      *
221      * @param enabled enable event
222      */
setEnabled(long eventTypeId, boolean enabled)223     public native void setEnabled(long eventTypeId, boolean enabled);
224 
225     /**
226      * Interval at which the JVM should notify on {@link #FILE_DELTA_CHANGE}
227      *
228      * @param delta number of bytes, reset after file rotation
229      */
setFileNotification(long delta)230     public native void setFileNotification(long delta);
231 
232     /**
233      * Set the number of global buffers to use
234      *
235      * @param count
236      *
237      * @throws IllegalArgumentException if count is not within a valid range
238      * @throws IllegalStateException if value can't be changed
239      */
setGlobalBufferCount(long count)240     public native void setGlobalBufferCount(long count) throws IllegalArgumentException, IllegalStateException;
241 
242     /**
243      * Set size of a global buffer
244      *
245      * @param size
246      *
247      * @throws IllegalArgumentException if buffer size is not within a valid
248      *         range
249      */
setGlobalBufferSize(long size)250     public native void setGlobalBufferSize(long size) throws IllegalArgumentException;
251 
252     /**
253      * Set overall memory size
254      *
255      * @param size
256      *
257      * @throws IllegalArgumentException if memory size is not within a valid
258      *         range
259      */
setMemorySize(long size)260     public native void setMemorySize(long size) throws IllegalArgumentException;
261 
262     /**
263      * Set interval for method samples, in milliseconds.
264      *
265      * Setting interval to 0 turns off the method sampler.
266      *
267      * @param intervalMillis the sampling interval
268      */
setMethodSamplingInterval(long type, long intervalMillis)269     public native void setMethodSamplingInterval(long type, long intervalMillis);
270 
271     /**
272      * Sets the file where data should be written.
273      *
274      * Requires that JFR has been started with {@link #createNativeJFR()}
275      *
276      * <pre>
277      * Recording  Previous  Current  Action
278      * ==============================================
279      *    true     null      null     Ignore, keep recording in-memory
280      *    true     null      file1    Start disk recording
281      *    true     file      null     Copy out metadata to disk and continue in-memory recording
282      *    true     file1     file2    Copy out metadata and start with new File (file2)
283      *    false     *        null     Ignore, but start recording to memory with {@link #beginRecording()}
284      *    false     *        file     Ignore, but start recording to disk with {@link #beginRecording()}
285      *
286      * </pre>
287      *
288      * recording can be set to true/false with {@link #beginRecording()}
289      * {@link #endRecording()}
290      *
291      * @param file the file where data should be written, or null if it should
292      *        not be copied out (in memory).
293      */
setOutput(String file)294     public native void setOutput(String file);
295 
296     /**
297      * Controls if a class deriving from jdk.jfr.Event should
298      * always be instrumented on class load.
299      *
300      * @param force, true to force initialization, false otherwise
301      */
setForceInstrumentation(boolean force)302     public native void setForceInstrumentation(boolean force);
303 
304     /**
305      * Turn on/off thread sampling.
306      *
307      * @param sampleThreads true if threads should be sampled, false otherwise.
308      *
309      * @throws IllegalStateException if state can't be changed.
310      */
setSampleThreads(boolean sampleThreads)311     public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException;
312 
313     /**
314      * Turn on/off compressed integers.
315      *
316      * @param compressed true if compressed integers should be used, false
317      *        otherwise.
318      *
319      * @throws IllegalStateException if state can't be changed.
320      */
setCompressedIntegers(boolean compressed)321     public native void setCompressedIntegers(boolean compressed) throws IllegalStateException;
322 
323     /**
324      * Set stack depth.
325      *
326      * @param depth
327      *
328      * @throws IllegalArgumentException if not within a valid range
329      * @throws IllegalStateException if depth can't be changed
330      */
setStackDepth(int depth)331     public native void setStackDepth(int depth) throws IllegalArgumentException, IllegalStateException;
332 
333     /**
334      * Turn on stack trace for an event
335      *
336      * @param eventTypeId the event id
337      *
338      * @param enabled if stack traces should be enabled
339      */
setStackTraceEnabled(long eventTypeId, boolean enabled)340     public native void setStackTraceEnabled(long eventTypeId, boolean enabled);
341 
342     /**
343      * Set thread buffer size.
344      *
345      * @param size
346      *
347      * @throws IllegalArgumentException if size is not within a valid range
348      * @throws IllegalStateException if size can't be changed
349      */
setThreadBufferSize(long size)350     public native void setThreadBufferSize(long size) throws IllegalArgumentException, IllegalStateException;
351 
352     /**
353      * Set threshold for event,
354      *
355      * Long.MAXIMUM_VALUE = no limit
356      *
357      * @param eventTypeId the id of the event type
358      * @param ticks threshold in ticks,
359      * @return true, if it could be set
360      */
setThreshold(long eventTypeId, long ticks)361     public native boolean setThreshold(long eventTypeId, long ticks);
362 
363     /**
364      * Store the metadata descriptor that is to be written at the end of a
365      * chunk, data should be written after GMT offset and size of metadata event
366      * should be adjusted
367      *
368      * Requires that JFR has been started with {@link #createNativeJFR()}
369      *
370      * @param bytes binary representation of metadata descriptor
371      */
storeMetadataDescriptor(byte[] bytes)372     public native void storeMetadataDescriptor(byte[] bytes);
373 
374     /**
375      * If the JVM supports JVM TI and retransformation has not been disabled this
376      * method will return true. This flag can not change during the lifetime of
377      * the JVM.
378      *
379      * @return if transform is allowed
380      */
getAllowedToDoEventRetransforms()381     public native boolean getAllowedToDoEventRetransforms();
382 
383     /**
384      * Set up native resources, data structures, threads etc. for JFR
385      *
386      * @param simulateFailure simulate a initialization failure and rollback in
387      *        native, used for testing purposes
388      *
389      * @throws IllegalStateException if native part of JFR could not be created.
390      *
391      */
createJFR(boolean simulateFailure)392     private native boolean createJFR(boolean simulateFailure) throws IllegalStateException;
393 
394     /**
395      * Destroys native part of JFR. If already destroy, call is ignored.
396      *
397      * Requires that JFR has been started with {@link #createNativeJFR()}
398      *
399      * @return if an instance was actually destroyed.
400      *
401      */
destroyJFR()402     private native boolean destroyJFR();
403 
createFailedNativeJFR()404     public boolean createFailedNativeJFR() throws IllegalStateException {
405         return createJFR(true);
406     }
407 
createNativeJFR()408     public void createNativeJFR() {
409         nativeOK = createJFR(false);
410     }
411 
destroyNativeJFR()412     public boolean destroyNativeJFR() {
413         boolean result = destroyJFR();
414         nativeOK = !result;
415         return result;
416     }
417 
hasNativeJFR()418     public boolean hasNativeJFR() {
419         return nativeOK;
420     }
421 
422     /**
423      * Cheap test to check if JFR functionality is available.
424      *
425      * @return
426      */
isAvailable()427     public native boolean isAvailable();
428 
429     /**
430      * To convert ticks to wall clock time.
431      */
getTimeConversionFactor()432     public native double getTimeConversionFactor();
433 
434     /**
435      * Return a unique identifier for a class. Compared to {@link #getClassId(Class)},
436      * this method does not tag the class as being "in-use".
437      *
438      * @param clazz class
439      *
440      * @return a unique class identifier
441      */
getTypeId(Class<?> clazz)442     public native long getTypeId(Class<?> clazz);
443 
444     /**
445      * Fast path fetching the EventWriter using VM intrinsics
446      *
447      * @return thread local EventWriter
448      */
449     @IntrinsicCandidate
getEventWriter()450     public static native Object getEventWriter();
451 
452     /**
453      * Create a new EventWriter
454      *
455      * @return thread local EventWriter
456      */
newEventWriter()457     public static native EventWriter newEventWriter();
458 
459     /**
460      * Flushes the EventWriter for this thread.
461      */
flush(EventWriter writer, int uncommittedSize, int requestedSize)462     public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize);
463 
464     /**
465      * Flushes all thread buffers to disk and the constant pool data needed to read
466      * them.
467      * <p>
468      * When the method returns, the chunk header should be updated with valid
469      * pointers to the metadata event, last check point event, correct file size and
470      * the generation id.
471      *
472      */
flush()473     public native void flush();
474 
475     /**
476      * Sets the location of the disk repository, to be used at an emergency
477      * dump.
478      *
479      * @param dirText
480      */
setRepositoryLocation(String dirText)481     public native void setRepositoryLocation(String dirText);
482 
483    /**
484     * Access to VM termination support.
485     *
486     * @param errorMsg descriptive message to be include in VM termination sequence
487     */
abort(String errorMsg)488     public native void abort(String errorMsg);
489 
490     /**
491      * Adds a string to the string constant pool.
492      *
493      * If the same string is added twice, two entries will be created.
494      *
495      * @param id identifier associated with the string, not negative
496      *
497      * @param s string constant to be added, not null
498      *
499      * @return true, if the string was successfully added.
500      */
addStringConstant(long id, String s)501     public static native boolean addStringConstant(long id, String s);
502 
uncaughtException(Thread thread, Throwable t)503     public native void uncaughtException(Thread thread, Throwable t);
504 
505     /**
506      * Sets cutoff for event.
507      *
508      * Determines how long the event should be allowed to run.
509      *
510      * Long.MAXIMUM_VALUE = no limit
511      *
512      * @param eventTypeId the id of the event type
513      * @param cutoffTicks cutoff in ticks,
514      * @return true, if it could be set
515      */
setCutoff(long eventTypeId, long cutoffTicks)516     public native boolean setCutoff(long eventTypeId, long cutoffTicks);
517 
518     /**
519      * Sets the event emission rate in event sample size per time unit.
520      *
521      * Determines how events are throttled.
522      *
523      * @param eventTypeId the id of the event type
524      * @param eventSampleSize event sample size
525      * @param period_ms time period in milliseconds
526      * @return true, if it could be set
527      */
setThrottle(long eventTypeId, long eventSampleSize, long period_ms)528     public native boolean setThrottle(long eventTypeId, long eventSampleSize, long period_ms);
529 
530     /**
531      * Emit old object sample events.
532      *
533      * @param cutoff the cutoff in ticks
534      * @param emitAll emit all samples in old object queue
535      * @param skipBFS don't use BFS when searching for path to GC root
536      */
emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS)537     public native void emitOldObjectSamples(long cutoff, boolean emitAll, boolean skipBFS);
538 
539     /**
540      * Test if a chunk rotation is warranted.
541      *
542      * @return if it is time to perform a chunk rotation
543      */
shouldRotateDisk()544     public native boolean shouldRotateDisk();
545 
546     /**
547      * Exclude a thread from the jfr system
548      *
549      */
exclude(Thread thread)550     public native void exclude(Thread thread);
551 
552     /**
553      * Include a thread back into the jfr system
554      *
555      */
include(Thread thread)556     public native void include(Thread thread);
557 
558     /**
559      * Test if a thread ius currently excluded from the jfr system.
560      *
561      * @return is thread currently excluded
562      */
isExcluded(Thread thread)563     public native boolean isExcluded(Thread thread);
564 
565     /**
566      * Get the start time in nanos from the header of the current chunk
567      *
568      * @return start time of the recording in nanos, -1 in case of in-memory
569      */
getChunkStartNanos()570     public native long getChunkStartNanos();
571 
572     /**
573      * Stores an EventHandler to the eventHandler field of an event class.
574      *
575      * @param eventClass the class, not {@code null}
576      *
577      * @param handler the handler, may be {@code null}
578      *
579      * @return if the field could be set
580      */
setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler)581     public native boolean setHandler(Class<? extends jdk.internal.event.Event> eventClass, EventHandler handler);
582 
583     /**
584      * Retrieves the EventHandler for an event class.
585      *
586      * @param eventClass the class, not {@code null}
587      *
588      * @return the handler, may be {@code null}
589      */
getHandler(Class<? extends jdk.internal.event.Event> eventClass)590     public native Object getHandler(Class<? extends jdk.internal.event.Event> eventClass);
591 
592     /**
593      * Returns the id for the Java types defined in metadata.xml.
594      *
595      * @param name the name of the type
596      *
597      * @return the id, or a negative value if it does not exists.
598      */
getTypeId(String name)599     public native long getTypeId(String name);
600 }
601