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