1 /*
   2  * Copyright (c) 2018, 2024, 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                                      jboolean check_lines,
 194                                      int print_out_comparisons) {
 195   jvmtiFrameInfo* frames;
 196   size_t i;
 197 
 198   if (expected_count > trace->frame_count) {
 199     return FALSE;
 200   }
 201 
 202   frames = trace->frames;
 203   for (i = 0; i < expected_count; i++) {
 204     // Get basic information out of the trace.
 205     jlocation bci = frames[i].location;
 206     jmethodID methodid = frames[i].method;
 207     char *name = nullptr, *signature = nullptr, *file_name = nullptr;
 208     jclass declaring_class;
 209     int line_number;
 210     jboolean differ;
 211     jvmtiError err;
 212 
 213     if (bci < 0 && expected[i].line_number != -1) {
 214       return FALSE;
 215     }
 216 
 217     // Transform into usable information.
 218     line_number = get_line_number(methodid, bci);
 219     jvmti->GetMethodName(methodid, &name, &signature, 0);
 220 
 221     if (JVMTI_ERROR_NONE != jvmti->GetMethodDeclaringClass(methodid, &declaring_class)) {
 222       return FALSE;
 223     }
 224 
 225     err = jvmti->GetSourceFileName(declaring_class, &file_name);
 226     if (err != JVMTI_ERROR_NONE) {
 227       return FALSE;
 228     }
 229 
 230     // Compare now, none should be null.
 231     if (name == nullptr) {
 232       return FALSE;
 233     }
 234 
 235     if (file_name == nullptr) {
 236       return FALSE;
 237     }
 238 
 239     if (signature == nullptr) {
 240       return FALSE;
 241     }
 242 
 243     differ = (strcmp(name, expected[i].name) ||
 244               strcmp(signature, expected[i].signature) ||
 245               strcmp(file_name, expected[i].file_name) ||
 246               (check_lines && line_number != expected[i].line_number));
 247 
 248     if (print_out_comparisons) {
 249       fprintf(stderr, "\tComparing: (check_lines: %d)\n", check_lines);
 250       fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
 251       fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
 252       fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
 253       fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
 254       fprintf(stderr, "\t\tResult is %d\n", differ);
 255     }
 256 
 257     if (differ) {
 258       return FALSE;
 259     }
 260   }
 261 
 262   return TRUE;
 263 }
 264 
 265 // Static native API for various tests.
 266 static int fill_native_frames(JNIEnv* env, jobjectArray frames,
 267                               ExpectedContentFrame* native_frames, size_t size) {
 268   size_t i;
 269   for (i = 0; i < size; i++) {
 270     jclass frame_class = nullptr;
 271     jfieldID line_number_field_id = 0;
 272     int line_number = 0;
 273     jfieldID string_id = 0;
 274     jstring string_object = nullptr;
 275     const char* method = nullptr;
 276     const char* file_name = nullptr;
 277     const char* signature = nullptr;
 278 
 279     jobject obj = env->GetObjectArrayElement(frames, (jsize) i);
 280 
 281     if (env->ExceptionOccurred()) {
 282       fprintf(stderr, "fill_native_frames: Exception in jni GetObjectArrayElement\n");
 283       return -1;
 284     }
 285 
 286     frame_class = env->GetObjectClass(obj);
 287 
 288     if (env->ExceptionOccurred()) {
 289       fprintf(stderr, "fill_native_frames: Exception in jni GetObjectClass\n");
 290       return -1;
 291     }
 292 
 293     line_number_field_id = env->GetFieldID(frame_class, "lineNumber", "I");
 294 
 295     if (env->ExceptionOccurred()) {
 296       fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
 297       return -1;
 298     }
 299 
 300     line_number = env->GetIntField(obj, line_number_field_id);
 301 
 302     if (env->ExceptionOccurred()) {
 303       fprintf(stderr, "fill_native_frames: Exception in jni GetIntField\n");
 304       return -1;
 305     }
 306 
 307     string_id = env->GetFieldID(frame_class, "method", "Ljava/lang/String;");
 308 
 309     if (env->ExceptionOccurred()) {
 310       fprintf(stderr, "fill_native_frames: Exception in jni GetFieldID\n");
 311       return -1;
 312     }
 313 
 314     string_object = (jstring) env->GetObjectField(obj, string_id);
 315 
 316     if (env->ExceptionOccurred()) {
 317       fprintf(stderr, "fill_native_frames: Exception in jni GetObjectField\n");
 318       return -1;
 319     }
 320 
 321     method = env->GetStringUTFChars(string_object, 0);
 322 
 323     if (env->ExceptionOccurred()) {
 324       fprintf(stderr, "Exception in jni GetStringUTFChars\n");
 325       return -1;
 326     }
 327 
 328     string_id = env->GetFieldID(frame_class, "fileName", "Ljava/lang/String;");
 329 
 330     if (env->ExceptionOccurred()) {
 331       fprintf(stderr, "Exception in jni GetFieldID\n");
 332       return -1;
 333     }
 334 
 335     string_object = (jstring) (env->GetObjectField(obj, string_id));
 336 
 337     if (env->ExceptionOccurred()) {
 338       fprintf(stderr, "fill_native_frames: Exception in second jni GetObjectField\n");
 339       return -1;
 340     }
 341 
 342     file_name = env->GetStringUTFChars(string_object, 0);
 343 
 344     if (env->ExceptionOccurred()) {
 345       fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
 346       return -1;
 347     }
 348 
 349     string_id = env->GetFieldID(frame_class, "signature", "Ljava/lang/String;");
 350 
 351     if (env->ExceptionOccurred()) {
 352       fprintf(stderr, "fill_native_frames: Exception in second jni GetFieldID\n");
 353       return -1;
 354     }
 355 
 356     string_object = (jstring) (env->GetObjectField(obj, string_id));
 357 
 358     if (env->ExceptionOccurred()) {
 359       fprintf(stderr, "fill_native_frames: Exception in third jni GetObjectField\n");
 360       return -1;
 361     }
 362 
 363     signature = env->GetStringUTFChars(string_object, 0);
 364 
 365     if (env->ExceptionOccurred()) {
 366       fprintf(stderr, "fill_native_frames: Exception in jni GetStringUTFChars\n");
 367       return -1;
 368     }
 369 
 370     native_frames[i].name = method;
 371     native_frames[i].file_name = file_name;
 372     native_frames[i].signature = signature;
 373     native_frames[i].line_number = line_number;
 374   }
 375 
 376   return 0;
 377 }
 378 
 379 // Internal storage system implementation.
 380 static EventStorage global_event_storage;
 381 static EventStorage second_global_event_storage;
 382 
 383 static void event_storage_set_compaction_required(EventStorage* storage) {
 384   event_storage_lock_compaction(storage);
 385   storage->compaction_required = 1;
 386   event_storage_unlock_compaction(storage);
 387 }
 388 
 389 static int event_storage_get_compaction_required(EventStorage* storage) {
 390   int result;
 391   event_storage_lock_compaction(storage);
 392   result = storage->compaction_required;
 393   event_storage_unlock_compaction(storage);
 394   return result;
 395 }
 396 
 397 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
 398   size_t size;
 399   event_storage_lock(storage);
 400   global_event_storage.garbage_history_size = value;
 401   free(global_event_storage.garbage_collected_objects);
 402   size = sizeof(*global_event_storage.garbage_collected_objects) * value;
 403   global_event_storage.garbage_collected_objects = reinterpret_cast<ObjectTrace**>(malloc(size));
 404   memset(global_event_storage.garbage_collected_objects, 0, size);
 405   event_storage_unlock(storage);
 406 }
 407 
 408 // No mutex here, it is handled by the caller.
 409 static void event_storage_add_garbage_collected_object(EventStorage* storage,
 410                                                        ObjectTrace* object) {
 411   int idx = storage->garbage_history_index;
 412   ObjectTrace* old_object = storage->garbage_collected_objects[idx];
 413   if (old_object != nullptr) {
 414     free(old_object->frames);
 415     free(storage->garbage_collected_objects[idx]);
 416   }
 417 
 418   storage->garbage_collected_objects[idx] = object;
 419   storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
 420 }
 421 
 422 static int event_storage_get_count(EventStorage* storage) {
 423   int result;
 424   event_storage_lock(storage);
 425   result = storage->live_object_count;
 426   event_storage_unlock(storage);
 427   return result;
 428 }
 429 
 430 static double event_storage_get_average_size(EventStorage* storage) {
 431   double accumulation = 0;
 432   int max_size;
 433   int i;
 434 
 435   event_storage_lock(storage);
 436   max_size = storage->live_object_count;
 437 
 438   for (i = 0; i < max_size; i++) {
 439     accumulation += storage->live_objects[i]->size;
 440   }
 441 
 442   event_storage_unlock(storage);
 443   return accumulation / max_size;
 444 }
 445 
 446 static jboolean event_storage_contains(JNIEnv* env,
 447                                        EventStorage* storage,
 448                                        ExpectedContentFrame* frames,
 449                                        size_t size,
 450                                        jboolean check_lines) {
 451   int i;
 452   event_storage_lock(storage);
 453   fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
 454   for (i = 0; i < storage->live_object_count; i++) {
 455     ObjectTrace* trace = storage->live_objects[i];
 456 
 457     if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {
 458       event_storage_unlock(storage);
 459       return TRUE;
 460     }
 461   }
 462   event_storage_unlock(storage);
 463   return FALSE;
 464 }
 465 
 466 static jlong event_storage_get_size(JNIEnv* env,
 467                                     EventStorage* storage,
 468                                     ExpectedContentFrame* frames,
 469                                     size_t size,
 470                                     jboolean check_lines) {
 471   int i;
 472   event_storage_lock(storage);
 473   fprintf(stderr, "Getting element from storage count, size %d\n", storage->live_object_count);
 474   for (i = 0; i < storage->live_object_count; i++) {
 475     ObjectTrace* trace = storage->live_objects[i];
 476 
 477     if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {
 478       jlong result = trace->size;
 479       event_storage_unlock(storage);
 480       return result;
 481     }
 482   }
 483   event_storage_unlock(storage);
 484   return 0;
 485 }
 486 
 487 static jboolean event_storage_garbage_contains(JNIEnv* env,
 488                                                EventStorage* storage,
 489                                                ExpectedContentFrame* frames,
 490                                                size_t size,
 491                                                jboolean check_lines) {
 492   int i;
 493   event_storage_lock(storage);
 494   fprintf(stderr, "Checking garbage storage count %d\n",
 495           storage->garbage_history_size);
 496   for (i = 0; i < storage->garbage_history_size; i++) {
 497     ObjectTrace* trace = storage->garbage_collected_objects[i];
 498 
 499     if (trace == nullptr) {
 500       continue;
 501     }
 502 
 503     if (check_sample_content(env, trace, frames, size, check_lines, PRINT_OUT)) {
 504       event_storage_unlock(storage);
 505       return TRUE;
 506     }
 507   }
 508   event_storage_unlock(storage);
 509   return FALSE;
 510 }
 511 
 512 // No mutex here, handled by the caller.
 513 static void event_storage_augment_storage(EventStorage* storage) {
 514   int new_max = (storage->live_object_size * 2) + 1;
 515   ObjectTrace** new_objects = reinterpret_cast<ObjectTrace**>(malloc(new_max * sizeof(*new_objects)));
 516 
 517   int current_count = storage->live_object_count;
 518   if (storage->live_objects != nullptr) {
 519     memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 520   }
 521   free(storage->live_objects);
 522   storage->live_objects = new_objects;
 523   storage->live_object_size = new_max;
 524 }
 525 
 526 static void event_storage_add(EventStorage* storage,
 527                               JNIEnv* jni,
 528                               jthread thread,
 529                               jobject object,
 530                               jclass klass,
 531                               jlong size) {
 532   jvmtiFrameInfo frames[64];
 533   jint count;
 534   jvmtiError err;
 535 
 536   err = jvmti->GetStackTrace(thread, 0, 64, frames, &count);
 537   if (err == JVMTI_ERROR_NONE && count >= 1) {
 538     ObjectTrace* live_object;
 539     jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
 540     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 541 
 542     live_object = (ObjectTrace*) malloc(sizeof(*live_object));
 543     live_object->frames = allocated_frames;
 544     live_object->frame_count = count;
 545     live_object->size = size;
 546     live_object->thread = thread;
 547     live_object->object = jni->NewWeakGlobalRef(object);
 548 
 549     if (jni->ExceptionOccurred()) {
 550       jni->FatalError("Error in event_storage_add: Exception in jni NewWeakGlobalRef");
 551     }
 552 
 553     // Only now lock and get things done quickly.
 554     event_storage_lock(storage);
 555 
 556     storage->live_object_additions++;
 557 
 558     if (storage->live_object_count >= storage->live_object_size) {
 559       event_storage_augment_storage(storage);
 560     }
 561     assert(storage->live_object_count < storage->live_object_size);
 562 
 563     if (PRINT_OUT) {
 564       fprintf(stderr, "Adding trace for thread %p, frame_count %d, storage %p\n",
 565               thread, count, storage);
 566       print_out_frames(jni, live_object);
 567     }
 568     storage->live_objects[storage->live_object_count] = live_object;
 569     storage->live_object_count++;
 570 
 571     event_storage_unlock(storage);
 572   }
 573 }
 574 
 575 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
 576   int max, i, dest;
 577   ObjectTrace** live_objects;
 578 
 579   event_storage_lock_compaction(storage);
 580   storage->compaction_required = 0;
 581   event_storage_unlock_compaction(storage);
 582 
 583   event_storage_lock(storage);
 584 
 585   max = storage->live_object_count;
 586   live_objects = storage->live_objects;
 587 
 588   for (i = 0, dest = 0; i < max; i++) {
 589     ObjectTrace* live_object = live_objects[i];
 590     jweak object = live_object->object;
 591 
 592     if (!jni->IsSameObject(object, nullptr)) {
 593       if (dest != i) {
 594         live_objects[dest] = live_object;
 595         dest++;
 596       }
 597     } else {
 598       jni->DeleteWeakGlobalRef(object);
 599       live_object->object = nullptr;
 600 
 601       event_storage_add_garbage_collected_object(storage, live_object);
 602     }
 603   }
 604 
 605   storage->live_object_count = dest;
 606   event_storage_unlock(storage);
 607 }
 608 
 609 static void event_storage_free_objects(ObjectTrace** array, int max) {
 610   int i;
 611   for (i = 0; i < max; i++) {
 612     free(array[i]), array[i] = nullptr;
 613   }
 614 }
 615 
 616 static void event_storage_reset(EventStorage* storage) {
 617   event_storage_lock(storage);
 618 
 619   // Reset everything except the mutex and the garbage collection.
 620   event_storage_free_objects(storage->live_objects,
 621                              storage->live_object_count);
 622   storage->live_object_additions = 0;
 623   storage->live_object_size = 0;
 624   storage->live_object_count = 0;
 625   free(storage->live_objects), storage->live_objects = nullptr;
 626 
 627   event_storage_free_objects(storage->garbage_collected_objects,
 628                              storage->garbage_history_size);
 629 
 630   storage->compaction_required = 0;
 631   storage->garbage_history_index = 0;
 632 
 633   event_storage_unlock(storage);
 634 }
 635 
 636 static int event_storage_number_additions(EventStorage* storage) {
 637   int result;
 638   event_storage_lock(storage);
 639   result = storage->live_object_additions;
 640   event_storage_unlock(storage);
 641   return result;
 642 }
 643 
 644 // Start of the JVMTI agent code.
 645 static const char *EXC_CNAME = "java/lang/Exception";
 646 
 647 static int check_error(jvmtiError err, const char *s) {
 648   if (err != JVMTI_ERROR_NONE) {
 649     printf("  ## %s error: %d\n", s, err);
 650     return 1;
 651   }
 652   return 0;
 653 }
 654 
 655 static int check_capability_error(jvmtiError err, const char *s) {
 656   if (err != JVMTI_ERROR_NONE) {
 657     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 658       return 0;
 659     }
 660     fprintf(stderr, "  ## %s error: %d\n", s, err);
 661   }
 662   return 1;
 663 }
 664 
 665 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 666 
 667 JNIEXPORT
 668 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 669   return Agent_Initialize(jvm, options, reserved);
 670 }
 671 
 672 JNIEXPORT
 673 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 674   return Agent_Initialize(jvm, options, reserved);
 675 }
 676 
 677 JNIEXPORT
 678 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 679   return JNI_VERSION_1_8;
 680 }
 681 
 682 #define MAX_THREADS 500
 683 
 684 typedef struct ThreadStats {
 685   int thread_count;
 686   int counts[MAX_THREADS];
 687   char* threads[MAX_THREADS];
 688 } ThreadStats;
 689 
 690 static ThreadStats thread_stats;
 691 
 692 JNIEXPORT jboolean JNICALL
 693 Java_MyPackage_HeapMonitorThreadDisabledTest_checkThreadSamplesOnlyFrom(
 694     JNIEnv* env, jclass cls, jthread thread) {
 695   jvmtiThreadInfo info;
 696   jvmtiError err;
 697   char* expected_name;
 698   int found_thread = FALSE;
 699 
 700   err = jvmti->GetThreadInfo(thread, &info);
 701   expected_name = info.name;
 702 
 703   if (err != JVMTI_ERROR_NONE) {
 704     fprintf(stderr, "Failed to get thread information\n");
 705     return FALSE;
 706   }
 707 
 708   if (thread_stats.thread_count != 1) {
 709     fprintf(stderr, "Wrong thread number: %d (expected 1)\n",
 710             thread_stats.thread_count);
 711     return FALSE;
 712   }
 713 
 714   if (strcmp(expected_name, thread_stats.threads[0]) != 0) {
 715     fprintf(stderr, "Unexpected thread name: '%s' (expected '%s')\n",
 716             thread_stats.threads[0], expected_name);
 717     return FALSE;
 718   }
 719 
 720   return TRUE;
 721 }
 722 
 723 static void add_thread_count(jthread thread) {
 724   int i;
 725   jvmtiThreadInfo info;
 726   jvmtiError err;
 727 
 728   err = jvmti->GetThreadInfo(thread, &info);
 729   if (err != JVMTI_ERROR_NONE) {
 730     fprintf(stderr, "Thread info for %p failed, ignoring thread count\n",
 731             thread);
 732     return;
 733   }
 734 
 735   event_storage_lock(&global_event_storage);
 736   for (i = 0; i < thread_stats.thread_count; i++) {
 737     if (!strcmp(thread_stats.threads[i], info.name)) {
 738       thread_stats.counts[i]++;
 739       event_storage_unlock(&global_event_storage);
 740       return;
 741     }
 742   }
 743 
 744   thread_stats.threads[thread_stats.thread_count] = info.name;
 745   thread_stats.counts[thread_stats.thread_count]++;
 746   thread_stats.thread_count++;
 747   event_storage_unlock(&global_event_storage);
 748 }
 749 
 750 JNIEXPORT void JNICALL
 751 Java_MyPackage_HeapMonitorThreadDisabledTest_enableSamplingEvents(
 752     JNIEnv* env, jclass cls, jthread thread) {
 753   fprintf(stderr, "Enabling for %p\n", thread);
 754   check_error(jvmti->SetEventNotificationMode(
 755       JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, thread),
 756               "Set event notifications for a single thread");
 757 }
 758 
 759 static void print_thread_stats() {
 760   int i;
 761   event_storage_lock(&global_event_storage);
 762   fprintf(stderr, "Thread count:\n");
 763   for (i = 0; i < thread_stats.thread_count; i++) {
 764     fprintf(stderr, "\t%s: %d\n", thread_stats.threads[i], thread_stats.counts[i]);
 765   }
 766   event_storage_unlock(&global_event_storage);
 767 }
 768 
 769 JNIEXPORT
 770 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 771                                 JNIEnv* jni_env,
 772                                 jthread thread,
 773                                 jobject object,
 774                                 jclass object_klass,
 775                                 jlong size) {
 776   add_thread_count(thread);
 777 
 778   if (event_storage_get_compaction_required(&global_event_storage)) {
 779     event_storage_compact(&global_event_storage, jni_env);
 780   }
 781 
 782   event_storage_add(&global_event_storage, jni_env, thread, object,
 783                     object_klass, size);
 784 }
 785 
 786 JNIEXPORT
 787 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
 788                            JNIEnv* jni_env,
 789                            jthread thread,
 790                            jobject object,
 791                            jclass object_klass,
 792                            jlong size) {
 793   event_storage_add(&second_global_event_storage, jni_env, thread, object,
 794                     object_klass, size);
 795 }
 796 
 797 JNIEXPORT
 798 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
 799   event_storage_set_compaction_required(&global_event_storage);
 800 }
 801 
 802 static int enable_notifications() {
 803   if (check_error(jvmti->SetEventNotificationMode(
 804       JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr),
 805                      "Set event notifications")) {
 806     return 1;
 807   }
 808 
 809   return check_error(jvmti->SetEventNotificationMode(
 810       JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr),
 811                      "Set event notifications");
 812 }
 813 
 814 static
 815 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 816   jint res;
 817   jvmtiEventCallbacks callbacks;
 818   jvmtiCapabilities caps;
 819 
 820   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION);
 821   if (res != JNI_OK || jvmti == nullptr) {
 822     fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
 823     return JNI_ERR;
 824   }
 825 
 826   // Get second jvmti environment.
 827   res = jvm->GetEnv((void **) &second_jvmti, JVMTI_VERSION);
 828   if (res != JNI_OK || second_jvmti == nullptr) {
 829     fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
 830     return JNI_ERR;
 831   }
 832 
 833   if (PRINT_OUT) {
 834     fprintf(stderr, "Storage is at %p, secondary is at %p\n",
 835             &global_event_storage, &second_global_event_storage);
 836   }
 837 
 838   jvmti->CreateRawMonitor("storage_monitor",
 839                              &global_event_storage.storage_monitor);
 840   jvmti->CreateRawMonitor("second_storage_monitor",
 841                              &second_global_event_storage.storage_monitor);
 842 
 843   jvmti->CreateRawMonitor("compaction_monitor",
 844                              &global_event_storage.compaction_monitor);
 845   jvmti->CreateRawMonitor("second_compaction_monitor",
 846                              &second_global_event_storage.compaction_monitor);
 847 
 848   event_storage_set_garbage_history(&global_event_storage, 200);
 849   event_storage_set_garbage_history(&second_global_event_storage, 200);
 850 
 851   memset(&callbacks, 0, sizeof(callbacks));
 852   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 853   callbacks.VMObjectAlloc = &VMObjectAlloc;
 854   callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
 855 
 856   memset(&caps, 0, sizeof(caps));
 857   // Get line numbers, sample events, filename, and gc events for the tests.
 858   caps.can_get_line_numbers = 1;
 859   caps.can_get_source_file_name = 1;
 860   caps.can_generate_garbage_collection_events = 1;
 861   caps.can_generate_sampled_object_alloc_events = 1;
 862   caps.can_generate_vm_object_alloc_events = 1;
 863   if (check_error(jvmti->AddCapabilities(&caps), "Add capabilities")) {
 864     return JNI_ERR;
 865   }
 866 
 867   if (check_error(jvmti->SetEventCallbacks(&callbacks,
 868                                            sizeof(jvmtiEventCallbacks)),
 869                   " Set Event Callbacks")) {
 870     return JNI_ERR;
 871   }
 872   return JNI_OK;
 873 }
 874 
 875 JNIEXPORT void JNICALL
 876 Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {
 877   jvmti->SetHeapSamplingInterval(value);
 878 }
 879 
 880 JNIEXPORT jboolean JNICALL
 881 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 882   return event_storage_get_count(&global_event_storage) == 0;
 883 }
 884 
 885 JNIEXPORT jint JNICALL
 886 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
 887   return event_storage_get_count(&global_event_storage);
 888 }
 889 
 890 JNIEXPORT void JNICALL
 891 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 892   enable_notifications();
 893 }
 894 
 895 JNIEXPORT void JNICALL
 896 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 897   check_error(jvmti->SetEventNotificationMode(
 898       JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr),
 899               "Set event notifications");
 900 
 901   check_error(jvmti->SetEventNotificationMode(
 902       JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr),
 903               "Garbage Collection Finish");
 904 }
 905 
 906 static ExpectedContentFrame *get_native_frames(JNIEnv* env, jclass cls,
 907                                                jobjectArray frames) {
 908   ExpectedContentFrame *native_frames;
 909   jsize size = env->GetArrayLength(frames);
 910 
 911   if (env->ExceptionOccurred()) {
 912     env->FatalError("get_native_frames failed with the GetArrayLength call");
 913   }
 914 
 915   native_frames = reinterpret_cast<ExpectedContentFrame*> (malloc(size * sizeof(*native_frames)));
 916 
 917   if (native_frames == nullptr) {
 918     env->FatalError("Error in get_native_frames: malloc returned null\n");
 919   }
 920 
 921   if (fill_native_frames(env, frames, native_frames, size) != 0) {
 922     env->FatalError("Error in get_native_frames: fill_native_frames returned failed status\n");
 923   }
 924 
 925   return native_frames;
 926 }
 927 
 928 JNIEXPORT jboolean JNICALL
 929 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,
 930                                           jobjectArray frames,
 931                                           jboolean check_lines) {
 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, check_lines);
 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 check_lines) {
 947   jboolean result;
 948   jsize size = env->GetArrayLength(frames);
 949   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 950 
 951   result = event_storage_garbage_contains(env, &global_event_storage,
 952                                           native_frames, size, check_lines);
 953 
 954   free(native_frames), native_frames = nullptr;
 955   return result;
 956 }
 957 
 958 JNIEXPORT jlong JNICALL
 959 Java_MyPackage_HeapMonitor_getSize(JNIEnv* env, jclass cls,
 960                                    jobjectArray frames,
 961                                    jboolean check_lines) {
 962   jlong result = 0;
 963   jsize size = env->GetArrayLength(frames);
 964   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 965 
 966   result = event_storage_get_size(env, &global_event_storage,
 967                                   native_frames, size, check_lines);
 968 
 969   free(native_frames), native_frames = nullptr;
 970   return result;
 971 }
 972 
 973 JNIEXPORT void JNICALL
 974 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
 975   check_error(jvmti->ForceGarbageCollection(),
 976               "Forced Garbage Collection");
 977 }
 978 
 979 JNIEXPORT void JNICALL
 980 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 981   event_storage_reset(&global_event_storage);
 982   event_storage_reset(&second_global_event_storage);
 983 }
 984 
 985 JNIEXPORT jboolean JNICALL
 986 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 987                                                                   jclass cls) {
 988   jvmtiCapabilities caps;
 989   memset(&caps, 0, sizeof(caps));
 990   caps.can_generate_sampled_object_alloc_events = 1;
 991   if (check_error(jvmti->RelinquishCapabilities(&caps),
 992                   "Add capabilities\n")){
 993     return FALSE;
 994   }
 995 
 996   if (check_capability_error(jvmti->SetHeapSamplingInterval(1<<19),
 997                              "Set Heap Sampling Interval")) {
 998     return FALSE;
 999   }
1000   return TRUE;
1001 }
1002 
1003 JNIEXPORT jboolean JNICALL
1004 Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env,
1005                                                                   jclass cls) {
1006   if (check_error(jvmti->SetHeapSamplingInterval(0),
1007                   "Sampling interval 0 failed\n")){
1008     return FALSE;
1009   }
1010 
1011   if (check_error(jvmti->SetHeapSamplingInterval(1024),
1012                   "Sampling interval 1024 failed\n")){
1013     return FALSE;
1014   }
1015 
1016   if (!check_error(jvmti->SetHeapSamplingInterval(-1),
1017                    "Sampling interval -1 passed\n")){
1018     return FALSE;
1019   }
1020 
1021   if (!check_error(jvmti->SetHeapSamplingInterval(-1024),
1022                    "Sampling interval -1024 passed\n")){
1023     return FALSE;
1024   }
1025 
1026   return TRUE;
1027 }
1028 
1029 JNIEXPORT jdouble JNICALL
1030 Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {
1031   return event_storage_get_average_size(&global_event_storage);
1032 }
1033 
1034 typedef struct sThreadsFound {
1035   jthread* threads;
1036   int num_threads;
1037 } ThreadsFound;
1038 
1039 JNIEXPORT jboolean JNICALL
1040 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
1041                                                   jint num_threads) {
1042   print_thread_stats();
1043   // Ensure we got stacks from at least num_threads.
1044   return thread_stats.thread_count >= num_threads;
1045 }
1046 
1047 JNIEXPORT
1048 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
1049                                  JNIEnv* jni_env,
1050                                  jthread thread,
1051                                  jobject object,
1052                                  jclass object_klass,
1053                                  jlong size) {
1054   // Nop for now, two agents are not yet implemented.
1055   assert(0);
1056 }
1057 
1058 JNIEXPORT jboolean JNICALL
1059 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
1060     JNIEnv* env, jclass cls) {
1061   // Currently this method should be failing directly at the AddCapability step
1062   // but the implementation is correct for when multi-agent support is enabled.
1063   jvmtiCapabilities caps;
1064   jvmtiEventCallbacks callbacks;
1065 
1066   memset(&caps, 0, sizeof(caps));
1067   caps.can_generate_sampled_object_alloc_events = 1;
1068   if (check_error(second_jvmti->AddCapabilities(&caps),
1069                   "Set the capability for second agent")) {
1070     return FALSE;
1071   }
1072 
1073   memset(&callbacks, 0, sizeof(callbacks));
1074   callbacks.SampledObjectAlloc = &SampledObjectAlloc2;
1075 
1076   if (check_error(second_jvmti->SetEventCallbacks(&callbacks,
1077                                                   sizeof(jvmtiEventCallbacks)),
1078                   " Set Event Callbacks for second agent")) {
1079     return FALSE;
1080   }
1081 
1082   return TRUE;
1083 }
1084 
1085 JNIEXPORT void JNICALL
1086 Java_MyPackage_HeapMonitor_enableVMEvents(JNIEnv* env, jclass cls) {
1087   check_error(jvmti->SetEventNotificationMode(
1088       JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr),
1089               "Set vm event notifications");
1090 }
1091 
1092 JNIEXPORT jint JNICALL
1093 Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) {
1094   return event_storage_number_additions(&second_global_event_storage);
1095 }
1096 
1097 JNIEXPORT jint JNICALL
1098 Java_MyPackage_HeapMonitor_sampledEvents(JNIEnv* env, jclass cls) {
1099   return event_storage_number_additions(&global_event_storage);
1100 }
1101 
1102 static jobject allocate_object(JNIEnv* env) {
1103   // Construct an Object.
1104   jclass cls = env->FindClass("java/lang/Object");
1105   jmethodID constructor;
1106   jobject result;
1107 
1108   if (env->ExceptionOccurred() || cls == nullptr) {
1109     env->FatalError("Error in jni FindClass: Cannot find Object class\n");
1110   }
1111 
1112   constructor = env->GetMethodID(cls, "<init>", "()V");
1113   if (env->ExceptionOccurred() || constructor == nullptr) {
1114     env->FatalError("Error in jni GetMethodID: Cannot find Object class constructor\n");
1115   }
1116 
1117   // Call back constructor to allocate a new instance, with an int argument
1118   result = env->NewObject(cls, constructor);
1119 
1120   if (env->ExceptionOccurred() || result == nullptr) {
1121     env->FatalError("Error in jni NewObject: Cannot allocate an object\n");
1122   }
1123   return result;
1124 }
1125 
1126 // Ensure we got a callback for the test.
1127 static int did_recursive_callback_test;
1128 
1129 JNIEXPORT
1130 void JNICALL RecursiveSampledObjectAlloc(jvmtiEnv *jvmti_env,
1131                                          JNIEnv* jni_env,
1132                                          jthread thread,
1133                                          jobject object,
1134                                          jclass object_klass,
1135                                          jlong size) {
1136   // Basically ensure that if we were to allocate objects, we would not have an
1137   // infinite recursion here.
1138   int i;
1139   for (i = 0; i < 1000; i++) {
1140     if (allocate_object(jni_env) == nullptr) {
1141       jni_env->FatalError("allocate_object returned null\n");
1142     }
1143   }
1144 
1145   did_recursive_callback_test = 1;
1146 }
1147 
1148 JNIEXPORT jboolean JNICALL
1149 Java_MyPackage_HeapMonitorRecursiveTest_didCallback(JNIEnv* env, jclass cls) {
1150   return did_recursive_callback_test != 0;
1151 }
1152 
1153 JNIEXPORT void JNICALL
1154 Java_MyPackage_HeapMonitorRecursiveTest_setCallbackToCallAllocateSomeMore(JNIEnv* env, jclass cls) {
1155   jvmtiEventCallbacks callbacks;
1156 
1157   memset(&callbacks, 0, sizeof(callbacks));
1158   callbacks.SampledObjectAlloc = &RecursiveSampledObjectAlloc;
1159 
1160   if (check_error(jvmti->SetEventCallbacks(&callbacks,
1161                                            sizeof(jvmtiEventCallbacks)),
1162                   "Set Event Callbacks")) {
1163     env->FatalError("Cannot reset the callback.");
1164   }
1165 }
1166 
1167 }