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                                      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   if (jni->IsValueObject(object)) {
 537     // weak references are prohibited for value objects, skip them
 538     return;
 539   }
 540 
 541   err = jvmti->GetStackTrace(thread, 0, 64, frames, &count);
 542   if (err == JVMTI_ERROR_NONE && count >= 1) {
 543     ObjectTrace* live_object;
 544     jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
 545     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 546 
 547     live_object = (ObjectTrace*) malloc(sizeof(*live_object));
 548     live_object->frames = allocated_frames;
 549     live_object->frame_count = count;
 550     live_object->size = size;
 551     live_object->thread = thread;
 552     live_object->object = jni->NewWeakGlobalRef(object);
 553 
 554     if (jni->ExceptionOccurred()) {
 555       jni->FatalError("Error in event_storage_add: Exception in jni NewWeakGlobalRef");
 556     }
 557 
 558     // Only now lock and get things done quickly.
 559     event_storage_lock(storage);
 560 
 561     storage->live_object_additions++;
 562 
 563     if (storage->live_object_count >= storage->live_object_size) {
 564       event_storage_augment_storage(storage);
 565     }
 566     assert(storage->live_object_count < storage->live_object_size);
 567 
 568     if (PRINT_OUT) {
 569       fprintf(stderr, "Adding trace for thread %p, frame_count %d, storage %p\n",
 570               thread, count, storage);
 571       print_out_frames(jni, live_object);
 572     }
 573     storage->live_objects[storage->live_object_count] = live_object;
 574     storage->live_object_count++;
 575 
 576     event_storage_unlock(storage);
 577   }
 578 }
 579 
 580 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
 581   int max, i, dest;
 582   ObjectTrace** live_objects;
 583 
 584   event_storage_lock_compaction(storage);
 585   storage->compaction_required = 0;
 586   event_storage_unlock_compaction(storage);
 587 
 588   event_storage_lock(storage);
 589 
 590   max = storage->live_object_count;
 591   live_objects = storage->live_objects;
 592 
 593   for (i = 0, dest = 0; i < max; i++) {
 594     ObjectTrace* live_object = live_objects[i];
 595     jweak object = live_object->object;
 596 
 597     if (!jni->IsSameObject(object, nullptr)) {
 598       if (dest != i) {
 599         live_objects[dest] = live_object;
 600         dest++;
 601       }
 602     } else {
 603       jni->DeleteWeakGlobalRef(object);
 604       live_object->object = nullptr;
 605 
 606       event_storage_add_garbage_collected_object(storage, live_object);
 607     }
 608   }
 609 
 610   storage->live_object_count = dest;
 611   event_storage_unlock(storage);
 612 }
 613 
 614 static void event_storage_free_objects(ObjectTrace** array, int max) {
 615   int i;
 616   for (i = 0; i < max; i++) {
 617     free(array[i]), array[i] = nullptr;
 618   }
 619 }
 620 
 621 static void event_storage_reset(EventStorage* storage) {
 622   event_storage_lock(storage);
 623 
 624   // Reset everything except the mutex and the garbage collection.
 625   event_storage_free_objects(storage->live_objects,
 626                              storage->live_object_count);
 627   storage->live_object_additions = 0;
 628   storage->live_object_size = 0;
 629   storage->live_object_count = 0;
 630   free(storage->live_objects), storage->live_objects = nullptr;
 631 
 632   event_storage_free_objects(storage->garbage_collected_objects,
 633                              storage->garbage_history_size);
 634 
 635   storage->compaction_required = 0;
 636   storage->garbage_history_index = 0;
 637 
 638   event_storage_unlock(storage);
 639 }
 640 
 641 static int event_storage_number_additions(EventStorage* storage) {
 642   int result;
 643   event_storage_lock(storage);
 644   result = storage->live_object_additions;
 645   event_storage_unlock(storage);
 646   return result;
 647 }
 648 
 649 // Start of the JVMTI agent code.
 650 static const char *EXC_CNAME = "java/lang/Exception";
 651 
 652 static int check_error(jvmtiError err, const char *s) {
 653   if (err != JVMTI_ERROR_NONE) {
 654     printf("  ## %s error: %d\n", s, err);
 655     return 1;
 656   }
 657   return 0;
 658 }
 659 
 660 static int check_capability_error(jvmtiError err, const char *s) {
 661   if (err != JVMTI_ERROR_NONE) {
 662     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 663       return 0;
 664     }
 665     fprintf(stderr, "  ## %s error: %d\n", s, err);
 666   }
 667   return 1;
 668 }
 669 
 670 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 671 
 672 JNIEXPORT
 673 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 674   return Agent_Initialize(jvm, options, reserved);
 675 }
 676 
 677 JNIEXPORT
 678 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 679   return Agent_Initialize(jvm, options, reserved);
 680 }
 681 
 682 JNIEXPORT
 683 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 684   return JNI_VERSION_1_8;
 685 }
 686 
 687 #define MAX_THREADS 500
 688 
 689 typedef struct ThreadStats {
 690   int thread_count;
 691   int counts[MAX_THREADS];
 692   char* threads[MAX_THREADS];
 693 } ThreadStats;
 694 
 695 static ThreadStats thread_stats;
 696 
 697 JNIEXPORT jboolean JNICALL
 698 Java_MyPackage_HeapMonitorThreadDisabledTest_checkThreadSamplesOnlyFrom(
 699     JNIEnv* env, jclass cls, jthread thread) {
 700   jvmtiThreadInfo info;
 701   jvmtiError err;
 702   char* expected_name;
 703   int found_thread = FALSE;
 704 
 705   err = jvmti->GetThreadInfo(thread, &info);
 706   expected_name = info.name;
 707 
 708   if (err != JVMTI_ERROR_NONE) {
 709     fprintf(stderr, "Failed to get thread information\n");
 710     return FALSE;
 711   }
 712 
 713   if (thread_stats.thread_count != 1) {
 714     fprintf(stderr, "Wrong thread number: %d (expected 1)\n",
 715             thread_stats.thread_count);
 716     return FALSE;
 717   }
 718 
 719   if (strcmp(expected_name, thread_stats.threads[0]) != 0) {
 720     fprintf(stderr, "Unexpected thread name: '%s' (expected '%s')\n",
 721             thread_stats.threads[0], expected_name);
 722     return FALSE;
 723   }
 724 
 725   return TRUE;
 726 }
 727 
 728 static void add_thread_count(jthread thread) {
 729   int i;
 730   jvmtiThreadInfo info;
 731   jvmtiError err;
 732 
 733   err = jvmti->GetThreadInfo(thread, &info);
 734   if (err != JVMTI_ERROR_NONE) {
 735     fprintf(stderr, "Thread info for %p failed, ignoring thread count\n",
 736             thread);
 737     return;
 738   }
 739 
 740   event_storage_lock(&global_event_storage);
 741   for (i = 0; i < thread_stats.thread_count; i++) {
 742     if (!strcmp(thread_stats.threads[i], info.name)) {
 743       thread_stats.counts[i]++;
 744       event_storage_unlock(&global_event_storage);
 745       return;
 746     }
 747   }
 748 
 749   thread_stats.threads[thread_stats.thread_count] = info.name;
 750   thread_stats.counts[thread_stats.thread_count]++;
 751   thread_stats.thread_count++;
 752   event_storage_unlock(&global_event_storage);
 753 }
 754 
 755 JNIEXPORT void JNICALL
 756 Java_MyPackage_HeapMonitorThreadDisabledTest_enableSamplingEvents(
 757     JNIEnv* env, jclass cls, jthread thread) {
 758   fprintf(stderr, "Enabling for %p\n", thread);
 759   check_error(jvmti->SetEventNotificationMode(
 760       JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, thread),
 761               "Set event notifications for a single thread");
 762 }
 763 
 764 static void print_thread_stats() {
 765   int i;
 766   event_storage_lock(&global_event_storage);
 767   fprintf(stderr, "Thread count:\n");
 768   for (i = 0; i < thread_stats.thread_count; i++) {
 769     fprintf(stderr, "\t%s: %d\n", thread_stats.threads[i], thread_stats.counts[i]);
 770   }
 771   event_storage_unlock(&global_event_storage);
 772 }
 773 
 774 JNIEXPORT
 775 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 776                                 JNIEnv* jni_env,
 777                                 jthread thread,
 778                                 jobject object,
 779                                 jclass object_klass,
 780                                 jlong size) {
 781   add_thread_count(thread);
 782 
 783   if (event_storage_get_compaction_required(&global_event_storage)) {
 784     event_storage_compact(&global_event_storage, jni_env);
 785   }
 786 
 787   event_storage_add(&global_event_storage, jni_env, thread, object,
 788                     object_klass, size);
 789 }
 790 
 791 JNIEXPORT
 792 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
 793                            JNIEnv* jni_env,
 794                            jthread thread,
 795                            jobject object,
 796                            jclass object_klass,
 797                            jlong size) {
 798   event_storage_add(&second_global_event_storage, jni_env, thread, object,
 799                     object_klass, size);
 800 }
 801 
 802 JNIEXPORT
 803 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
 804   event_storage_set_compaction_required(&global_event_storage);
 805 }
 806 
 807 static int enable_notifications() {
 808   if (check_error(jvmti->SetEventNotificationMode(
 809       JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr),
 810                      "Set event notifications")) {
 811     return 1;
 812   }
 813 
 814   return check_error(jvmti->SetEventNotificationMode(
 815       JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr),
 816                      "Set event notifications");
 817 }
 818 
 819 static
 820 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 821   jint res;
 822   jvmtiEventCallbacks callbacks;
 823   jvmtiCapabilities caps;
 824 
 825   res = jvm->GetEnv((void **) &jvmti, JVMTI_VERSION);
 826   if (res != JNI_OK || jvmti == nullptr) {
 827     fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
 828     return JNI_ERR;
 829   }
 830 
 831   // Get second jvmti environment.
 832   res = jvm->GetEnv((void **) &second_jvmti, JVMTI_VERSION);
 833   if (res != JNI_OK || second_jvmti == nullptr) {
 834     fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
 835     return JNI_ERR;
 836   }
 837 
 838   if (PRINT_OUT) {
 839     fprintf(stderr, "Storage is at %p, secondary is at %p\n",
 840             &global_event_storage, &second_global_event_storage);
 841   }
 842 
 843   jvmti->CreateRawMonitor("storage_monitor",
 844                              &global_event_storage.storage_monitor);
 845   jvmti->CreateRawMonitor("second_storage_monitor",
 846                              &second_global_event_storage.storage_monitor);
 847 
 848   jvmti->CreateRawMonitor("compaction_monitor",
 849                              &global_event_storage.compaction_monitor);
 850   jvmti->CreateRawMonitor("second_compaction_monitor",
 851                              &second_global_event_storage.compaction_monitor);
 852 
 853   event_storage_set_garbage_history(&global_event_storage, 200);
 854   event_storage_set_garbage_history(&second_global_event_storage, 200);
 855 
 856   memset(&callbacks, 0, sizeof(callbacks));
 857   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 858   callbacks.VMObjectAlloc = &VMObjectAlloc;
 859   callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
 860 
 861   memset(&caps, 0, sizeof(caps));
 862   // Get line numbers, sample events, filename, and gc events for the tests.
 863   caps.can_get_line_numbers = 1;
 864   caps.can_get_source_file_name = 1;
 865   caps.can_generate_garbage_collection_events = 1;
 866   caps.can_generate_sampled_object_alloc_events = 1;
 867   caps.can_generate_vm_object_alloc_events = 1;
 868   if (check_error(jvmti->AddCapabilities(&caps), "Add capabilities")) {
 869     return JNI_ERR;
 870   }
 871 
 872   if (check_error(jvmti->SetEventCallbacks(&callbacks,
 873                                            sizeof(jvmtiEventCallbacks)),
 874                   " Set Event Callbacks")) {
 875     return JNI_ERR;
 876   }
 877   return JNI_OK;
 878 }
 879 
 880 JNIEXPORT void JNICALL
 881 Java_MyPackage_HeapMonitor_setSamplingInterval(JNIEnv* env, jclass cls, jint value) {
 882   jvmti->SetHeapSamplingInterval(value);
 883 }
 884 
 885 JNIEXPORT jboolean JNICALL
 886 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 887   return event_storage_get_count(&global_event_storage) == 0;
 888 }
 889 
 890 JNIEXPORT jint JNICALL
 891 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
 892   return event_storage_get_count(&global_event_storage);
 893 }
 894 
 895 JNIEXPORT void JNICALL
 896 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 897   enable_notifications();
 898 }
 899 
 900 JNIEXPORT void JNICALL
 901 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 902   check_error(jvmti->SetEventNotificationMode(
 903       JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, nullptr),
 904               "Set event notifications");
 905 
 906   check_error(jvmti->SetEventNotificationMode(
 907       JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, nullptr),
 908               "Garbage Collection Finish");
 909 }
 910 
 911 static ExpectedContentFrame *get_native_frames(JNIEnv* env, jclass cls,
 912                                                jobjectArray frames) {
 913   ExpectedContentFrame *native_frames;
 914   jsize size = env->GetArrayLength(frames);
 915 
 916   if (env->ExceptionOccurred()) {
 917     env->FatalError("get_native_frames failed with the GetArrayLength call");
 918   }
 919 
 920   native_frames = reinterpret_cast<ExpectedContentFrame*> (malloc(size * sizeof(*native_frames)));
 921 
 922   if (native_frames == nullptr) {
 923     env->FatalError("Error in get_native_frames: malloc returned null\n");
 924   }
 925 
 926   if (fill_native_frames(env, frames, native_frames, size) != 0) {
 927     env->FatalError("Error in get_native_frames: fill_native_frames returned failed status\n");
 928   }
 929 
 930   return native_frames;
 931 }
 932 
 933 JNIEXPORT jboolean JNICALL
 934 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls,
 935                                           jobjectArray frames,
 936                                           jboolean check_lines) {
 937   jboolean result;
 938   jsize size = env->GetArrayLength(frames);
 939   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 940 
 941   result = event_storage_contains(env, &global_event_storage, native_frames,
 942                                   size, check_lines);
 943 
 944   free(native_frames), native_frames = nullptr;
 945   return result;
 946 }
 947 
 948 JNIEXPORT jboolean JNICALL
 949 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls,
 950                                            jobjectArray frames,
 951                                            jboolean check_lines) {
 952   jboolean result;
 953   jsize size = env->GetArrayLength(frames);
 954   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 955 
 956   result = event_storage_garbage_contains(env, &global_event_storage,
 957                                           native_frames, size, check_lines);
 958 
 959   free(native_frames), native_frames = nullptr;
 960   return result;
 961 }
 962 
 963 JNIEXPORT jlong JNICALL
 964 Java_MyPackage_HeapMonitor_getSize(JNIEnv* env, jclass cls,
 965                                    jobjectArray frames,
 966                                    jboolean check_lines) {
 967   jlong result = 0;
 968   jsize size = env->GetArrayLength(frames);
 969   ExpectedContentFrame *native_frames = get_native_frames(env, cls, frames);
 970 
 971   result = event_storage_get_size(env, &global_event_storage,
 972                                   native_frames, size, check_lines);
 973 
 974   free(native_frames), native_frames = nullptr;
 975   return result;
 976 }
 977 
 978 JNIEXPORT void JNICALL
 979 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
 980   check_error(jvmti->ForceGarbageCollection(),
 981               "Forced Garbage Collection");
 982 }
 983 
 984 JNIEXPORT void JNICALL
 985 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 986   event_storage_reset(&global_event_storage);
 987   event_storage_reset(&second_global_event_storage);
 988 }
 989 
 990 JNIEXPORT jboolean JNICALL
 991 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 992                                                                   jclass cls) {
 993   jvmtiCapabilities caps;
 994   memset(&caps, 0, sizeof(caps));
 995   caps.can_generate_sampled_object_alloc_events = 1;
 996   if (check_error(jvmti->RelinquishCapabilities(&caps),
 997                   "Add capabilities\n")){
 998     return FALSE;
 999   }
1000 
1001   if (check_capability_error(jvmti->SetHeapSamplingInterval(1<<19),
1002                              "Set Heap Sampling Interval")) {
1003     return FALSE;
1004   }
1005   return TRUE;
1006 }
1007 
1008 JNIEXPORT jboolean JNICALL
1009 Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env,
1010                                                                   jclass cls) {
1011   if (check_error(jvmti->SetHeapSamplingInterval(0),
1012                   "Sampling interval 0 failed\n")){
1013     return FALSE;
1014   }
1015 
1016   if (check_error(jvmti->SetHeapSamplingInterval(1024),
1017                   "Sampling interval 1024 failed\n")){
1018     return FALSE;
1019   }
1020 
1021   if (!check_error(jvmti->SetHeapSamplingInterval(-1),
1022                    "Sampling interval -1 passed\n")){
1023     return FALSE;
1024   }
1025 
1026   if (!check_error(jvmti->SetHeapSamplingInterval(-1024),
1027                    "Sampling interval -1024 passed\n")){
1028     return FALSE;
1029   }
1030 
1031   return TRUE;
1032 }
1033 
1034 JNIEXPORT jdouble JNICALL
1035 Java_MyPackage_HeapMonitor_getAverageSize(JNIEnv *env, jclass cls) {
1036   return event_storage_get_average_size(&global_event_storage);
1037 }
1038 
1039 typedef struct sThreadsFound {
1040   jthread* threads;
1041   int num_threads;
1042 } ThreadsFound;
1043 
1044 JNIEXPORT jboolean JNICALL
1045 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
1046                                                   jint num_threads) {
1047   print_thread_stats();
1048   // Ensure we got stacks from at least num_threads.
1049   return thread_stats.thread_count >= num_threads;
1050 }
1051 
1052 JNIEXPORT
1053 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
1054                                  JNIEnv* jni_env,
1055                                  jthread thread,
1056                                  jobject object,
1057                                  jclass object_klass,
1058                                  jlong size) {
1059   // Nop for now, two agents are not yet implemented.
1060   assert(0);
1061 }
1062 
1063 JNIEXPORT jboolean JNICALL
1064 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
1065     JNIEnv* env, jclass cls) {
1066   // Currently this method should be failing directly at the AddCapability step
1067   // but the implementation is correct for when multi-agent support is enabled.
1068   jvmtiCapabilities caps;
1069   jvmtiEventCallbacks callbacks;
1070 
1071   memset(&caps, 0, sizeof(caps));
1072   caps.can_generate_sampled_object_alloc_events = 1;
1073   if (check_error(second_jvmti->AddCapabilities(&caps),
1074                   "Set the capability for second agent")) {
1075     return FALSE;
1076   }
1077 
1078   memset(&callbacks, 0, sizeof(callbacks));
1079   callbacks.SampledObjectAlloc = &SampledObjectAlloc2;
1080 
1081   if (check_error(second_jvmti->SetEventCallbacks(&callbacks,
1082                                                   sizeof(jvmtiEventCallbacks)),
1083                   " Set Event Callbacks for second agent")) {
1084     return FALSE;
1085   }
1086 
1087   return TRUE;
1088 }
1089 
1090 JNIEXPORT void JNICALL
1091 Java_MyPackage_HeapMonitor_enableVMEvents(JNIEnv* env, jclass cls) {
1092   check_error(jvmti->SetEventNotificationMode(
1093       JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, nullptr),
1094               "Set vm event notifications");
1095 }
1096 
1097 JNIEXPORT jint JNICALL
1098 Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) {
1099   return event_storage_number_additions(&second_global_event_storage);
1100 }
1101 
1102 JNIEXPORT jint JNICALL
1103 Java_MyPackage_HeapMonitor_sampledEvents(JNIEnv* env, jclass cls) {
1104   return event_storage_number_additions(&global_event_storage);
1105 }
1106 
1107 static jobject allocate_object(JNIEnv* env) {
1108   // Construct an Object.
1109   jclass cls = env->FindClass("java/lang/Object");
1110   jmethodID constructor;
1111   jobject result;
1112 
1113   if (env->ExceptionOccurred() || cls == nullptr) {
1114     env->FatalError("Error in jni FindClass: Cannot find Object class\n");
1115   }
1116 
1117   constructor = env->GetMethodID(cls, "<init>", "()V");
1118   if (env->ExceptionOccurred() || constructor == nullptr) {
1119     env->FatalError("Error in jni GetMethodID: Cannot find Object class constructor\n");
1120   }
1121 
1122   // Call back constructor to allocate a new instance, with an int argument
1123   result = env->NewObject(cls, constructor);
1124 
1125   if (env->ExceptionOccurred() || result == nullptr) {
1126     env->FatalError("Error in jni NewObject: Cannot allocate an object\n");
1127   }
1128   return result;
1129 }
1130 
1131 // Ensure we got a callback for the test.
1132 static int did_recursive_callback_test;
1133 
1134 JNIEXPORT
1135 void JNICALL RecursiveSampledObjectAlloc(jvmtiEnv *jvmti_env,
1136                                          JNIEnv* jni_env,
1137                                          jthread thread,
1138                                          jobject object,
1139                                          jclass object_klass,
1140                                          jlong size) {
1141   // Basically ensure that if we were to allocate objects, we would not have an
1142   // infinite recursion here.
1143   int i;
1144   for (i = 0; i < 1000; i++) {
1145     if (allocate_object(jni_env) == nullptr) {
1146       jni_env->FatalError("allocate_object returned null\n");
1147     }
1148   }
1149 
1150   did_recursive_callback_test = 1;
1151 }
1152 
1153 JNIEXPORT jboolean JNICALL
1154 Java_MyPackage_HeapMonitorRecursiveTest_didCallback(JNIEnv* env, jclass cls) {
1155   return did_recursive_callback_test != 0;
1156 }
1157 
1158 JNIEXPORT void JNICALL
1159 Java_MyPackage_HeapMonitorRecursiveTest_setCallbackToCallAllocateSomeMore(JNIEnv* env, jclass cls) {
1160   jvmtiEventCallbacks callbacks;
1161 
1162   memset(&callbacks, 0, sizeof(callbacks));
1163   callbacks.SampledObjectAlloc = &RecursiveSampledObjectAlloc;
1164 
1165   if (check_error(jvmti->SetEventCallbacks(&callbacks,
1166                                            sizeof(jvmtiEventCallbacks)),
1167                   "Set Event Callbacks")) {
1168     env->FatalError("Cannot reset the callback.");
1169   }
1170 }
1171 
1172 }