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