1 /*
   2  * Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2018, Google and/or its affiliates. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  */
  24 
  25 #include <assert.h>
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include "jvmti.h"
  30 
  31 extern "C" {
  32 
  33 #define TRUE 1
  34 #define FALSE 0
  35 #define PRINT_OUT 0
  36 
  37 static jvmtiEnv *jvmti = nullptr;
  38 static jvmtiEnv *second_jvmti = nullptr;
  39 
  40 typedef struct _ObjectTrace{
  41   jweak object;
  42   jlong size;
  43   jvmtiFrameInfo* frames;
  44   size_t frame_count;
  45   jthread thread;
  46 } ObjectTrace;
  47 
  48 typedef struct _EventStorage {
  49   int live_object_additions;
  50   int live_object_size;
  51   int live_object_count;
  52   ObjectTrace** live_objects;
  53 
  54   int garbage_history_size;
  55   int garbage_history_index;
  56   ObjectTrace** garbage_collected_objects;
  57 
  58   // Two separate monitors to separate storage data race and the compaction field
  59   // data race.
  60   jrawMonitorID storage_monitor;
  61 
  62   int compaction_required;
  63   jrawMonitorID compaction_monitor;
  64 } EventStorage;
  65 
  66 typedef struct _ExpectedContentFrame {
  67   const char *name;
  68   const char *signature;
  69   const char *file_name;
  70   int line_number;
  71 } ExpectedContentFrame;
  72 
  73 static
  74 void event_storage_lock(EventStorage* storage) {
  75   jvmti->RawMonitorEnter(storage->storage_monitor);
  76 }
  77 
  78 static
  79 void event_storage_unlock(EventStorage* storage) {
  80   jvmti->RawMonitorExit(storage->storage_monitor);
  81 }
  82 
  83 static
  84 void event_storage_lock_compaction(EventStorage* storage) {
  85   jvmti->RawMonitorEnter(storage->compaction_monitor);
  86 }
  87 
  88 static
  89 void event_storage_unlock_compaction(EventStorage* storage) {
  90   jvmti->RawMonitorExit(storage->compaction_monitor);
  91 }
  92 
  93 // Given a method and a location, this method gets the line number.
  94 static
  95 jint get_line_number(jmethodID method, jlocation location) {
  96   // Read the line number table.
  97   jvmtiLineNumberEntry *table_ptr = 0;
  98   jint line_number_table_entries;
  99   int l;
 100   jlocation last_location;
 101   int jvmti_error = jvmti->GetLineNumberTable(method,
 102                                               &line_number_table_entries,
 103                                               &table_ptr);
 104 
 105   if (JVMTI_ERROR_NONE != jvmti_error) {
 106     return -1;
 107   }
 108   if (line_number_table_entries <= 0) {
 109     return -1;
 110   }
 111   if (line_number_table_entries == 1) {
 112     return table_ptr[0].line_number;
 113   }
 114 
 115   // Go through all the line numbers...
 116   last_location = table_ptr[0].start_location;
 117   for (l = 1; l < line_number_table_entries; l++) {
 118     // ... and if you see one that is in the right place for your
 119     // location, you've found the line number!
 120     if ((location < table_ptr[l].start_location) &&
 121         (location >= last_location)) {
 122       return table_ptr[l - 1].line_number;
 123     }
 124     last_location = table_ptr[l].start_location;
 125   }
 126 
 127   if (location >= last_location) {
 128     return table_ptr[line_number_table_entries - 1].line_number;
 129   } else {
 130     return -1;
 131   }
 132 }
 133 
 134 static void print_out_frames(JNIEnv* env, ObjectTrace* trace) {
 135   jvmtiFrameInfo* frames = trace->frames;
 136   size_t i;
 137   for (i = 0; i < trace->frame_count; i++) {
 138     // Get basic information out of the trace.
 139     jlocation bci = frames[i].location;
 140     jmethodID methodid = frames[i].method;
 141     char *name = nullptr, *signature = nullptr, *file_name = nullptr;
 142     jclass declaring_class;
 143     int line_number;
 144     jvmtiError err;
 145 
 146     if (bci < 0) {
 147       fprintf(stderr, "\tNative frame\n");
 148       continue;
 149     }
 150 
 151     // Transform into usable information.
 152     line_number = get_line_number(methodid, bci);
 153     if (JVMTI_ERROR_NONE != jvmti->GetMethodName(methodid, &name, &signature, 0)) {
 154       fprintf(stderr, "\tUnknown method name\n");
 155       continue;
 156     }
 157 
 158     if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {
 159       fprintf(stderr, "\tUnknown class\n");
 160       continue;
 161     }
 162 
 163     err = jvmti->GetSourceFileName(declaring_class, &file_name);
 164     if (err != JVMTI_ERROR_NONE) {
 165       fprintf(stderr, "\tUnknown file\n");
 166       continue;
 167     }
 168 
 169     // Compare now, none should be null.
 170     if (name == nullptr) {
 171       fprintf(stderr, "\tUnknown name\n");
 172       continue;
 173     }
 174 
 175     if (file_name == nullptr) {
 176       fprintf(stderr, "\tUnknown file\n");
 177       continue;
 178     }
 179 
 180     if (signature == nullptr) {
 181       fprintf(stderr, "\tUnknown signature\n");
 182       continue;
 183     }
 184 
 185     fprintf(stderr, "\t%s%s (%s: %d)\n", name, signature, file_name, line_number);
 186   }
 187 }
 188 
 189 static jboolean check_sample_content(JNIEnv* env,
 190                                      ObjectTrace* trace,
 191                                      ExpectedContentFrame *expected,
 192                                      size_t expected_count,
 193                                      int print_out_comparisons) {
 194   jvmtiFrameInfo* frames;
 195   size_t i;
 196 
 197   if (expected_count > trace->frame_count) {
 198     return FALSE;
 199   }
 200 
 201   frames = trace->frames;
 202   for (i = 0; i < expected_count; i++) {
 203     // Get basic information out of the trace.
 204     jlocation bci = frames[i].location;
 205     jmethodID methodid = frames[i].method;
 206     char *name = nullptr, *signature = nullptr, *file_name = nullptr;
 207     jclass declaring_class;
 208     int line_number;
 209     jboolean differ;
 210     jvmtiError err;
 211 
 212     if (bci < 0 && expected[i].line_number != -1) {
 213       return FALSE;
 214     }
 215 
 216     // Transform into usable information.
 217     line_number = get_line_number(methodid, bci);
 218     jvmti->GetMethodName(methodid, &name, &signature, 0);
 219 
 220     if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {
 221       return FALSE;
 222     }
 223 
 224     err = jvmti->GetSourceFileName(declaring_class, &file_name);
 225     if (err != JVMTI_ERROR_NONE) {
 226       return FALSE;
 227     }
 228 
 229     // Compare now, none should be null.
 230     if (name == nullptr) {
 231       return FALSE;
 232     }
 233 
 234     if (file_name == nullptr) {
 235       return FALSE;
 236     }
 237 
 238     if (signature == nullptr) {
 239       return FALSE;
 240     }
 241 
 242     differ = (strcmp(name, expected[i].name) ||
 243               strcmp(signature, expected[i].signature) ||
 244               strcmp(file_name, expected[i].file_name) ||
 245               line_number != expected[i].line_number);
 246 
 247     if (print_out_comparisons) {
 248       fprintf(stderr, "\tComparing:\n");
 249       fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
 250       fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
 251       fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
 252       fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
 253       fprintf(stderr, "\t\tResult is %d\n", differ);
 254     }
 255 
 256     if (differ) {
 257       return FALSE;
 258     }
 259   }
 260 
 261   return TRUE;
 262 }
 263 
 264 // Static native API for various tests.
 265 static int fill_native_frames(JNIEnv* env, jobjectArray frames,
 266                               ExpectedContentFrame* native_frames, size_t size) {
 267   size_t i;
 268   for (i = 0; i < size; i++) {
 269     jclass frame_class = nullptr;
 270     jfieldID line_number_field_id = 0;
 271     int line_number = 0;
 272     jfieldID string_id = 0;
 273     jstring string_object = nullptr;
 274     const char* method = nullptr;
 275     const char* file_name = nullptr;
 276     const char* signature = nullptr;
 277 
 278     jobject obj = env->GetObjectArrayElement(frames, (jsize) i);
 279 
 280     if (env->ExceptionOccurred()) {
 281       fprintf(stderr, "fill_native_frames: Exception in jni GetObjectArrayElement\n");
 282       return -1;
 283     }
 284 
 285     frame_class = env->GetObjectClass(obj);
 286 
 287     if (env->ExceptionOccurred()) {
 288       fprintf(stderr, "fill_native_frames: Exception in jni GetObjectClass\n");
 289       return -1;
 290     }
 291 
 292     line_number_field_id = env->GetFieldID(frame_class, "lineNumber", "I");
 293 
 294     if (env->ExceptionOccurred()) {
 295       fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
 296       return -1;
 297     }
 298 
 299     line_number = env->GetIntField(obj, line_number_field_id);
 300 
 301     if (env->ExceptionOccurred()) {
 302       fprintf(stderr, "fill_native_frames: Exception in jni GetIntField\n");
 303       return -1;
 304     }
 305 
 306     string_id = env->GetFieldID(frame_class, "method", "Ljava/lang/String;");
 307 
 308     if (env->ExceptionOccurred()) {
 309       fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
 310       return -1;
 311     }
 312 
 313     string_object = (jstring) env->GetObjectField(obj, string_id);
 314 
 315     if (env->ExceptionOccurred()) {
 316       fprintf(stderr, "fill_native_frames: Exception in jni GetObjectField\n");
 317       return -1;
 318     }
 319 
 320     method = env->GetStringUTFChars(string_object, 0);
 321 
 322     if (env->ExceptionOccurred()) {
 323       fprintf(stderr, "Exception in jni GetStringUTFChars\n");
 324       return -1;
 325     }
 326 
 327     string_id = env->GetFieldID(frame_class, "fileName", "Ljava/lang/String;");
 328 
 329     if (env->ExceptionOccurred()) {
 330       fprintf(stderr, "Exception in jni GetFieldID\n");
 331       return -1;
 332     }
 333 
 334     string_object = (jstring) (env->GetObjectField(obj, string_id));
 335 
 336     if (env->ExceptionOccurred()) {
 337       fprintf(stderr, "fill_native_frames: Exception in second jni GetObjectField\n");
 338       return -1;
 339     }
 340 
 341     file_name = env->GetStringUTFChars(string_object, 0);
 342 
 343     if (env->ExceptionOccurred()) {
 344       fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
 345       return -1;
 346     }
 347 
 348     string_id = env->GetFieldID(frame_class, "signature", "Ljava/lang/String;");
 349 
 350     if (env->ExceptionOccurred()) {
 351       fprintf(stderr, "fill_native_frames: Exception in second jni GetFieldID\n");
 352       return -1;
 353     }
 354 
 355     string_object = (jstring) (env->GetObjectField(obj, string_id));
 356 
 357     if (env->ExceptionOccurred()) {
 358       fprintf(stderr, "fill_native_frames: Exception in third jni GetObjectField\n");
 359       return -1;
 360     }
 361 
 362     signature = env->GetStringUTFChars(string_object, 0);
 363 
 364     if (env->ExceptionOccurred()) {
 365       fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
 366       return -1;
 367     }
 368 
 369     native_frames[i].name = method;
 370     native_frames[i].file_name = file_name;
 371     native_frames[i].signature = signature;
 372     native_frames[i].line_number = line_number;
 373   }
 374 
 375   return 0;
 376 }
 377 
 378 // Internal storage system implementation.
 379 static EventStorage global_event_storage;
 380 static EventStorage second_global_event_storage;
 381 
 382 static void event_storage_set_compaction_required(EventStorage* storage) {
 383   event_storage_lock_compaction(storage);
 384   storage->compaction_required = 1;
 385   event_storage_unlock_compaction(storage);
 386 }
 387 
 388 static int event_storage_get_compaction_required(EventStorage* storage) {
 389   int result;
 390   event_storage_lock_compaction(storage);
 391   result = storage->compaction_required;
 392   event_storage_unlock_compaction(storage);
 393   return result;
 394 }
 395 
 396 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
 397   size_t size;
 398   event_storage_lock(storage);
 399   global_event_storage.garbage_history_size = value;
 400   free(global_event_storage.garbage_collected_objects);
 401   size = sizeof(*global_event_storage.garbage_collected_objects) * value;
 402   global_event_storage.garbage_collected_objects = reinterpret_cast<ObjectTrace**>(malloc(size));
 403   memset(global_event_storage.garbage_collected_objects, 0, size);
 404   event_storage_unlock(storage);
 405 }
 406 
 407 // No mutex here, it is handled by the caller.
 408 static void event_storage_add_garbage_collected_object(EventStorage* storage,
 409                                                        ObjectTrace* object) {
 410   int idx = storage->garbage_history_index;
 411   ObjectTrace* old_object = storage->garbage_collected_objects[idx];
 412   if (old_object != nullptr) {
 413     free(old_object->frames);
 414     free(storage->garbage_collected_objects[idx]);
 415   }
 416 
 417   storage->garbage_collected_objects[idx] = object;
 418   storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
 419 }
 420 
 421 static int event_storage_get_count(EventStorage* storage) {
 422   int result;
 423   event_storage_lock(storage);
 424   result = storage->live_object_count;
 425   event_storage_unlock(storage);
 426   return result;
 427 }
 428 
 429 static double event_storage_get_average_size(EventStorage* storage) {
 430   double accumulation = 0;
 431   int max_size;
 432   int i;
 433 
 434   event_storage_lock(storage);
 435   max_size = storage->live_object_count;
 436 
 437   for (i = 0; i < max_size; i++) {
 438     accumulation += storage->live_objects[i]->size;
 439   }
 440 
 441   event_storage_unlock(storage);
 442   return accumulation / max_size;
 443 }
 444 
 445 static jboolean event_storage_contains(JNIEnv* env,
 446                                        EventStorage* storage,
 447                                        ExpectedContentFrame* frames,
 448                                        size_t size) {
 449   int i;
 450   event_storage_lock(storage);
 451   fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
 452   for (i = 0; i < storage->live_object_count; i++) {
 453     ObjectTrace* trace = storage->live_objects[i];
 454 
 455     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 456       event_storage_unlock(storage);
 457       return TRUE;
 458     }
 459   }
 460   event_storage_unlock(storage);
 461   return FALSE;
 462 }
 463 
 464 static jlong event_storage_get_size(JNIEnv* env,
 465                                     EventStorage* storage,
 466                                     ExpectedContentFrame* frames,
 467                                     size_t size) {
 468   int i;
 469   event_storage_lock(storage);
 470   fprintf(stderr, "Getting element from storage count, size %d\n", storage->live_object_count);
 471   for (i = 0; i < storage->live_object_count; i++) {
 472     ObjectTrace* trace = storage->live_objects[i];
 473 
 474     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 475       jlong result = trace->size;
 476       event_storage_unlock(storage);
 477       return result;
 478     }
 479   }
 480   event_storage_unlock(storage);
 481   return 0;
 482 }
 483 
 484 static jboolean event_storage_garbage_contains(JNIEnv* env,
 485                                                EventStorage* storage,
 486                                                ExpectedContentFrame* frames,
 487                                                size_t size) {
 488   int i;
 489   event_storage_lock(storage);
 490   fprintf(stderr, "Checking garbage storage count %d\n",
 491           storage->garbage_history_size);
 492   for (i = 0; i < storage->garbage_history_size; i++) {
 493     ObjectTrace* trace = storage->garbage_collected_objects[i];
 494 
 495     if (trace == nullptr) {
 496       continue;
 497     }
 498 
 499     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 500       event_storage_unlock(storage);
 501       return TRUE;
 502     }
 503   }
 504   event_storage_unlock(storage);
 505   return FALSE;
 506 }
 507 
 508 // No mutex here, handled by the caller.
 509 static void event_storage_augment_storage(EventStorage* storage) {
 510   int new_max = (storage->live_object_size * 2) + 1;
 511   ObjectTrace** new_objects = reinterpret_cast<ObjectTrace**>(malloc(new_max * sizeof(*new_objects)));
 512 
 513   int current_count = storage->live_object_count;
 514   if (storage->live_objects != nullptr) {
 515     memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 516   }
 517   free(storage->live_objects);
 518   storage->live_objects = new_objects;
 519   storage->live_object_size = new_max;
 520 }
 521 
 522 static void event_storage_add(EventStorage* storage,
 523                               JNIEnv* jni,
 524                               jthread thread,
 525                               jobject object,
 526                               jclass klass,
 527                               jlong size) {
 528   jvmtiFrameInfo frames[64];
 529   jint count;
 530   jvmtiError err;
 531 
 532   if (!jni->HasIdentity(object)) {
 533     // weak references are prohibited for non-identity objects, skip them
 534     return;
 535   }
 536 
 537   err = jvmti->GetStackTrace(thread, 0, 64, frames, &count);
 538   if (err == JVMTI_ERROR_NONE && count >= 1) {
 539     ObjectTrace* live_object;
 540     jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
 541     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 542 
 543     live_object = (ObjectTrace*) malloc(sizeof(*live_object));
 544     live_object->frames = allocated_frames;
 545     live_object->frame_count = count;
 546     live_object->size = size;
 547     live_object->thread = thread;
 548     live_object->object = jni->NewWeakGlobalRef(object);
 549 
 550     if (jni->ExceptionOccurred()) {
 551       jni->FatalError("Error in event_storage_add: Exception in jni NewWeakGlobalRef");
 552     }
 553 
 554     // Only now lock and get things done quickly.
 555     event_storage_lock(storage);
 556 
 557     storage->live_object_additions++;
 558 
 559     if (storage->live_object_count >= storage->live_object_size) {
 560       event_storage_augment_storage(storage);
 561     }
 562     assert(storage->live_object_count < storage->live_object_size);
 563 
 564     if (PRINT_OUT) {
 565       fprintf(stderr, "Adding trace for thread %p, frame_count %d, storage %p\n",
 566               thread, count, storage);
 567       print_out_frames(jni, live_object);
 568     }
 569     storage->live_objects[storage->live_object_count] = live_object;
 570     storage->live_object_count++;
 571 
 572     event_storage_unlock(storage);
 573   }
 574 }
 575 
 576 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
 577   int max, i, dest;
 578   ObjectTrace** live_objects;
 579 
 580   event_storage_lock_compaction(storage);
 581   storage->compaction_required = 0;
 582   event_storage_unlock_compaction(storage);
 583 
 584   event_storage_lock(storage);
 585 
 586   max = storage->live_object_count;
 587   live_objects = storage->live_objects;
 588 
 589   for (i = 0, dest = 0; i < max; i++) {
 590     ObjectTrace* live_object = live_objects[i];
 591     jweak object = live_object->object;
 592 
 593     if (!jni->IsSameObject(object, nullptr)) {
 594       if (dest != i) {
 595         live_objects[dest] = live_object;
 596         dest++;
 597       }
 598     } else {
 599       jni->DeleteWeakGlobalRef(object);
 600       live_object->object = nullptr;
 601 
 602       event_storage_add_garbage_collected_object(storage, live_object);
 603     }
 604   }
 605 
 606   storage->live_object_count = dest;
 607   event_storage_unlock(storage);
 608 }
 609 
 610 static void event_storage_free_objects(ObjectTrace** array, int max) {
 611   int i;
 612   for (i = 0; i < max; i++) {
 613     free(array[i]), array[i] = nullptr;
 614   }
 615 }
 616 
 617 static void event_storage_reset(EventStorage* storage) {
 618   event_storage_lock(storage);
 619 
 620   // Reset everything except the mutex and the garbage collection.
 621   event_storage_free_objects(storage->live_objects,
 622                              storage->live_object_count);
 623   storage->live_object_additions = 0;
 624   storage->live_object_size = 0;
 625   storage->live_object_count = 0;
 626   free(storage->live_objects), storage->live_objects = nullptr;
 627 
 628   event_storage_free_objects(storage->garbage_collected_objects,
 629                              storage->garbage_history_size);
 630 
 631   storage->compaction_required = 0;
 632   storage->garbage_history_index = 0;
 633 
 634   event_storage_unlock(storage);
 635 }
 636 
 637 static int event_storage_number_additions(EventStorage* storage) {
 638   int result;
 639   event_storage_lock(storage);
 640   result = storage->live_object_additions;
 641   event_storage_unlock(storage);
 642   return result;
 643 }
 644 
 645 // Start of the JVMTI agent code.
 646 static const char *EXC_CNAME = "java/lang/Exception";
 647 
 648 static int check_error(jvmtiError err, const char *s) {
 649   if (err != JVMTI_ERROR_NONE) {
 650     printf("  ## %s error: %d\n", s, err);
 651     return 1;
 652   }
 653   return 0;
 654 }
 655 
 656 static int check_capability_error(jvmtiError err, const char *s) {
 657   if (err != JVMTI_ERROR_NONE) {
 658     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 659       return 0;
 660     }
 661     fprintf(stderr, "  ## %s error: %d\n", s, err);
 662   }
 663   return 1;
 664 }
 665 
 666 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 667 
 668 JNIEXPORT
 669 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 670   return Agent_Initialize(jvm, options, reserved);
 671 }
 672 
 673 JNIEXPORT
 674 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 675   return Agent_Initialize(jvm, options, reserved);
 676 }
 677 
 678 JNIEXPORT
 679 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 680   return JNI_VERSION_1_8;
 681 }
 682 
 683 #define MAX_THREADS 500
 684 
 685 typedef struct ThreadStats {
 686   int thread_count;
 687   int counts[MAX_THREADS];
 688   char* threads[MAX_THREADS];
 689 } ThreadStats;
 690 
 691 static ThreadStats thread_stats;
 692 
 693 JNIEXPORT jboolean JNICALL
 694 Java_MyPackage_HeapMonitorThreadDisabledTest_checkThreadSamplesOnlyFrom(
 695     JNIEnv* env, jclass cls, jthread thread) {
 696   jvmtiThreadInfo info;
 697   jvmtiError err;
 698   char* expected_name;
 699   int found_thread = FALSE;
 700 
 701   err = jvmti->GetThreadInfo(thread, &info);
 702   expected_name = info.name;
 703 
 704   if (err != JVMTI_ERROR_NONE) {
 705     fprintf(stderr, "Failed to get thread information\n");
 706     return FALSE;
 707   }
 708 
 709   if (thread_stats.thread_count != 1) {
 710     fprintf(stderr, "Wrong thread number: %d (expected 1)\n",
 711             thread_stats.thread_count);
 712     return FALSE;
 713   }
 714 
 715   if (strcmp(expected_name, thread_stats.threads[0]) != 0) {
 716     fprintf(stderr, "Unexpected thread name: '%s' (expected '%s')\n",
 717             thread_stats.threads[0], expected_name);
 718     return FALSE;
 719   }
 720 
 721   return TRUE;
 722 }
 723 
 724 static void add_thread_count(jthread thread) {
 725   int i;
 726   jvmtiThreadInfo info;
 727   jvmtiError err;
 728 
 729   err = jvmti->GetThreadInfo(thread, &info);
 730   if (err != JVMTI_ERROR_NONE) {
 731     fprintf(stderr, "Thread info for %p failed, ignoring thread count\n",
 732             thread);
 733     return;
 734   }
 735 
 736   event_storage_lock(&global_event_storage);
 737   for (i = 0; i < thread_stats.thread_count; i++) {
 738     if (!strcmp(thread_stats.threads[i], info.name)) {
 739       thread_stats.counts[i]++;
 740       event_storage_unlock(&global_event_storage);
 741       return;
 742     }
 743   }
 744 
 745   thread_stats.threads[thread_stats.thread_count] = info.name;
 746   thread_stats.counts[thread_stats.thread_count]++;
 747   thread_stats.thread_count++;
 748   event_storage_unlock(&global_event_storage);
 749 }
 750 
 751 JNIEXPORT void JNICALL
 752 Java_MyPackage_HeapMonitorThreadDisabledTest_enableSamplingEvents(
 753     JNIEnv* env, jclass cls, jthread thread) {
 754   fprintf(stderr, "Enabling for %p\n", thread);
 755   check_error(jvmti->SetEventNotificationMode(
 756       JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, thread),
 757               "Set event notifications for a single thread");
 758 }
 759 
 760 static void print_thread_stats() {
 761   int i;
 762   event_storage_lock(&global_event_storage);
 763   fprintf(stderr, "Thread count:\n");
 764   for (i = 0; i < thread_stats.thread_count; i++) {
 765     fprintf(stderr, "\t%s: %d\n", thread_stats.threads[i], thread_stats.counts[i]);
 766   }
 767   event_storage_unlock(&global_event_storage);
 768 }
 769 
 770 JNIEXPORT
 771 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 772                                 JNIEnv* jni_env,
 773                                 jthread thread,
 774                                 jobject object,
 775                                 jclass object_klass,
 776                                 jlong size) {
 777   add_thread_count(thread);
 778 
 779   if (event_storage_get_compaction_required(&global_event_storage)) {
 780     event_storage_compact(&global_event_storage, jni_env);
 781   }
 782 
 783   event_storage_add(&global_event_storage, jni_env, thread, object,
 784                     object_klass, size);
 785 }
 786 
 787 JNIEXPORT
 788 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
 789                            JNIEnv* jni_env,
 790                            jthread thread,
 791                            jobject object,
 792                            jclass object_klass,
 793                            jlong size) {
 794   event_storage_add(&second_global_event_storage, jni_env, thread, object,
 795                     object_klass, size);
 796 }
 797 
 798 JNIEXPORT
 799 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
 800   event_storage_set_compaction_required(&global_event_storage);
 801 }
 802 
 803 static int enable_notifications() {
 804   if (check_error(jvmti->SetEventNotificationMode(
 805       JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr),
 806                      "Set event notifications")) {
 807     return 1;
 808   }
 809 
 810   return check_error(jvmti->SetEventNotificationMode(
 811       JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr),
 812                      "Set event notifications");
 813 }
 814 
 815 static
 816 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 817   jint res;
 818   jvmtiEventCallbacks callbacks;
 819   jvmtiCapabilities caps;
 820 
 821   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION);
 822   if (res != JNI_OK || jvmti == nullptr) {
 823     fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
 824     return JNI_ERR;
 825   }
 826 
 827   // Get second jvmti environment.
 828   res = jvm->GetEnv((void **) &second_jvmti, JVMTI_VERSION);
 829   if (res != JNI_OK || second_jvmti == nullptr) {
 830     fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
 831     return JNI_ERR;
 832   }
 833 
 834   if (PRINT_OUT) {
 835     fprintf(stderr, "Storage is at %p, secondary is at %p\n",
 836             &global_event_storage, &second_global_event_storage);
 837   }
 838 
 839   jvmti->CreateRawMonitor("storage_monitor",
 840                              &global_event_storage.storage_monitor);
 841   jvmti->CreateRawMonitor("second_storage_monitor",
 842                              &second_global_event_storage.storage_monitor);
 843 
 844   jvmti->CreateRawMonitor("compaction_monitor",
 845                              &global_event_storage.compaction_monitor);
 846   jvmti->CreateRawMonitor("second_compaction_monitor",
 847                              &second_global_event_storage.compaction_monitor);
 848 
 849   event_storage_set_garbage_history(&global_event_storage, 200);
 850   event_storage_set_garbage_history(&second_global_event_storage, 200);
 851 
 852   memset(&callbacks, 0, sizeof(callbacks));
 853   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 854   callbacks.VMObjectAlloc = &VMObjectAlloc;
 855   callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
 856 
 857   memset(&caps, 0, sizeof(caps));
 858   // Get line numbers, sample events, filename, and gc events for the tests.
 859   caps.can_get_line_numbers = 1;
 860   caps.can_get_source_file_name = 1;
 861   caps.can_generate_garbage_collection_events = 1;
 862   caps.can_generate_sampled_object_alloc_events = 1;
 863   caps.can_generate_vm_object_alloc_events = 1;
 864   if (check_error(jvmti->AddCapabilities(&caps), "Add capabilities")) {
 865     return JNI_ERR;
 866   }
 867 
 868   if (check_error(jvmti->SetEventCallbacks(&callbacks,
 869                                            sizeof(jvmtiEventCallbacks)),
 870                   " Set Event Callbacks")) {
 871     return JNI_ERR;
 872   }
 873   return JNI_OK;
 874 }
 875 
 876 JNIEXPORT void JNICALL
 877 Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {
 878   jvmti->SetHeapSamplingInterval(value);
 879 }
 880 
 881 JNIEXPORT jboolean JNICALL
 882 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 883   return event_storage_get_count(&global_event_storage) == 0;
 884 }
 885 
 886 JNIEXPORT jint JNICALL
 887 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
 888   return event_storage_get_count(&global_event_storage);
 889 }
 890 
 891 JNIEXPORT void JNICALL
 892 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 893   enable_notifications();
 894 }
 895 
 896 JNIEXPORT void JNICALL
 897 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 898   check_error(jvmti->SetEventNotificationMode(
 899       JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr),
 900               "Set event notifications");
 901 
 902   check_error(jvmti->SetEventNotificationMode(
 903       JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr),
 904               "Garbage Collection Finish");
 905 }
 906 
 907 static ExpectedContentFrame *get_native_frames(JNIEnv* env, jclass cls,
 908                                                jobjectArray frames) {
 909   ExpectedContentFrame *native_frames;
 910   jsize size = env->GetArrayLength(frames);
 911 
 912   if (env->ExceptionOccurred()) {
 913     env->FatalError("get_native_frames failed with the GetArrayLength call");
 914   }
 915 
 916   native_frames = reinterpret_cast<ExpectedContentFrame*> (malloc(size * sizeof(*native_frames)));
 917 
 918   if (native_frames == nullptr) {
 919     env->FatalError("Error in get_native_frames: malloc returned null\n");
 920   }
 921 
 922   if (fill_native_frames(env, frames, native_frames, size) != 0) {
 923     env->FatalError("Error in get_native_frames: fill_native_frames returned failed status\n");
 924   }
 925 
 926   return native_frames;
 927 }
 928 
 929 JNIEXPORT jboolean JNICALL
 930 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,
 931                                           jobjectArray frames) {
 932   jboolean result;
 933   jsize size = env->GetArrayLength(frames);
 934   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 935 
 936   result = event_storage_contains(env, &global_event_storage, native_frames,
 937                                   size);
 938 
 939   free(native_frames), native_frames = nullptr;
 940   return result;
 941 }
 942 
 943 JNIEXPORT jboolean JNICALL
 944 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls,
 945                                            jobjectArray frames) {
 946   jboolean result;
 947   jsize size = env->GetArrayLength(frames);
 948   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 949 
 950   result = event_storage_garbage_contains(env, &global_event_storage,
 951                                           native_frames, size);
 952 
 953   free(native_frames), native_frames = nullptr;
 954   return result;
 955 }
 956 
 957 JNIEXPORT jlong JNICALL
 958 Java_MyPackage_HeapMonitor_getSize(JNIEnv* env, jclass cls,
 959                                    jobjectArray frames) {
 960   jlong result = 0;
 961   jsize size = env->GetArrayLength(frames);
 962   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 963 
 964   result = event_storage_get_size(env, &global_event_storage,
 965                                   native_frames, size);
 966 
 967   free(native_frames), native_frames = nullptr;
 968   return result;
 969 }
 970 
 971 JNIEXPORT void JNICALL
 972 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
 973   check_error(jvmti->ForceGarbageCollection(),
 974               "Forced Garbage Collection");
 975 }
 976 
 977 JNIEXPORT void JNICALL
 978 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 979   event_storage_reset(&global_event_storage);
 980   event_storage_reset(&second_global_event_storage);
 981 }
 982 
 983 JNIEXPORT jboolean JNICALL
 984 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 985                                                                   jclass cls) {
 986   jvmtiCapabilities caps;
 987   memset(&caps, 0, sizeof(caps));
 988   caps.can_generate_sampled_object_alloc_events = 1;
 989   if (check_error(jvmti->RelinquishCapabilities(&caps),
 990                   "Add capabilities\n")){
 991     return FALSE;
 992   }
 993 
 994   if (check_capability_error(jvmti->SetHeapSamplingInterval(1<<19),
 995                              "Set Heap Sampling Interval")) {
 996     return FALSE;
 997   }
 998   return TRUE;
 999 }
1000 
1001 JNIEXPORT jboolean JNICALL
1002 Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env,
1003                                                                   jclass cls) {
1004   if (check_error(jvmti->SetHeapSamplingInterval(0),
1005                   "Sampling interval 0 failed\n")){
1006     return FALSE;
1007   }
1008 
1009   if (check_error(jvmti->SetHeapSamplingInterval(1024),
1010                   "Sampling interval 1024 failed\n")){
1011     return FALSE;
1012   }
1013 
1014   if (!check_error(jvmti->SetHeapSamplingInterval(-1),
1015                    "Sampling interval -1 passed\n")){
1016     return FALSE;
1017   }
1018 
1019   if (!check_error(jvmti->SetHeapSamplingInterval(-1024),
1020                    "Sampling interval -1024 passed\n")){
1021     return FALSE;
1022   }
1023 
1024   return TRUE;
1025 }
1026 
1027 JNIEXPORT jdouble JNICALL
1028 Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {
1029   return event_storage_get_average_size(&global_event_storage);
1030 }
1031 
1032 typedef struct sThreadsFound {
1033   jthread* threads;
1034   int num_threads;
1035 } ThreadsFound;
1036 
1037 JNIEXPORT jboolean JNICALL
1038 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
1039                                                   jint num_threads) {
1040   print_thread_stats();
1041   // Ensure we got stacks from at least num_threads.
1042   return thread_stats.thread_count >= num_threads;
1043 }
1044 
1045 JNIEXPORT
1046 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
1047                                  JNIEnv* jni_env,
1048                                  jthread thread,
1049                                  jobject object,
1050                                  jclass object_klass,
1051                                  jlong size) {
1052   // Nop for now, two agents are not yet implemented.
1053   assert(0);
1054 }
1055 
1056 JNIEXPORT jboolean JNICALL
1057 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
1058     JNIEnv* env, jclass cls) {
1059   // Currently this method should be failing directly at the AddCapability step
1060   // but the implementation is correct for when multi-agent support is enabled.
1061   jvmtiCapabilities caps;
1062   jvmtiEventCallbacks callbacks;
1063 
1064   memset(&caps, 0, sizeof(caps));
1065   caps.can_generate_sampled_object_alloc_events = 1;
1066   if (check_error(second_jvmti->AddCapabilities(&caps),
1067                   "Set the capability for second agent")) {
1068     return FALSE;
1069   }
1070 
1071   memset(&callbacks, 0, sizeof(callbacks));
1072   callbacks.SampledObjectAlloc = &SampledObjectAlloc2;
1073 
1074   if (check_error(second_jvmti->SetEventCallbacks(&callbacks,
1075                                                   sizeof(jvmtiEventCallbacks)),
1076                   " Set Event Callbacks for second agent")) {
1077     return FALSE;
1078   }
1079 
1080   return TRUE;
1081 }
1082 
1083 JNIEXPORT void JNICALL
1084 Java_MyPackage_HeapMonitor_enableVMEvents(JNIEnv* env, jclass cls) {
1085   check_error(jvmti->SetEventNotificationMode(
1086       JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr),
1087               "Set vm event notifications");
1088 }
1089 
1090 JNIEXPORT jint JNICALL
1091 Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) {
1092   return event_storage_number_additions(&second_global_event_storage);
1093 }
1094 
1095 JNIEXPORT jint JNICALL
1096 Java_MyPackage_HeapMonitor_sampledEvents(JNIEnv* env, jclass cls) {
1097   return event_storage_number_additions(&global_event_storage);
1098 }
1099 
1100 static jobject allocate_object(JNIEnv* env) {
1101   // Construct an Object.
1102   jclass cls = env->FindClass("java/lang/Object");
1103   jmethodID constructor;
1104   jobject result;
1105 
1106   if (env->ExceptionOccurred() || cls == nullptr) {
1107     env->FatalError("Error in jni FindClass: Cannot find Object class\n");
1108   }
1109 
1110   constructor = env->GetMethodID(cls, "<init>", "()V");
1111   if (env->ExceptionOccurred() || constructor == nullptr) {
1112     env->FatalError("Error in jni GetMethodID: Cannot find Object class constructor\n");
1113   }
1114 
1115   // Call back constructor to allocate a new instance, with an int argument
1116   result = env->NewObject(cls, constructor);
1117 
1118   if (env->ExceptionOccurred() || result == nullptr) {
1119     env->FatalError("Error in jni NewObject: Cannot allocate an object\n");
1120   }
1121   return result;
1122 }
1123 
1124 // Ensure we got a callback for the test.
1125 static int did_recursive_callback_test;
1126 
1127 JNIEXPORT
1128 void JNICALL RecursiveSampledObjectAlloc(jvmtiEnv *jvmti_env,
1129                                          JNIEnv* jni_env,
1130                                          jthread thread,
1131                                          jobject object,
1132                                          jclass object_klass,
1133                                          jlong size) {
1134   // Basically ensure that if we were to allocate objects, we would not have an
1135   // infinite recursion here.
1136   int i;
1137   for (i = 0; i < 1000; i++) {
1138     if (allocate_object(jni_env) == nullptr) {
1139       jni_env->FatalError("allocate_object returned null\n");
1140     }
1141   }
1142 
1143   did_recursive_callback_test = 1;
1144 }
1145 
1146 JNIEXPORT jboolean JNICALL
1147 Java_MyPackage_HeapMonitorRecursiveTest_didCallback(JNIEnv* env, jclass cls) {
1148   return did_recursive_callback_test != 0;
1149 }
1150 
1151 JNIEXPORT void JNICALL
1152 Java_MyPackage_HeapMonitorRecursiveTest_setCallbackToCallAllocateSomeMore(JNIEnv* env, jclass cls) {
1153   jvmtiEventCallbacks callbacks;
1154 
1155   memset(&callbacks, 0, sizeof(callbacks));
1156   callbacks.SampledObjectAlloc = &RecursiveSampledObjectAlloc;
1157 
1158   if (check_error(jvmti->SetEventCallbacks(&callbacks,
1159                                            sizeof(jvmtiEventCallbacks)),
1160                   "Set Event Callbacks")) {
1161     env->FatalError("Cannot reset the callback.");
1162   }
1163 }
1164 
1165 }
--- EOF ---