1 /*
   2  * Copyright (c) 2018, Google and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 #include <assert.h>
  25 #include <pthread.h>
  26 #include <stdio.h>
  27 #include <stdlib.h>
  28 #include <string.h>
  29 #include "jvmti.h"
  30 
  31 #ifdef __cplusplus
  32 extern "C" {
  33 #endif
  34 
  35 #ifndef JNI_ENV_ARG
  36 
  37 #ifdef __cplusplus
  38 #define JNI_ENV_ARG(x, y) y
  39 #define JNI_ENV_PTR(x) x
  40 #else
  41 #define JNI_ENV_ARG(x,y) x, y
  42 #define JNI_ENV_PTR(x) (*x)
  43 #endif
  44 
  45 #endif
  46 
  47 #define TRUE 1
  48 #define FALSE 0
  49 #define PRINT_OUT 1
  50 #define MAX_TRACES 400
  51 
  52 static jvmtiEnv *jvmti = NULL;
  53 static jvmtiEnv *second_jvmti = NULL;
  54 
  55 typedef struct _ObjectTrace{
  56   jweak object;
  57   size_t size;
  58   jvmtiFrameInfo* frames;
  59   size_t frame_count;
  60   jthread thread;
  61 } ObjectTrace;
  62 
  63 typedef struct _EventStorage {
  64   int live_object_additions;
  65   int live_object_size;
  66   int live_object_count;
  67   ObjectTrace** live_objects;
  68 
  69   int garbage_history_size;
  70   int garbage_history_index;
  71   ObjectTrace** garbage_collected_objects;
  72 
  73   // Two separate mutexes to separate storage data race and the compaction field
  74   // data race.
  75   pthread_mutex_t storage_mutex;
  76 
  77   int compaction_required;
  78   pthread_mutex_t compaction_mutex;
  79 } EventStorage;
  80 
  81 typedef struct _ExpectedContentFrame {
  82   const char *name;
  83   const char *signature;
  84   const char *file_name;
  85   int line_number;
  86 } ExpectedContentFrame;
  87 
  88 // Given a method and a location, this method gets the line number.
  89 static
  90 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
  91                      jlocation location) {
  92   // Read the line number table.
  93   jvmtiLineNumberEntry *table_ptr = 0;
  94   jint line_number_table_entries;
  95   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
  96                                                  &line_number_table_entries,
  97                                                  &table_ptr);
  98 
  99   if (JVMTI_ERROR_NONE != jvmti_error) {
 100     return -1;
 101   }
 102   if (line_number_table_entries <= 0) {
 103     return -1;
 104   }
 105   if (line_number_table_entries == 1) {
 106     return table_ptr[0].line_number;
 107   }
 108 
 109   // Go through all the line numbers...
 110   jint last_location = table_ptr[0].start_location;
 111   int l;
 112   for (l = 1; l < line_number_table_entries; l++) {
 113     // ... and if you see one that is in the right place for your
 114     // location, you've found the line number!
 115     if ((location < table_ptr[l].start_location) &&
 116         (location >= last_location)) {
 117       return table_ptr[l - 1].line_number;
 118     }
 119     last_location = table_ptr[l].start_location;
 120   }
 121 
 122   if (location >= last_location) {
 123     return table_ptr[line_number_table_entries - 1].line_number;
 124   } else {
 125     return -1;
 126   }
 127 }
 128 
 129 static jboolean check_sample_content(JNIEnv *env,
 130                                      ObjectTrace* trace,
 131                                      ExpectedContentFrame *expected,
 132                                      size_t expected_count,
 133                                      int print_out_comparisons) {
 134   if (expected_count > trace->frame_count) {
 135     return FALSE;
 136   }
 137 
 138   jvmtiFrameInfo* frames = trace->frames;
 139 
 140   size_t i;
 141   for (i = 0; i < expected_count; i++) {
 142     // Get basic information out of the trace.
 143     int bci = frames[i].location;
 144     jmethodID methodid = frames[i].method;
 145     char *name = NULL, *signature = NULL, *file_name = NULL;
 146 
 147     if (bci < 0 && expected[i].line_number != -1) {
 148       return FALSE;
 149     }
 150 
 151     // Transform into usable information.
 152     int line_number = get_line_number(jvmti, methodid, bci);
 153     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 154 
 155     jclass declaring_class;
 156     if (JVMTI_ERROR_NONE !=
 157         (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
 158       return FALSE;
 159     }
 160 
 161     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
 162                                                  &file_name);
 163     if (err != JVMTI_ERROR_NONE) {
 164       return FALSE;
 165     }
 166 
 167     // Compare now, none should be NULL.
 168     if (name == NULL) {
 169       return FALSE;
 170     }
 171 
 172     if (file_name == NULL) {
 173       return FALSE;
 174     }
 175 
 176     if (signature == NULL) {
 177       return FALSE;
 178     }
 179 
 180     if (print_out_comparisons) {
 181       fprintf(stderr, "\tComparing:\n");
 182       fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
 183       fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
 184       fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
 185       fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
 186       fprintf(stderr, "\t\tResult is %d\n",
 187               (strcmp(name, expected[i].name) ||
 188                strcmp(signature, expected[i].signature) ||
 189                strcmp(file_name, expected[i].file_name) ||
 190                line_number != expected[i].line_number));
 191     }
 192 
 193     if (strcmp(name, expected[i].name) ||
 194         strcmp(signature, expected[i].signature) ||
 195         strcmp(file_name, expected[i].file_name) ||
 196         line_number != expected[i].line_number) {
 197       return FALSE;
 198     }
 199   }
 200 
 201   return TRUE;
 202 }
 203 
 204 // Static native API for various tests.
 205 static void fill_native_frames(JNIEnv* env, jobjectArray frames,
 206                                ExpectedContentFrame* native_frames, size_t size) {
 207   size_t i;
 208   for (i = 0; i < size; i++) {
 209     jobject obj = (*env)->GetObjectArrayElement(env, frames, i);
 210     jclass frame_class = (*env)->GetObjectClass(env, obj);
 211     jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class,
 212                                                        "lineNumber", "I");
 213     int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
 214 
 215     jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method",
 216                                             "Ljava/lang/String;");
 217     jstring string_object = (jstring) (*env)->GetObjectField(env, obj,
 218                                                              string_id);
 219     const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
 220 
 221     string_id = (*env)->GetFieldID(env, frame_class, "fileName",
 222                                    "Ljava/lang/String;");
 223     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 224     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 225 
 226     string_id = (*env)->GetFieldID(env, frame_class, "signature",
 227                                    "Ljava/lang/String;");
 228     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 229     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 230 
 231     native_frames[i].name = method;
 232     native_frames[i].file_name = file_name;
 233     native_frames[i].signature = signature;
 234     native_frames[i].line_number = line_number;
 235   }
 236 }
 237 
 238 // Internal storage system implementation.
 239 
 240 static EventStorage global_event_storage;
 241 static EventStorage second_global_event_storage;
 242 
 243 static void event_storage_set_compaction_required(EventStorage* storage) {
 244   pthread_mutex_lock(&storage->compaction_mutex);
 245   storage->compaction_required = 1;
 246   pthread_mutex_unlock(&storage->compaction_mutex);
 247 }
 248 
 249 static int event_storage_get_compaction_required(EventStorage* storage) {
 250   pthread_mutex_lock(&storage->compaction_mutex);
 251   int result = storage->compaction_required;
 252   pthread_mutex_unlock(&storage->compaction_mutex);
 253   return result;
 254 }
 255 
 256 static void event_storage_set_garbage_history(EventStorage* storage, int value) {
 257   pthread_mutex_lock(&storage->storage_mutex);
 258   global_event_storage.garbage_history_size = value;
 259   free(global_event_storage.garbage_collected_objects);
 260   size_t size =
 261       sizeof(*global_event_storage.garbage_collected_objects) * value;
 262   global_event_storage.garbage_collected_objects = malloc(size);
 263   memset(global_event_storage.garbage_collected_objects, 0, size);
 264   pthread_mutex_unlock(&storage->storage_mutex);
 265 }
 266 
 267 // No mutex here, it is handled by the caller.
 268 static void event_storage_add_garbage_collected_object(EventStorage* storage,
 269                                                        ObjectTrace* object) {
 270   int idx = storage->garbage_history_index;
 271   free(storage->garbage_collected_objects[idx]);
 272   storage->garbage_collected_objects[idx] = object;
 273   storage->garbage_history_index = (idx + 1) % storage->garbage_history_size;
 274 }
 275 
 276 static int event_storage_get_count(EventStorage* storage) {
 277   pthread_mutex_lock(&storage->storage_mutex);
 278   int result = storage->live_object_count;
 279   pthread_mutex_unlock(&storage->storage_mutex);
 280   return result;
 281 }
 282 
 283 static double event_storage_get_average_rate(EventStorage* storage) {
 284   double accumulation = 0;
 285 
 286   pthread_mutex_lock(&storage->storage_mutex);
 287   int max_size = storage->live_object_count;
 288 
 289   int i;
 290   for (i = 0; i < max_size; i++) {
 291     accumulation += storage->live_objects[i]->size;
 292   }
 293   pthread_mutex_unlock(&storage->storage_mutex);
 294   return accumulation / max_size;
 295 }
 296 
 297 static jboolean event_storage_contains(JNIEnv* env,
 298                                        EventStorage* storage,
 299                                        ExpectedContentFrame* frames,
 300                                        size_t size) {
 301   pthread_mutex_lock(&storage->storage_mutex);
 302   fprintf(stderr, "Checking storage count %d\n", storage->live_object_count);
 303   int i;
 304   for (i = 0; i < storage->live_object_count; i++) {
 305     ObjectTrace* trace = storage->live_objects[i];
 306 
 307     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 308       pthread_mutex_unlock(&storage->storage_mutex);
 309       return TRUE;
 310     }
 311   }
 312   pthread_mutex_unlock(&storage->storage_mutex);
 313   return FALSE;
 314 }
 315 
 316 static jboolean event_storage_garbage_contains(JNIEnv* env,
 317                                                EventStorage* storage,
 318                                                ExpectedContentFrame* frames,
 319                                                size_t size) {
 320   pthread_mutex_lock(&storage->storage_mutex);
 321   fprintf(stderr, "Checking garbage storage count %d\n",
 322           storage->garbage_history_size);
 323   int i;
 324   for (i = 0; i < storage->garbage_history_size; i++) {
 325     ObjectTrace* trace = storage->garbage_collected_objects[i];
 326 
 327     if (trace == NULL) {
 328       continue;
 329     }
 330 
 331     if (check_sample_content(env, trace, frames, size, PRINT_OUT)) {
 332       pthread_mutex_unlock(&storage->storage_mutex);
 333       return TRUE;
 334     }
 335   }
 336   pthread_mutex_unlock(&storage->storage_mutex);
 337   return FALSE;
 338 }
 339 
 340 // No mutex here, handled by the caller.
 341 static void event_storage_augment_storage(EventStorage* storage) {
 342   int new_max = (storage->live_object_size * 2) + 1;
 343   ObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
 344 
 345   int current_count = storage->live_object_count;
 346   memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 347   free(storage->live_objects);
 348   storage->live_objects = new_objects;
 349 
 350   storage->live_object_size = new_max;
 351 }
 352 
 353 static void event_storage_add(EventStorage* storage,
 354                               JNIEnv* jni,
 355                               jthread thread,
 356                               jobject object,
 357                               jclass klass,
 358                               jlong size) {
 359   jvmtiFrameInfo frames[64];
 360   jint count;
 361   jvmtiError err;
 362 
 363   err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
 364   if (err == JVMTI_ERROR_NONE && count >= 1) {
 365     jvmtiFrameInfo* allocated_frames = (jvmtiFrameInfo*) malloc(count * sizeof(*allocated_frames));
 366     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 367 
 368     ObjectTrace* live_object = (ObjectTrace*) malloc(sizeof(*live_object));
 369     live_object->frames = allocated_frames;
 370     live_object->frame_count = count;
 371     live_object->size = size;
 372     live_object->thread = thread;
 373     live_object->object = (*jni)->NewWeakGlobalRef(jni, object);
 374 
 375     // Only now lock and get things done quickly.
 376     pthread_mutex_lock(&storage->storage_mutex);
 377 
 378     storage->live_object_additions++;
 379 
 380     if (storage->live_object_count >= storage->live_object_size) {
 381       event_storage_augment_storage(storage);
 382     }
 383     assert(storage->live_object_count < storage->live_object_size);
 384 
 385     storage->live_objects[storage->live_object_count] = live_object;
 386     storage->live_object_count++;
 387 
 388     pthread_mutex_unlock(&storage->storage_mutex);
 389   }
 390 }
 391 
 392 static void event_storage_compact(EventStorage* storage, JNIEnv* jni) {
 393   pthread_mutex_lock(&storage->compaction_mutex);
 394   storage->compaction_required = 0;
 395   pthread_mutex_unlock(&storage->compaction_mutex);
 396 
 397   pthread_mutex_lock(&storage->storage_mutex);
 398 
 399   int max = storage->live_object_count;
 400   int i, dest;
 401   ObjectTrace** live_objects = storage->live_objects;
 402 
 403   for (i = 0, dest = 0; i < max; i++) {
 404     ObjectTrace* live_object = live_objects[i];
 405     jweak object = live_object->object;
 406 
 407     if (!(*jni)->IsSameObject(jni, object, NULL)) {
 408       if (dest != i) {
 409         live_objects[dest] = live_object;
 410         dest++;
 411       }
 412     } else {
 413       event_storage_add_garbage_collected_object(storage, live_object);
 414     }
 415   }
 416 
 417   storage->live_object_count = dest;
 418   pthread_mutex_unlock(&storage->storage_mutex);
 419 }
 420 
 421 static void event_storage_free_objects(ObjectTrace** array, int max) {
 422   int i;
 423   for (i = 0; i < max; i++) {
 424     free(array[i]), array[i] = NULL;
 425   }
 426 }
 427 
 428 static void event_storage_reset(EventStorage* storage) {
 429   pthread_mutex_lock(&storage->storage_mutex);
 430 
 431   // Reset everything except the mutex and the garbage collection.
 432   event_storage_free_objects(storage->live_objects,
 433                              storage->live_object_count);
 434   storage->live_object_additions = 0;
 435   storage->live_object_size = 0;
 436   storage->live_object_count = 0;
 437   free(storage->live_objects), storage->live_objects = NULL;
 438 
 439   event_storage_free_objects(storage->garbage_collected_objects,
 440                              storage->garbage_history_size);
 441 
 442   storage->compaction_required = 0;
 443   storage->garbage_history_index = 0;
 444 
 445   pthread_mutex_unlock(&storage->storage_mutex);
 446 }
 447 
 448 static int event_storage_number_additions(EventStorage* storage) {
 449   pthread_mutex_lock(&storage->storage_mutex);
 450   int result = storage->live_object_additions;
 451   pthread_mutex_unlock(&storage->storage_mutex);
 452   return result;
 453 }
 454 
 455 // Start of the JVMTI agent code.
 456 
 457 static const char *EXC_CNAME = "java/lang/Exception";
 458 
 459 static int check_error(jvmtiError err, const char *s) {
 460   if (err != JVMTI_ERROR_NONE) {
 461     printf("  ## %s error: %d\n", s, err);
 462     return 1;
 463   }
 464   return 0;
 465 }
 466 
 467 static int check_capability_error(jvmtiError err, const char *s) {
 468   if (err != JVMTI_ERROR_NONE) {
 469     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 470       return 0;
 471     }
 472     printf("  ## %s error: %d\n", s, err);
 473     return 1;
 474   }
 475   return 1;
 476 }
 477 
 478 static
 479 jint throw_exc(JNIEnv *env, char *msg) {
 480   jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
 481 
 482   if (exc_class == NULL) {
 483     printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
 484     return -1;
 485   }
 486   return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
 487 }
 488 
 489 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 490 
 491 JNIEXPORT
 492 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 493   return Agent_Initialize(jvm, options, reserved);
 494 }
 495 
 496 JNIEXPORT
 497 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 498   return Agent_Initialize(jvm, options, reserved);
 499 }
 500 
 501 JNIEXPORT
 502 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 503   return JNI_VERSION_1_8;
 504 }
 505 
 506 JNIEXPORT
 507 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 508                                 JNIEnv* jni_env,
 509                                 jthread thread,
 510                                 jobject object,
 511                                 jclass object_klass,
 512                                 jlong size) {
 513   if (event_storage_get_compaction_required(&global_event_storage)) {
 514     event_storage_compact(&global_event_storage, jni_env);
 515   }
 516 
 517   jvmtiThreadInfo first_info;
 518   event_storage_add(&global_event_storage, jni_env, thread, object,
 519                     object_klass, size);
 520 }
 521 
 522 JNIEXPORT
 523 void JNICALL VMObjectAlloc(jvmtiEnv *jvmti_env,
 524                            JNIEnv* jni_env,
 525                            jthread thread,
 526                            jobject object,
 527                            jclass object_klass,
 528                            jlong size) {
 529   event_storage_add(&second_global_event_storage, jni_env, thread, object,
 530                     object_klass, size);
 531 }
 532 
 533 JNIEXPORT
 534 void JNICALL GarbageCollectionFinish(jvmtiEnv *jvmti_env) {
 535   event_storage_set_compaction_required(&global_event_storage);
 536 }
 537 
 538 static int enable_notifications() {
 539   if (check_error((*jvmti)->SetEventNotificationMode(
 540       jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 541                      "Set event notifications")) {
 542     return 1;
 543   }
 544 
 545   return check_error((*jvmti)->SetEventNotificationMode(
 546       jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 547                      "Set event notifications");
 548 }
 549 
 550 static int enable_notifications_for_two_threads(jthread first, jthread second) {
 551   if (check_error((*jvmti)->SetEventNotificationMode(
 552       jvmti, JVMTI_ENABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 553                            "Set event notifications")) {
 554     return 0;
 555   }
 556 
 557   if (check_error((*jvmti)->SetEventNotificationMode(
 558       jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, first),
 559                   "Set event notifications")) {
 560     return 0;
 561   }
 562 
 563   // Second thread should fail.
 564   if (check_error((*jvmti)->SetEventNotificationMode(
 565       jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, second),
 566                   "Set event notifications")) {
 567     return 0;
 568   }
 569 
 570   return 1;
 571 }
 572 
 573 static
 574 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 575   jint res;
 576 
 577   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 578                                  JVMTI_VERSION_9);
 579   if (res != JNI_OK || jvmti == NULL) {
 580     fprintf(stderr, "Error: wrong result of a valid call to GetEnv!\n");
 581     return JNI_ERR;
 582   }
 583 
 584   // Get second jvmti environment.
 585   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &second_jvmti),
 586                                  JVMTI_VERSION_9);
 587   if (res != JNI_OK || second_jvmti == NULL) {
 588     fprintf(stderr, "Error: wrong result of a valid second call to GetEnv!\n");
 589     return JNI_ERR;
 590   }
 591 
 592   pthread_mutex_init(&global_event_storage.storage_mutex, 0);
 593   pthread_mutex_init(&global_event_storage.compaction_mutex, 0);
 594   event_storage_set_garbage_history(&global_event_storage, 200);
 595 
 596   pthread_mutex_init(&second_global_event_storage.storage_mutex, 0);
 597   pthread_mutex_init(&second_global_event_storage.compaction_mutex, 0);
 598   event_storage_set_garbage_history(&second_global_event_storage, 200);
 599 
 600   jvmtiEventCallbacks callbacks;
 601   memset(&callbacks, 0, sizeof(callbacks));
 602   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 603   callbacks.VMObjectAlloc = &VMObjectAlloc;
 604   callbacks.GarbageCollectionFinish = &GarbageCollectionFinish;
 605 
 606   jvmtiCapabilities caps;
 607   memset(&caps, 0, sizeof(caps));
 608   // Get line numbers, sample events, filename, and gc events for the tests.
 609   caps.can_get_line_numbers = 1;
 610   caps.can_generate_sampled_alloc_events = 1;
 611   caps.can_generate_vm_object_alloc_events = 1;
 612   caps.can_get_source_file_name = 1;
 613   caps.can_generate_garbage_collection_events = 1;
 614   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps), "Add capabilities")) {
 615     return JNI_ERR;
 616   }
 617 
 618   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 619                                               sizeof(jvmtiEventCallbacks)),
 620                   " Set Event Callbacks")) {
 621     return JNI_ERR;
 622   }
 623   return JNI_OK;
 624 }
 625 
 626 JNIEXPORT void JNICALL
 627 Java_MyPackage_HeapMonitor_setSamplingRate(JNIEnv* env, jclass cls, jint value) {
 628   (*jvmti)->SetHeapSamplingRate(jvmti, value);
 629 }
 630 
 631 JNIEXPORT jboolean JNICALL
 632 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
 633   return event_storage_get_count(&global_event_storage) == 0;
 634 }
 635 
 636 JNIEXPORT jint JNICALL
 637 Java_MyPackage_HeapMonitor_getEventStorageElementCount(JNIEnv* env, jclass cls) {
 638   return event_storage_get_count(&global_event_storage);
 639 }
 640 
 641 JNIEXPORT void JNICALL
 642 Java_MyPackage_HeapMonitor_enableSamplingEvents(JNIEnv* env, jclass cls) {
 643   enable_notifications();
 644 }
 645 
 646 JNIEXPORT jboolean JNICALL
 647 Java_MyPackage_HeapMonitor_enableSamplingEventsForTwoThreads(JNIEnv* env,
 648                                                              jclass cls,
 649                                                              jthread first,
 650                                                              jthread second) {
 651   return enable_notifications_for_two_threads(first, second);
 652 }
 653 
 654 JNIEXPORT void JNICALL
 655 Java_MyPackage_HeapMonitor_disableSamplingEvents(JNIEnv* env, jclass cls) {
 656   check_error((*jvmti)->SetEventNotificationMode(
 657       jvmti, JVMTI_DISABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
 658               "Set event notifications");
 659 
 660   check_error((*jvmti)->SetEventNotificationMode(
 661       jvmti, JVMTI_DISABLE, JVMTI_EVENT_GARBAGE_COLLECTION_FINISH, NULL),
 662               "Garbage Collection Finish");
 663 }
 664 
 665 JNIEXPORT jboolean JNICALL
 666 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) {
 667   jsize size = (*env)->GetArrayLength(env, frames);
 668   ExpectedContentFrame native_frames[size];
 669   fill_native_frames(env, frames, native_frames, size);
 670   return event_storage_contains(env, &global_event_storage, native_frames, size);
 671 }
 672 
 673 JNIEXPORT jboolean JNICALL
 674 Java_MyPackage_HeapMonitor_garbageContains(JNIEnv* env, jclass cls, jobjectArray frames) {
 675   jsize size = (*env)->GetArrayLength(env, frames);
 676   ExpectedContentFrame native_frames[size];
 677   fill_native_frames(env, frames, native_frames, size);
 678   return event_storage_garbage_contains(env, &global_event_storage, native_frames, size);
 679 }
 680 
 681 JNIEXPORT void JNICALL
 682 Java_MyPackage_HeapMonitor_forceGarbageCollection(JNIEnv* env, jclass cls) {
 683   check_error((*jvmti)->ForceGarbageCollection(jvmti),
 684               "Forced Garbage Collection");
 685 }
 686 
 687 JNIEXPORT void JNICALL
 688 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
 689   event_storage_reset(&global_event_storage);
 690   event_storage_reset(&second_global_event_storage);
 691 }
 692 
 693 JNIEXPORT jboolean JNICALL
 694 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 695                                                                   jclass cls) {
 696   jvmtiCapabilities caps;
 697   memset(&caps, 0, sizeof(caps));
 698   caps.can_generate_sampled_alloc_events = 1;
 699   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 700                   "Add capabilities\n")){
 701     return FALSE;
 702   }
 703 
 704   if (check_capability_error((*jvmti)->SetHeapSamplingRate(jvmti, 1<<19),
 705                              "Set Heap Sampling Rate")) {
 706     return FALSE;
 707   }
 708   return TRUE;
 709 }
 710 
 711 JNIEXPORT jboolean JNICALL
 712 Java_MyPackage_HeapMonitorIllegalArgumentTest_testIllegalArgument(JNIEnv *env,
 713                                                                   jclass cls) {
 714   if (check_error((*jvmti)->SetHeapSamplingRate(jvmti, 0),
 715                   "Sampling rate 0 failed\n")){
 716     return FALSE;
 717   }
 718 
 719   if (check_error((*jvmti)->SetHeapSamplingRate(jvmti, 1024),
 720                   "Sampling rate 1024 failed\n")){
 721     return FALSE;
 722   }
 723 
 724   if (!check_error((*jvmti)->SetHeapSamplingRate(jvmti, -1),
 725                    "Sampling rate -1 passed\n")){
 726     return FALSE;
 727   }
 728 
 729   if (!check_error((*jvmti)->SetHeapSamplingRate(jvmti, -1024),
 730                    "Sampling rate -1024 passed\n")){
 731     return FALSE;
 732   }
 733 
 734   return TRUE;
 735 }
 736 
 737 JNIEXPORT jdouble JNICALL
 738 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 739   return event_storage_get_average_rate(&global_event_storage);
 740 }
 741 
 742 typedef struct sThreadsFound {
 743   jthread* threads;
 744   int num_threads;
 745 } ThreadsFound;
 746 
 747 static void find_threads_in_array(ThreadsFound* thread_data,
 748                                   ObjectTrace** array,
 749                                   int array_size) {
 750   int i;
 751   jthread* threads = thread_data->threads;
 752   int num_threads = thread_data->num_threads;
 753 
 754   for (i = 0; i < array_size; i++) {
 755     ObjectTrace* object = array[i];
 756 
 757     if (object == NULL) {
 758       continue;
 759     }
 760 
 761     // Check it is the right frame: only accept helper top framed traces.
 762     if (object->frame_count == 0) {
 763       continue;
 764     }
 765 
 766     jvmtiFrameInfo* frames = object->frames;
 767     jthread thread = object->thread;
 768 
 769     jmethodID methodid = frames[0].method;
 770     char *name = NULL, *signature = NULL, *file_name = NULL;
 771     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 772 
 773     if (strcmp(name, "helper")) {
 774       continue;
 775     }
 776 
 777     // Really not efficient look-up but it's for a test...
 778     int found = 0;
 779     int j;
 780     for (j = 0; j < num_threads; j++) {
 781       if (thread == threads[j]) {
 782         found = 1;
 783         break;
 784       }
 785     }
 786 
 787     if (!found) {
 788       threads[num_threads] = thread;
 789       num_threads++;
 790     }
 791   }
 792   thread_data->num_threads = num_threads;
 793 }
 794 
 795 JNIEXPORT jboolean JNICALL
 796 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
 797                                                   jint num_threads) {
 798   pthread_mutex_lock(&global_event_storage.storage_mutex);
 799   jint trace_counter;
 800 
 801   ThreadsFound thread_data;
 802   thread_data.num_threads = 0;
 803   thread_data.threads = malloc(sizeof(jthread) * num_threads);
 804   memset(thread_data.threads, 0, sizeof(jthread) * num_threads);
 805 
 806   find_threads_in_array(&thread_data, global_event_storage.live_objects,
 807                         global_event_storage.live_object_count);
 808 
 809   free(thread_data.threads);
 810   pthread_mutex_unlock(&global_event_storage.storage_mutex);
 811   fprintf(stderr, "Obtained %d - %d\n",
 812           thread_data.num_threads,
 813           num_threads);
 814   return thread_data.num_threads == num_threads;
 815 }
 816 
 817 
 818 static void release_data(JNIEnv* env, jstring first, const char* first_str,
 819                          jstring second, const char* second_str,
 820                          jthread* threads) {
 821   (*env)->ReleaseStringUTFChars(env, first, first_str);
 822   (*env)->ReleaseStringUTFChars(env, second, second_str);
 823   free(threads);
 824 }
 825 
 826 JNIEXPORT jboolean JNICALL
 827 Java_MyPackage_HeapMonitorEventsForTwoThreadsTest_checkSamples(JNIEnv* env,
 828                                                                jclass cls) {
 829   pthread_mutex_lock(&global_event_storage.storage_mutex);
 830   jint trace_counter;
 831 
 832   const int expected_num_threads = 2;
 833   ThreadsFound thread_data;
 834   thread_data.num_threads = 0;
 835   thread_data.threads = malloc(sizeof(jthread) * expected_num_threads);
 836   memset(thread_data.threads, 0, sizeof(jthread) * expected_num_threads);
 837 
 838   find_threads_in_array(&thread_data, global_event_storage.live_objects,
 839                         global_event_storage.live_object_count);
 840 
 841   pthread_mutex_unlock(&global_event_storage.storage_mutex);
 842 
 843   int obtained_threads = thread_data.num_threads;
 844   return obtained_threads == expected_num_threads;
 845 }
 846 
 847 JNIEXPORT
 848 void JNICALL SampledObjectAlloc2(jvmtiEnv *jvmti_env,
 849                                  JNIEnv* jni_env,
 850                                  jthread thread,
 851                                  jobject object,
 852                                  jclass object_klass,
 853                                  jlong size) {
 854   event_storage_add(&second_global_event_storage, jni_env, thread, object,
 855                     object_klass, size);
 856 }
 857 
 858 JNIEXPORT jboolean JNICALL
 859 Java_MyPackage_HeapMonitorTwoAgentsTest_enablingSamplingInSecondaryAgent(
 860     JNIEnv* env, jclass cls) {
 861   jvmtiCapabilities caps;
 862   memset(&caps, 0, sizeof(caps));
 863   caps.can_generate_sampled_alloc_events = 1;
 864   if (check_error((*second_jvmti)->AddCapabilities(second_jvmti, &caps),
 865                   "Set the capability for second agent")) {
 866     return FALSE;
 867   }
 868 
 869   jvmtiEventCallbacks callbacks;
 870   memset(&callbacks, 0, sizeof(callbacks));
 871   callbacks.SampledObjectAlloc = &SampledObjectAlloc2;
 872 
 873   if (check_error((*second_jvmti)->SetEventCallbacks(second_jvmti, &callbacks,
 874                                                      sizeof(jvmtiEventCallbacks)),
 875                   " Set Event Callbacks for second agent")) {
 876     return FALSE;
 877   }
 878 
 879   return TRUE;
 880 }
 881 
 882 JNIEXPORT jboolean JNICALL
 883 Java_MyPackage_HeapMonitorTwoAgentsTest_obtainedEventsForBothAgents(
 884     JNIEnv* env, jclass cls, jobjectArray frames) {
 885   jsize size = (*env)->GetArrayLength(env, frames);
 886   ExpectedContentFrame native_frames[size];
 887   fill_native_frames(env, frames, native_frames, size);
 888 
 889   int first_storage_contained_events =
 890       event_storage_contains(env, &global_event_storage, native_frames, size);
 891 
 892   int second_storage_contained_events =
 893       event_storage_contains(env, &second_global_event_storage, native_frames, size);
 894 
 895   return first_storage_contained_events && second_storage_contained_events;
 896 }
 897 
 898 JNIEXPORT void JNICALL
 899 Java_MyPackage_HeapMonitorVMEventsTest_enableVMEvents(JNIEnv* env, jclass cls) {
 900   check_error((*jvmti)->SetEventNotificationMode(
 901       jvmti, JVMTI_ENABLE, JVMTI_EVENT_VM_OBJECT_ALLOC, NULL),
 902               "Set vm event notifications");
 903 }
 904 
 905 JNIEXPORT jboolean JNICALL
 906 Java_MyPackage_HeapMonitorVMEventsTest_vmStorageContained(
 907     JNIEnv* env, jclass cls, jobjectArray frames) {
 908   jsize size = (*env)->GetArrayLength(env, frames);
 909   ExpectedContentFrame native_frames[size];
 910   fill_native_frames(env, frames, native_frames, size);
 911 
 912   return event_storage_contains(env, &second_global_event_storage, native_frames, size);
 913 }
 914 
 915 JNIEXPORT jint JNICALL
 916 Java_MyPackage_HeapMonitorVMEventsTest_vmEvents(JNIEnv* env, jclass cls) {
 917   return event_storage_number_additions(&second_global_event_storage);
 918 }
 919 
 920 JNIEXPORT jint JNICALL
 921 Java_MyPackage_HeapMonitorVMEventsTest_sampledEvents(JNIEnv* env, jclass cls) {
 922   return event_storage_number_additions(&global_event_storage);
 923 }
 924 
 925 #ifdef __cplusplus
 926 }
 927 #endif