1 /*
2  * Copyright (c) 2017, 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.  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.io.IOException;
29 import java.util.List;
30 
31 import jdk.internal.HotSpotIntrinsicCandidate;
32 import jdk.jfr.Event;
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#notifu on this object
42     static final Object FILE_DELTA_CHANGE = new Object();
43 
44     static final long RESERVED_CLASS_ID_LIMIT = 400;
45 
46     private volatile boolean recording;
47     private volatile boolean nativeOK;
48 
registerNatives()49     private static native void registerNatives();
50 
51     static {
registerNatives()52         registerNatives();
53         for (LogTag tag : LogTag.values()) {
subscribeLogLevel(tag, tag.id)54             subscribeLogLevel(tag, tag.id);
55         }
Options.ensureInitialized()56         Options.ensureInitialized();
57     }
58 
59     /**
60      * Get the one and only JVM.
61      *
62      * @return the JVM
63      */
getJVM()64     public static JVM getJVM() {
65         return jvm;
66     }
67 
JVM()68     private JVM() {
69     }
70 
71     /**
72      * Begin recording events
73      *
74      * Requires that JFR has been started with {@link #createNativeJFR()}
75      */
beginRecording()76     public native void beginRecording();
77 
78     /**
79      * Return ticks
80      *
81      * @return the time, in ticks
82      *
83      */
84     @HotSpotIntrinsicCandidate
counterTime()85     public static native long counterTime();
86 
87 
88     /**
89      * Emits native periodic event.
90      *
91      * @param eventTypeId type id
92      *
93      * @param timestamp commit time for event
94      * @param when when it is being done {@link Periodic.When}
95      *
96      * @return true if the event was committed
97      */
emitEvent(long eventTypeId, long timestamp, long when)98     public native boolean emitEvent(long eventTypeId, long timestamp, long when);
99 
100     /**
101      * End recording events, which includes flushing data in thread buffers
102      *
103      * Requires that JFR has been started with {@link #createNativeJFR()}
104      *
105      */
endRecording()106     public native void endRecording();
107 
108     /**
109      * Return a list of all classes deriving from {@link jdk.internal.event.Event}
110      *
111      * @return list of event classes.
112      */
getAllEventClasses()113     public native List<Class<? extends jdk.internal.event.Event>> getAllEventClasses();
114 
115     /**
116      * Return a count of the number of unloaded classes deriving from {@link Event}
117      *
118      * @return number of unloaded event classes.
119      */
getUnloadedEventClassCount()120     public native long getUnloadedEventClassCount();
121 
122     /**
123      * Return a unique identifier for a class. The class is marked as being
124      * "in use" in JFR.
125      *
126      * @param clazz clazz
127      *
128      * @return a unique class identifier
129      */
130    @HotSpotIntrinsicCandidate
getClassId(Class<?> clazz)131     public static native long getClassId(Class<?> clazz);
132 
133     // temporary workaround until we solve intrinsics supporting epoch shift tagging
getClassIdNonIntrinsic(Class<?> clazz)134     public static native long getClassIdNonIntrinsic(Class<?> clazz);
135 
136     /**
137      * Return process identifier.
138      *
139      * @return process identifier
140      */
getPid()141     public native String getPid();
142 
143     /**
144      * Return unique identifier for stack trace.
145      *
146      * Requires that JFR has been started with {@link #createNativeJFR()}
147      *
148      * @param skipCount number of frames to skip
149      * @return a unique stack trace identifier
150      */
getStackTraceId(int skipCount)151     public native long getStackTraceId(int skipCount);
152 
153     /**
154      * Return identifier for thread
155      *
156      * @param t thread
157      * @return a unique thread identifier
158      */
getThreadId(Thread t)159     public native long getThreadId(Thread t);
160 
161     /**
162      * Frequency, ticks per second
163      *
164      * @return frequency
165      */
getTicksFrequency()166     public native long getTicksFrequency();
167 
168     /**
169      * Write message to log. Should swallow null or empty message, and be able
170      * to handle any Java character and not crash with very large message
171      *
172      * @param tagSetId the tagset id
173      * @param level on level
174      * @param message log message
175      *
176      */
log(int tagSetId, int level, String message)177     public static native void log(int tagSetId, int level, String message);
178 
179     /**
180      * Subscribe to LogLevel updates for LogTag
181      *
182      * @param lt the log tag to subscribe
183      * @param tagSetId the tagset id
184      */
subscribeLogLevel(LogTag lt, int tagSetId)185     public static native void subscribeLogLevel(LogTag lt, int tagSetId);
186 
187     /**
188      * Call to invoke event tagging and retransformation of the passed classes
189      *
190      * @param classes
191      */
retransformClasses(Class<?>[] classes)192     public native synchronized void retransformClasses(Class<?>[] classes);
193 
194     /**
195      * Enable event
196      *
197      * @param eventTypeId event type id
198      *
199      * @param enabled enable event
200      */
setEnabled(long eventTypeId, boolean enabled)201     public native void setEnabled(long eventTypeId, boolean enabled);
202 
203     /**
204      * Interval at which the JVM should notify on {@link #FILE_DELTA_CHANGE}
205      *
206      * @param delta number of bytes, reset after file rotation
207      */
setFileNotification(long delta)208     public native void setFileNotification(long delta);
209 
210     /**
211      * Set the number of global buffers to use
212      *
213      * @param count
214      *
215      * @throws IllegalArgumentException if count is not within a valid range
216      * @throws IllegalStateException if value can't be changed
217      */
setGlobalBufferCount(long count)218     public native void setGlobalBufferCount(long count) throws IllegalArgumentException, IllegalStateException;
219 
220     /**
221      * Set size of a global buffer
222      *
223      * @param size
224      *
225      * @throws IllegalArgumentException if buffer size is not within a valid
226      *         range
227      */
setGlobalBufferSize(long size)228     public native void setGlobalBufferSize(long size) throws IllegalArgumentException;
229 
230     /**
231      * Set overall memory size
232      *
233      * @param size
234      *
235      * @throws IllegalArgumentException if memory size is not within a valid
236      *         range
237      */
setMemorySize(long size)238     public native void setMemorySize(long size) throws IllegalArgumentException;
239 
240     /**
241 
242     /**
243      * Set interval for method samples, in milliseconds.
244      *
245      * Setting interval to 0 turns off the method sampler.
246      *
247      * @param intervalMillis the sampling interval
248      */
setMethodSamplingInterval(long type, long intervalMillis)249     public native void setMethodSamplingInterval(long type, long intervalMillis);
250 
251       /**
252      * Sets the file where data should be written.
253      *
254      * Requires that JFR has been started with {@link #createNativeJFR()}
255      *
256      * <pre>
257      * Recording  Previous  Current  Action
258      * ==============================================
259      *    true     null      null     Ignore, keep recording in-memory
260      *    true     null      file1    Start disk recording
261      *    true     file      null     Copy out metadata to disk and continue in-memory recording
262      *    true     file1     file2    Copy out metadata and start with new File (file2)
263      *    false     *        null     Ignore, but start recording to memory with {@link #beginRecording()}
264      *    false     *        file     Ignore, but start recording to disk with {@link #beginRecording()}
265      *
266      * </pre>
267      *
268      * recording can be set to true/false with {@link #beginRecording()}
269      * {@link #endRecording()}
270      *
271      * @param file the file where data should be written, or null if it should
272      *        not be copied out (in memory).
273      *
274      * @throws IOException
275      */
setOutput(String file)276     public native void setOutput(String file);
277 
278     /**
279      * Controls if a class deriving from jdk.jfr.Event should
280      * always be instrumented on class load.
281      *
282      * @param force, true to force initialization, false otherwise
283      */
setForceInstrumentation(boolean force)284     public native void setForceInstrumentation(boolean force);
285 
286     /**
287      * Turn on/off thread sampling.
288      *
289      * @param sampleThreads true if threads should be sampled, false otherwise.
290      *
291      * @throws IllegalStateException if state can't be changed.
292      */
setSampleThreads(boolean sampleThreads)293     public native void setSampleThreads(boolean sampleThreads) throws IllegalStateException;
294 
295     /**
296      * Turn on/off compressed integers.
297      *
298      * @param compressed true if compressed integers should be used, false
299      *        otherwise.
300      *
301      * @throws IllegalStateException if state can't be changed.
302      */
setCompressedIntegers(boolean compressed)303     public native void setCompressedIntegers(boolean compressed) throws IllegalStateException;
304 
305     /**
306      * Set stack depth.
307      *
308      * @param depth
309      *
310      * @throws IllegalArgumentException if not within a valid range
311      * @throws IllegalStateException if depth can't be changed
312      */
setStackDepth(int depth)313     public native void setStackDepth(int depth) throws IllegalArgumentException, IllegalStateException;
314 
315     /**
316      * Turn on stack trace for an event
317      *
318      * @param eventTypeId the event id
319      *
320      * @param enabled if stack traces should be enabled
321      */
setStackTraceEnabled(long eventTypeId, boolean enabled)322     public native void setStackTraceEnabled(long eventTypeId, boolean enabled);
323 
324     /**
325      * Set thread buffer size.
326      *
327      * @param size
328      *
329      * @throws IllegalArgumentException if size is not within a valid range
330      * @throws IllegalStateException if size can't be changed
331      */
setThreadBufferSize(long size)332     public native void setThreadBufferSize(long size) throws IllegalArgumentException, IllegalStateException;
333 
334     /**
335      * Set threshold for event,
336      *
337      * Long.MAXIMUM_VALUE = no limit
338      *
339      * @param eventTypeId the id of the event type
340      * @param ticks threshold in ticks,
341      * @return true, if it could be set
342      */
setThreshold(long eventTypeId, long ticks)343     public native boolean setThreshold(long eventTypeId, long ticks);
344 
345     /**
346      * Store the metadata descriptor that is to be written at the end of a
347      * chunk, data should be written after GMT offset and size of metadata event
348      * should be adjusted
349      *
350      * Requires that JFR has been started with {@link #createNativeJFR()}
351      *
352      * @param bytes binary representation of metadata descriptor
353      *
354      * @param binary representation of descriptor
355      */
storeMetadataDescriptor(byte[] bytes)356     public native void storeMetadataDescriptor(byte[] bytes);
357 
endRecording_()358     public void endRecording_() {
359         endRecording();
360         recording = false;
361     }
362 
beginRecording_()363     public void beginRecording_() {
364         beginRecording();
365         recording = true;
366     }
367 
isRecording()368     public boolean isRecording() {
369         return recording;
370     }
371 
372     /**
373      * If the JVM supports JVM TI and retransformation has not been disabled this
374      * method will return true. This flag can not change during the lifetime of
375      * the JVM.
376      *
377      * @return if transform is allowed
378      */
getAllowedToDoEventRetransforms()379     public native boolean getAllowedToDoEventRetransforms();
380 
381     /**
382      * Set up native resources, data structures, threads etc. for JFR
383      *
384      * @param simulateFailure simulate a initialization failure and rollback in
385      *        native, used for testing purposes
386      *
387      * @throws IllegalStateException if native part of JFR could not be created.
388      *
389      */
createJFR(boolean simulateFailure)390     private native boolean createJFR(boolean simulateFailure) throws IllegalStateException;
391 
392     /**
393      * Destroys native part of JFR. If already destroy, call is ignored.
394      *
395      * Requires that JFR has been started with {@link #createNativeJFR()}
396      *
397      * @return if an instance was actually destroyed.
398      *
399      */
destroyJFR()400     private native boolean destroyJFR();
401 
createFailedNativeJFR()402     public boolean createFailedNativeJFR() throws IllegalStateException {
403         return createJFR(true);
404     }
405 
createNativeJFR()406     public void createNativeJFR() {
407         nativeOK = createJFR(false);
408     }
409 
destroyNativeJFR()410     public boolean destroyNativeJFR() {
411         boolean result = destroyJFR();
412         nativeOK = !result;
413         return result;
414     }
415 
hasNativeJFR()416     public boolean hasNativeJFR() {
417         return nativeOK;
418     }
419 
420     /**
421      * Cheap test to check if JFR functionality is available.
422      *
423      * @return
424      */
isAvailable()425     public native boolean isAvailable();
426 
427     /**
428      * To convert ticks to wall clock time.
429      */
getTimeConversionFactor()430     public native double getTimeConversionFactor();
431 
432     /**
433      * Return a unique identifier for a class. Compared to {@link #getClassId()}
434      * , this method does not tag the class as being "in-use".
435      *
436      * @param clazz class
437      *
438      * @return a unique class identifier
439      */
getTypeId(Class<?> clazz)440     public native long getTypeId(Class<?> clazz);
441 
442     /**
443      * Fast path fetching the EventWriter using VM intrinsics
444      *
445      * @return thread local EventWriter
446      */
447     @HotSpotIntrinsicCandidate
getEventWriter()448     public static native Object getEventWriter();
449 
450     /**
451      * Create a new EventWriter
452      *
453      * @return thread local EventWriter
454      */
newEventWriter()455     public static native EventWriter newEventWriter();
456 
457     /**
458      * Flushes the EventWriter for this thread.
459      */
flush(EventWriter writer, int uncommittedSize, int requestedSize)460     public static native boolean flush(EventWriter writer, int uncommittedSize, int requestedSize);
461 
462     /**
463      * Sets the location of the disk repository, to be used at an emergency
464      * dump.
465      *
466      * @param dirText
467      */
setRepositoryLocation(String dirText)468     public native void setRepositoryLocation(String dirText);
469 
470     /**
471     * Access to VM termination support.
472     *
473     *@param errorMsg descriptive message to be include in VM termination sequence
474     */
abort(String errorMsg)475     public native void abort(String errorMsg);
476 
477     /**
478      * Adds a string to the string constant pool.
479      *
480      * If the same string is added twice, two entries will be created.
481      *
482      * @param id identifier associated with the string, not negative
483      *
484      * @param s string constant to be added, not null
485      *
486      * @return the current epoch of this insertion attempt
487      */
addStringConstant(boolean epoch, long id, String s)488     public static native boolean addStringConstant(boolean epoch, long id, String s);
489     /**
490      * Gets the address of the jboolean epoch.
491      *
492      * The epoch alternates every checkpoint.
493      *
494      * @return The address of the jboolean.
495      */
getEpochAddress()496     public native long getEpochAddress();
497 
uncaughtException(Thread thread, Throwable t)498     public native void uncaughtException(Thread thread, Throwable t);
499     /**
500      * Sets cutoff for event.
501      *
502      * Determines how long the event should be allowed to run.
503      *
504      * Long.MAXIMUM_VALUE = no limit
505      *
506      * @param eventTypeId the id of the event type
507      * @param cutoffTicks cutoff in ticks,
508      * @return true, if it could be set
509      */
setCutoff(long eventTypeId, long cutoffTicks)510     public native boolean setCutoff(long eventTypeId, long cutoffTicks);
511 
512     /**
513      * Emit old object sample events.
514      *
515      * @param cutoff the cutoff in ticks
516      * @param emitAll emit all samples in old object queue
517      */
emitOldObjectSamples(long cutoff, boolean emitAll)518     public native void emitOldObjectSamples(long cutoff, boolean emitAll);
519 
520     /**
521      * Test if a chunk rotation is warranted.
522      *
523      * @return if it is time to perform a chunk rotation
524      */
shouldRotateDisk()525     public native boolean shouldRotateDisk();
526 }
527