1 /*
   2  * Copyright (c) 2017, 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 const char *EXC_CNAME = "java/lang/Exception";
  53 static jvmtiEnv *jvmti = NULL;
  54 static pthread_mutex_t event_data_lock;
  55 
  56 // Event storage code.
  57 
  58 typedef struct _LiveObjectTrace{
  59   jvmtiFrameInfo* frames;
  60   size_t frame_count;
  61 } LiveObjectTrace;
  62 
  63 typedef struct _EventStorage {
  64   int live_object_size;
  65   int live_object_count;
  66   LiveObjectTrace** live_objects;
  67 } EventStorage;
  68 
  69 typedef struct _ExpectedContentFrame {
  70   const char *name;
  71   const char *signature;
  72   const char *file_name;
  73   int line_number;
  74 } ExpectedContentFrame;
  75 
  76 static jboolean check_live_object_trace_content(
  77     JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected,
  78     size_t expected_count, int print_out_comparisons);
  79 
  80 static EventStorage global_event_storage;
  81 
  82 static int event_storage_get_count(EventStorage* storage) {
  83   return storage->live_object_count;
  84 }
  85 
  86 static jboolean event_storage_contains(JNIEnv* env,
  87                                        EventStorage* storage,
  88                                        ExpectedContentFrame* frames,
  89                                        size_t size) {
  90   int i;
  91   fprintf(stderr, "Event storage contains: %d\n", storage->live_object_count);
  92   for (i = 0; i < storage->live_object_count; i++) {
  93     LiveObjectTrace* trace = storage->live_objects[i];
  94 
  95     if (check_live_object_trace_content(env, trace, frames, size, PRINT_OUT)) {
  96       return TRUE;
  97     }
  98   }
  99   return FALSE;
 100 }
 101 
 102 static void event_storage_augment_storage(EventStorage* storage) {
 103   int new_max = (storage->live_object_size * 2) + 1;
 104   LiveObjectTrace** new_objects = malloc(new_max * sizeof(*new_objects));
 105 
 106   int current_count = storage->live_object_count;
 107   memcpy(new_objects, storage->live_objects, current_count * sizeof(*new_objects));
 108   free(storage->live_objects);
 109   storage->live_objects = new_objects;
 110 
 111   storage->live_object_size = new_max;
 112 }
 113 
 114 static void event_storage_add(EventStorage* storage,
 115                               jthread thread,
 116                               jobject object,
 117                               jclass klass,
 118                               jlong size) {
 119   pthread_mutex_lock(&event_data_lock);
 120   jvmtiFrameInfo frames[64];
 121   jint count;
 122   jvmtiError err;
 123   err = (*jvmti)->GetStackTrace(jvmti, thread, 0, 64, frames, &count);
 124   if (err == JVMTI_ERROR_NONE && count >= 1) {
 125     if (storage->live_object_count >= storage->live_object_size) {
 126       event_storage_augment_storage(storage);
 127     }
 128     assert(storage->live_object_count < storage->live_object_size);
 129 
 130     jvmtiFrameInfo* allocated_frames = malloc(count * sizeof(*allocated_frames));
 131     memcpy(allocated_frames, frames, count * sizeof(*allocated_frames));
 132 
 133     LiveObjectTrace* live_object = malloc(sizeof(*live_object));
 134     live_object->frames = allocated_frames;
 135     live_object->frame_count = count;
 136     storage->live_objects[storage->live_object_count] = live_object;
 137     storage->live_object_count++;
 138   }
 139   pthread_mutex_unlock(&event_data_lock);
 140 }
 141 
 142 static void event_storage_reset(EventStorage* storage) {
 143   pthread_mutex_lock(&event_data_lock);
 144   int max = storage->live_object_count;
 145   int i;
 146   for (i = 0; i < max; i++) {
 147     LiveObjectTrace* object = storage->live_objects[i];
 148     free(object);
 149   }
 150   free(storage->live_objects);
 151   memset(storage, 0, sizeof(*storage));
 152   pthread_mutex_unlock(&event_data_lock);
 153 }
 154 
 155 // General JVMTI agent code.
 156 
 157 static int check_error(jvmtiError err, const char *s) {
 158   if (err != JVMTI_ERROR_NONE) {
 159     printf("  ## %s error: %d\n", s, err);
 160     return 1;
 161   }
 162   return 0;
 163 }
 164 
 165 static int check_capability_error(jvmtiError err, const char *s) {
 166   if (err != JVMTI_ERROR_NONE) {
 167     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
 168       return 0;
 169     }
 170     printf("  ## %s error: %d\n", s, err);
 171     return 1;
 172   }
 173   return 1;
 174 }
 175 
 176 static
 177 jint throw_exc(JNIEnv *env, char *msg) {
 178   jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
 179 
 180   if (exc_class == NULL) {
 181     printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
 182     return -1;
 183   }
 184   return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
 185 }
 186 
 187 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
 188 
 189 JNIEXPORT
 190 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
 191   return Agent_Initialize(jvm, options, reserved);
 192 }
 193 
 194 JNIEXPORT
 195 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
 196   return Agent_Initialize(jvm, options, reserved);
 197 }
 198 
 199 JNIEXPORT
 200 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
 201   return JNI_VERSION_1_8;
 202 }
 203 
 204 JNIEXPORT
 205 void JNICALL SampledObjectAlloc(jvmtiEnv *jvmti_env,
 206                                 JNIEnv* jni_env,
 207                                 jthread thread,
 208                                 jobject object,
 209                                 jclass object_klass,
 210                                 jlong size) {
 211   // Not optimal to do this at the callback but makes testing easier for now.
 212   event_storage_add(&global_event_storage, thread, object, object_klass, size);
 213 }
 214 
 215 static
 216 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 217   jint res;
 218 
 219   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 220                                  JVMTI_VERSION_9);
 221   if (res != JNI_OK || jvmti == NULL) {
 222     printf("    Error: wrong result of a valid call to GetEnv!\n");
 223     return JNI_ERR;
 224   }
 225 
 226   jvmtiEventCallbacks callbacks;
 227   memset(&callbacks, 0, sizeof(callbacks));
 228   callbacks.SampledObjectAlloc = &SampledObjectAlloc;
 229 
 230   jvmtiCapabilities caps;
 231   memset(&caps, 0, sizeof(caps));
 232   // Get line numbers, sample heap, and filename for the test.
 233   caps.can_get_line_numbers = 1;
 234   caps.can_sample_heap = 1;
 235   caps.can_generate_sampled_object_alloc_events = 1;
 236   caps.can_get_source_file_name = 1;
 237   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps),
 238                   "Add capabilities\n")){
 239     return JNI_ERR;
 240   }
 241 
 242   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 243                                               sizeof(jvmtiEventCallbacks)),
 244                   " Set Event Callbacks")) {
 245     return JNI_ERR;
 246   }
 247 
 248 
 249   if (pthread_mutex_init(&event_data_lock, NULL) != 0) {
 250     return JNI_ERR;
 251   }
 252 
 253   return JNI_OK;
 254 }
 255 
 256 // Given a method and a location, this method gets the line number.
 257 static
 258 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
 259                      jlocation location) {
 260   // Read the line number table.
 261   jvmtiLineNumberEntry *table_ptr = 0;
 262   jint line_number_table_entries;
 263   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
 264                                                  &line_number_table_entries,
 265                                                  &table_ptr);
 266 
 267   if (JVMTI_ERROR_NONE != jvmti_error) {
 268     return -1;
 269   }
 270   if (line_number_table_entries <= 0) {
 271     return -1;
 272   }
 273   if (line_number_table_entries == 1) {
 274     return table_ptr[0].line_number;
 275   }
 276 
 277   // Go through all the line numbers...
 278   jint last_location = table_ptr[0].start_location;
 279   int l;
 280   for (l = 1; l < line_number_table_entries; l++) {
 281     // ... and if you see one that is in the right place for your
 282     // location, you've found the line number!
 283     if ((location < table_ptr[l].start_location) &&
 284         (location >= last_location)) {
 285       return table_ptr[l - 1].line_number;
 286     }
 287     last_location = table_ptr[l].start_location;
 288   }
 289 
 290   if (location >= last_location) {
 291     return table_ptr[line_number_table_entries - 1].line_number;
 292   } else {
 293     return -1;
 294   }
 295 }
 296 
 297 static jboolean check_frame_content(JNIEnv *env,
 298                                     jvmtiFrameInfo* frames,
 299                                     ExpectedContentFrame *expected,
 300                                     int expected_count,
 301                                     int print_out_comparisons) {
 302   int i;
 303   for (i = 0; i < expected_count; i++) {
 304     // Get basic information out of the trace.
 305     int bci = frames[i].location;
 306     jmethodID methodid = frames[i].method;
 307     char *name = NULL, *signature = NULL, *file_name = NULL;
 308 
 309     if (bci < 0) {
 310       return FALSE;
 311     }
 312 
 313     // Transform into usable information.
 314     int line_number = get_line_number(jvmti, methodid, bci);
 315     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 316 
 317     jclass declaring_class;
 318     if (JVMTI_ERROR_NONE !=
 319         (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
 320       return FALSE;
 321     }
 322 
 323     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
 324                                                  &file_name);
 325     if (err != JVMTI_ERROR_NONE) {
 326       return FALSE;
 327     }
 328 
 329     // Compare now, none should be NULL.
 330     if (name == NULL) {
 331       return FALSE;
 332     }
 333 
 334     if (file_name == NULL) {
 335       return FALSE;
 336     }
 337 
 338     if (signature == NULL) {
 339       return FALSE;
 340     }
 341 
 342     if (print_out_comparisons) {
 343       fprintf(stderr, "\tComparing:\n");
 344       fprintf(stderr, "\t\tNames: %s and %s\n", name, expected[i].name);
 345       fprintf(stderr, "\t\tSignatures: %s and %s\n", signature, expected[i].signature);
 346       fprintf(stderr, "\t\tFile name: %s and %s\n", file_name, expected[i].file_name);
 347       fprintf(stderr, "\t\tLines: %d and %d\n", line_number, expected[i].line_number);
 348       fprintf(stderr, "\t\tResult is %d\n",
 349               (strcmp(name, expected[i].name) ||
 350                strcmp(signature, expected[i].signature) ||
 351                strcmp(file_name, expected[i].file_name) ||
 352                line_number != expected[i].line_number));
 353     }
 354 
 355     if (strcmp(name, expected[i].name) ||
 356         strcmp(signature, expected[i].signature) ||
 357         strcmp(file_name, expected[i].file_name) ||
 358         line_number != expected[i].line_number) {
 359       return FALSE;
 360     }
 361   }
 362 
 363   return TRUE;
 364 }
 365 
 366 static jboolean check_live_object_trace_content(
 367     JNIEnv *env, LiveObjectTrace* trace, ExpectedContentFrame *expected,
 368     size_t expected_count, int print_out_comparisons) {
 369 
 370   if (expected_count > trace->frame_count) {
 371     return FALSE;
 372   }
 373 
 374   return check_frame_content(env, trace->frames,
 375                              expected, expected_count, print_out_comparisons);
 376 }
 377 
 378 static jboolean check_sample_content(JNIEnv *env,
 379                                      jvmtiAllocTraceInfo* trace,
 380                                      ExpectedContentFrame *expected,
 381                                      int expected_count,
 382                                      int print_out_comparisons) {
 383   jvmtiStackInfo* stack_info = trace->stack_info;
 384 
 385   if (expected_count > stack_info->frame_count) {
 386     return FALSE;
 387   }
 388 
 389   return check_frame_content(env, stack_info->frame_buffer,
 390                              expected, expected_count, print_out_comparisons);
 391 }
 392 
 393 static jboolean compare_samples(JNIEnv* env, jvmtiAllocTraceInfo* traces,
 394                                 int trace_count,
 395                                 ExpectedContentFrame* expected_content,
 396                                 size_t size,
 397                                 int print_out_comparisons) {
 398   // We expect the code to record correctly the bci, retrieve the line
 399   // number, have the right method and the class name of the first frames.
 400   int i;
 401   if (print_out_comparisons) {
 402     fprintf(stderr, "\tNumber of traces: %d\n", print_out_comparisons);
 403   }
 404 
 405   for (i = 0; i < trace_count; i++) {
 406     jvmtiAllocTraceInfo* trace = traces + i;
 407     if (check_sample_content(env, trace, expected_content, size,
 408                              print_out_comparisons)) {
 409       // At least one frame matched what we were looking for.
 410       return TRUE;
 411     }
 412   }
 413 
 414   return FALSE;
 415 }
 416 
 417 static jboolean
 418 check_samples(JNIEnv* env,
 419               ExpectedContentFrame* expected,
 420               size_t size,
 421               jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiAllocTraceInfo**, jint*),
 422               int print_out_comparisons) {
 423   jvmtiAllocTraceInfo *traces;
 424   jint trace_counter;
 425   jvmtiError error = get_traces(jvmti, &traces, &trace_counter);
 426 
 427   if (error != JVMTI_ERROR_NONE) {
 428     return FALSE;
 429   }
 430 
 431   int result = compare_samples(env, traces, trace_counter,
 432                                expected, size, print_out_comparisons);
 433 
 434   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
 435     return FALSE;
 436   }
 437 
 438   return result;
 439 }
 440 
 441 static jboolean frames_exist_live(JNIEnv* env,
 442                                   ExpectedContentFrame* expected,
 443                                   size_t size,
 444                                   int print_out_comparisons) {
 445   return check_samples(env, expected, size,
 446                        (*jvmti)->GetLiveObjectAllocTraces,
 447                        print_out_comparisons);
 448 }
 449 
 450 static jboolean frames_exist_recent(JNIEnv* env,
 451                                     ExpectedContentFrame* expected,
 452                                     size_t size,
 453                                     int print_out_comparisons) {
 454   return check_samples(env, expected, size,
 455                        (*jvmti)->GetGarbageObjectAllocTraces,
 456                        print_out_comparisons);
 457 }
 458 
 459 static jboolean frames_exist_frequent(JNIEnv* env,
 460                                       ExpectedContentFrame* expected,
 461                                       size_t size,
 462                                       int print_out_comparisons) {
 463   return check_samples(env, expected, size,
 464                        (*jvmti)->GetFrequentGarbageObjectAllocTraces,
 465                        print_out_comparisons);
 466 }
 467 
 468 // Static native API for various tests.
 469 static void fill_native_frames(JNIEnv* env, jobjectArray frames,
 470                                ExpectedContentFrame* native_frames, size_t size) {
 471   size_t i;
 472   for(i = 0; i < size; i++) {
 473     jobject obj = (*env)->GetObjectArrayElement(env, frames, i);
 474     jclass frame_class = (*env)->GetObjectClass(env, obj);
 475     jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class,
 476                                                        "lineNumber", "I");
 477     int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
 478 
 479     jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method",
 480                                             "Ljava/lang/String;");
 481     jstring string_object = (jstring) (*env)->GetObjectField(env, obj,
 482                                                              string_id);
 483     const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
 484 
 485     string_id = (*env)->GetFieldID(env, frame_class, "fileName",
 486                                    "Ljava/lang/String;");
 487     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 488     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 489 
 490     string_id = (*env)->GetFieldID(env, frame_class, "signature",
 491                                    "Ljava/lang/String;");
 492     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 493     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 494 
 495     native_frames[i].name = method;
 496     native_frames[i].file_name = file_name;
 497     native_frames[i].signature = signature;
 498     native_frames[i].line_number = line_number;
 499   }
 500 }
 501 
 502 static jboolean check_and(JNIEnv *env, jobjectArray frames, int live,
 503                           int recent, int frequent, int print_out) {
 504   jobject loader = NULL;
 505 
 506   if (frames == NULL) {
 507     return FALSE;
 508   }
 509 
 510   // Start by transforming the frames into a C-friendly structure.
 511   jsize size = (*env)->GetArrayLength(env, frames);
 512   ExpectedContentFrame native_frames[size];
 513   fill_native_frames(env, frames, native_frames, size);
 514 
 515   if (jvmti == NULL) {
 516     throw_exc(env, "JVMTI client was not properly loaded!\n");
 517     return FALSE;
 518   }
 519 
 520   int result = TRUE;
 521 
 522   if (live) {
 523     result = frames_exist_live(env, native_frames, size, print_out);
 524   }
 525 
 526   if (recent) {
 527     result = result &&
 528         frames_exist_recent(env, native_frames, size, print_out);
 529   }
 530 
 531   if (frequent) {
 532     result = result &&
 533         frames_exist_frequent(env, native_frames, size, print_out);
 534   }
 535 
 536   return result;
 537 }
 538 
 539 static jboolean check_or(JNIEnv *env, jobjectArray frames, int live, int recent,
 540                          int frequent, int print_out) {
 541   jobject loader = NULL;
 542 
 543   if (frames == NULL) {
 544     return FALSE;
 545   }
 546 
 547   // Start by transforming the frames into a C-friendly structure.
 548   jsize size = (*env)->GetArrayLength(env, frames);
 549   ExpectedContentFrame native_frames[size];
 550   fill_native_frames(env, frames, native_frames, size);
 551 
 552   if (jvmti == NULL) {
 553     throw_exc(env, "JVMTI client was not properly loaded!\n");
 554     return FALSE;
 555   }
 556 
 557   jboolean result = FALSE;
 558 
 559   if (live) {
 560     result = frames_exist_live(env, native_frames, size, print_out);
 561   }
 562 
 563   if (recent) {
 564     result = result ||
 565         frames_exist_recent(env, native_frames, size, print_out);
 566   }
 567 
 568   if (frequent) {
 569     result = result ||
 570         frames_exist_frequent(env, native_frames, size, print_out);
 571   }
 572 
 573   return result;
 574 }
 575 
 576 static jboolean checkAll(JNIEnv *env, jobjectArray frames, int print_out) {
 577   return check_and(env, frames, 1, 1, 1, print_out);
 578 }
 579 
 580 static jboolean checkNone(JNIEnv *env, jobjectArray frames,
 581                           int print_out) {
 582   jobject loader = NULL;
 583 
 584   if (frames == NULL) {
 585     return FALSE;
 586   }
 587 
 588   // Start by transforming the frames into a C-friendly structure.
 589   jsize size = (*env)->GetArrayLength(env, frames);
 590   ExpectedContentFrame native_frames[size];
 591   fill_native_frames(env, frames, native_frames, size);
 592 
 593   if (jvmti == NULL) {
 594     throw_exc(env, "JVMTI client was not properly loaded!\n");
 595     return FALSE ;
 596   }
 597 
 598   if ((!frames_exist_live(env, native_frames, size, print_out)) &&
 599       (!frames_exist_recent(env, native_frames, size, print_out)) &&
 600       (!frames_exist_frequent(env, native_frames, size, print_out))) {
 601     return TRUE;
 602   }
 603   return FALSE;
 604 }
 605 
 606 JNIEXPORT void JNICALL
 607 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate,
 608                                           int max_traces) {
 609   check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces),
 610               "Start Heap Sampling");
 611   check_error(
 612       (*jvmti)->SetEventNotificationMode(jvmti,
 613                                          JVMTI_ENABLE,
 614                                          JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
 615                                          NULL),
 616       "Start sampling events");
 617 }
 618 
 619 JNIEXPORT void JNICALL
 620 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) {
 621   check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
 622 
 623   check_error(
 624       (*jvmti)->SetEventNotificationMode(jvmti,
 625                                          JVMTI_DISABLE,
 626                                          JVMTI_EVENT_SAMPLED_OBJECT_ALLOC,
 627                                          NULL),
 628       "Start sampling events");
 629 }
 630 
 631 JNIEXPORT jboolean JNICALL
 632 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) {
 633   jvmtiHeapSamplingStats stats;
 634   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 635               "Heap Sampling Statistics");
 636 
 637   jvmtiHeapSamplingStats zero;
 638   memset(&zero, 0, sizeof(zero));
 639   return memcmp(&stats, &zero, sizeof(zero)) == 0;
 640 }
 641 
 642 JNIEXPORT jboolean JNICALL
 643 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls,
 644                                                  jobjectArray frames) {
 645   // We want the frames in each part.
 646   return checkAll(env, frames, PRINT_OUT);
 647 }
 648 
 649 JNIEXPORT jboolean JNICALL
 650 Java_MyPackage_HeapMonitor_framesExistNowhere(JNIEnv *env, jclass cls,
 651                                               jobjectArray frames) {
 652   // We want the frames in none of the parts.
 653   return checkNone(env, frames, PRINT_OUT);
 654 }
 655 
 656 JNIEXPORT jboolean JNICALL
 657 Java_MyPackage_HeapMonitor_framesExistSomewhere(JNIEnv *env, jclass cls,
 658                                                 jobjectArray frames) {
 659   return check_or(env, frames, TRUE, TRUE, TRUE, PRINT_OUT);
 660 }
 661 
 662 JNIEXPORT jboolean JNICALL
 663 Java_MyPackage_HeapMonitorRecentTest_framesNotInLiveOrRecent(JNIEnv *env,
 664                                                              jclass cls,
 665                                                              jobjectArray frames) {
 666   return !check_or(env, frames, TRUE, TRUE, FALSE, PRINT_OUT);
 667 }
 668 
 669 JNIEXPORT jboolean JNICALL
 670 Java_MyPackage_HeapMonitorRecentTest_framesExistInRecent(JNIEnv *env,
 671                                                          jclass cls,
 672                                                          jobjectArray frames) {
 673   return check_and(env, frames, FALSE, TRUE, FALSE, PRINT_OUT);
 674 }
 675 
 676 JNIEXPORT jboolean JNICALL
 677 Java_MyPackage_HeapMonitorFrequentTest_framesExistInFrequent(JNIEnv *env,
 678                                                              jclass cls,
 679                                                              jobjectArray frames) {
 680   return check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
 681 }
 682 
 683 JNIEXPORT jboolean JNICALL
 684 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 685                                                                   jclass cls) {
 686   jvmtiCapabilities caps;
 687   memset(&caps, 0, sizeof(caps));
 688   caps.can_sample_heap= 1;
 689   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 690                   "Add capabilities\n")){
 691     return FALSE;
 692   }
 693 
 694   if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
 695                                                          MAX_TRACES),
 696                              "Start Heap Sampling")) {
 697     return FALSE;
 698   }
 699 
 700   if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
 701                              "Stop Heap Sampling")) {
 702     return FALSE;
 703   }
 704 
 705   if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
 706                              "Get Heap Sampling Stats")) {
 707     return FALSE;
 708   }
 709 
 710   if (check_capability_error((*jvmti)->GetGarbageObjectAllocTraces(jvmti, NULL, NULL),
 711                              "Get Garbage ObjectAllocTraces")) {
 712     return FALSE;
 713   }
 714 
 715   if (check_capability_error((*jvmti)->GetFrequentGarbageObjectAllocTraces(jvmti, NULL, NULL),
 716                              "Get Frequent Garbage ObjectAllocTraces")) {
 717     return FALSE;
 718   }
 719 
 720   if (check_capability_error((*jvmti)->GetLiveObjectAllocTraces(jvmti, NULL, NULL),
 721                              "Get Object Allocated ObjectAllocTraces")) {
 722     return FALSE;
 723   }
 724 
 725   if (check_capability_error((*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, NULL, NULL),
 726                              "Get Cached Object Allocated ObjectAllocTraces")) {
 727     return FALSE;
 728   }
 729   return TRUE;
 730 }
 731 
 732 JNIEXPORT jboolean JNICALL
 733 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env,
 734                                                           jclass cls,
 735                                                           int expected,
 736                                                           int percent_error) {
 737   jvmtiHeapSamplingStats stats;
 738   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 739               "Heap Sampling Statistics");
 740 
 741   double diff_ratio = (stats.sample_count - expected);
 742   diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
 743   diff_ratio /= expected;
 744 
 745   if (diff_ratio * 100 >= percent_error) {
 746     fprintf(stderr, "Problem with sample count, obtained %ld and expected %d\n",
 747             stats.sample_count, expected);
 748   }
 749   return diff_ratio * 100 < percent_error;
 750 }
 751 
 752 JNIEXPORT jdouble JNICALL
 753 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 754   jvmtiHeapSamplingStats stats;
 755   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 756               "Heap Sampling Statistics");
 757   return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count;
 758 }
 759 
 760 static double calculate_average_stack_depth(
 761     jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiAllocTraceInfo**, jint*)) {
 762   jvmtiAllocTraceInfo* traces = NULL;
 763   jint trace_counter;
 764 
 765   jvmtiError error = get_traces(jvmti, &traces, &trace_counter);;
 766 
 767   if (error != JVMTI_ERROR_NONE) {
 768     return 0;
 769   }
 770 
 771   if (trace_counter == 0) {
 772     return 0;
 773   }
 774 
 775   int i;
 776   double sum = 0;
 777   for (i = 0; i < trace_counter; i++) {
 778     jvmtiAllocTraceInfo* trace = traces + i;
 779     jvmtiStackInfo* stack_info = trace->stack_info;
 780     sum += stack_info->frame_count;
 781   }
 782 
 783   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
 784     return 0;
 785   }
 786 
 787   return sum / i;
 788 }
 789 
 790 JNIEXPORT jdouble JNICALL
 791 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env,
 792                                                               jclass cls) {
 793   double result =
 794       calculate_average_stack_depth((*jvmti)->GetLiveObjectAllocTraces);
 795 
 796   if (result != 0) {
 797     return result;
 798   }
 799 
 800   // It is possible all the live objects got collected, check the garbage traces
 801   // in case.
 802   return calculate_average_stack_depth((*jvmti)->GetGarbageObjectAllocTraces);
 803 }
 804 
 805 typedef struct sThreadsFound {
 806   jint* threads;
 807   int num_threads;
 808 } ThreadsFound;
 809 
 810 static void find_threads_in_traces(jvmtiAllocTraceInfo* traces,
 811                                    jint trace_counter,
 812                                    ThreadsFound* thread_data) {
 813   int i;
 814   jint* threads = thread_data->threads;
 815   int num_threads = thread_data->num_threads;
 816 
 817   // We are looking for at last expected_num_threads different traces.
 818   for (i = 0; i < trace_counter; i++) {
 819     jvmtiAllocTraceInfo* trace = traces + i;
 820     jvmtiStackInfo* stack_info = trace->stack_info;
 821     jint thread_id = trace->thread_id;
 822 
 823     // Check it is the right frame: only accept helper top framed traces.
 824     if (stack_info->frame_count == 0) {
 825       continue;
 826     }
 827 
 828     jmethodID methodid = stack_info->frame_buffer[0].method;
 829     char *name = NULL, *signature = NULL, *file_name = NULL;
 830     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 831 
 832     if (strcmp(name, "helper")) {
 833       continue;
 834     }
 835 
 836     // Really not efficient look-up but it's for a test...
 837     int found = 0;
 838     int j;
 839     for (j = 0; j < num_threads; j++) {
 840       if (thread_id == threads[j]) {
 841         found = 1;
 842         break;
 843       }
 844     }
 845 
 846     if (!found) {
 847       threads[num_threads] = thread_id;
 848       num_threads++;
 849     }
 850   }
 851   thread_data->num_threads = num_threads;
 852 }
 853 
 854 JNIEXPORT jboolean JNICALL
 855 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
 856                                                   jintArray threads) {
 857   jvmtiAllocTraceInfo* traces;
 858   jint trace_counter;
 859 
 860   ThreadsFound thread_data;
 861   thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0);
 862   thread_data.num_threads = 0;
 863 
 864   // Get live and garbage traces to ensure we capture all the threads that have
 865   // been sampled.
 866   if ((*jvmti)->GetLiveObjectAllocTraces(jvmti, &traces, &trace_counter) != JVMTI_ERROR_NONE) {
 867     return FALSE;
 868   }
 869 
 870   find_threads_in_traces(traces, trace_counter, &thread_data);
 871 
 872   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
 873     return FALSE;
 874   }
 875 
 876   if ((*jvmti)->GetGarbageObjectAllocTraces(
 877       jvmti, &traces, &trace_counter) != JVMTI_ERROR_NONE) {
 878     return FALSE;
 879   }
 880 
 881   find_threads_in_traces(traces, trace_counter, &thread_data);
 882 
 883   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) traces) != JVMTI_ERROR_NONE) {
 884     return FALSE;
 885   }
 886 
 887   (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0);
 888   return TRUE;
 889 }
 890 
 891 JNIEXPORT void JNICALL
 892 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env,
 893                                                             jclass cls) {
 894   jvmtiAllocTraceInfo* traces;
 895   jint trace_counter;
 896 
 897   jvmtiError error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &traces,
 898                                                         &trace_counter);
 899 
 900   if (error != JVMTI_ERROR_NONE) {
 901     return;
 902   }
 903 
 904   (*jvmti)->Deallocate(jvmti, (unsigned char*) traces);
 905 }
 906 
 907 static jboolean compare_traces(jvmtiAllocTraceInfo* traces,
 908                                int trace_count,
 909                                jvmtiAllocTraceInfo* other_traces,
 910                                int other_trace_count,
 911                                int print_out_comparisons) {
 912   if (trace_count != other_trace_count) {
 913     fprintf(stderr, "Trace count not the same!\n %d %d",
 914             trace_count, other_trace_count);
 915     return FALSE;
 916   }
 917 
 918   int i;
 919   for (i = 0; i < trace_count; i++) {
 920     jvmtiAllocTraceInfo* trace = traces + i;
 921     jvmtiAllocTraceInfo* other_trace = other_traces + i;
 922 
 923     jvmtiStackInfo* stack_info = trace->stack_info;
 924     jvmtiStackInfo* other_stack_info = trace->stack_info;
 925 
 926     if (stack_info->frame_count != other_stack_info->frame_count) {
 927       fprintf(stderr, "Frame count not the same!\n");
 928       return FALSE;
 929     }
 930 
 931     if (trace->size != other_trace->size) {
 932       fprintf(stderr, "Size not the same!\n");
 933       return FALSE;
 934     }
 935 
 936     if (trace->thread_id != other_trace->thread_id) {
 937       fprintf(stderr, "Thread id not the same!\n");
 938       return FALSE;
 939     }
 940 
 941     jvmtiFrameInfo* frames = stack_info->frame_buffer;
 942     jvmtiFrameInfo* other_frames = other_stack_info->frame_buffer;
 943     if (memcmp(frames, other_frames, sizeof(*frames) * stack_info->frame_count)) {
 944       fprintf(stderr, "memcmp not the same!\n");
 945       return FALSE;
 946     }
 947   }
 948 
 949   return TRUE;
 950 }
 951 
 952 JNIEXPORT jboolean JNICALL
 953 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
 954                                                           jclass cls) {
 955   // Get cached first, then get live (since live performs a GC).
 956   jvmtiAllocTraceInfo* cached_traces;
 957   jint cached_trace_counter;
 958   jvmtiError error =
 959       (*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, &cached_traces,
 960                                                &cached_trace_counter);
 961 
 962   if (error != JVMTI_ERROR_NONE) {
 963     return FALSE;
 964   }
 965 
 966   jvmtiAllocTraceInfo* live_traces;
 967   jint live_trace_counter;
 968   error = (*jvmti)->GetLiveObjectAllocTraces(jvmti, &live_traces,
 969                                              &live_trace_counter);
 970 
 971   if (error != JVMTI_ERROR_NONE) {
 972     return FALSE;
 973   }
 974 
 975   int result = compare_traces(cached_traces, cached_trace_counter,
 976                               live_traces, live_trace_counter,
 977                               PRINT_OUT);
 978 
 979   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
 980     return FALSE;
 981   }
 982   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) live_traces) != JVMTI_ERROR_NONE) {
 983     return FALSE;
 984   }
 985   return result;
 986 }
 987 
 988 JNIEXPORT jboolean JNICALL
 989 Java_MyPackage_HeapMonitorCachedTest_forceGC(JNIEnv *env, jclass cls) {
 990   jvmtiError error = (*jvmti)->ForceGarbageCollection(jvmti);
 991 
 992   if (error != JVMTI_ERROR_NONE) {
 993     return FALSE;
 994   }
 995   return TRUE;
 996 }
 997 
 998 static long hash(long hash_code, long value) {
 999   return hash_code * 31 + value;
1000 }
1001 
1002 static long get_hash_code(jvmtiAllocTraceInfo* traces, jint trace_counter) {
1003   int hash_code = 17;
1004   int i, j;
1005 
1006   hash_code = hash(hash_code, trace_counter);
1007   for (i = 0; i < trace_counter; i++) {
1008     jvmtiAllocTraceInfo* trace = traces + i;
1009 
1010     hash_code = hash(hash_code, trace->size);
1011     hash_code = hash(hash_code, trace->thread_id);
1012 
1013     jvmtiStackInfo* stack_info = trace->stack_info;
1014     hash_code = hash(hash_code, stack_info->frame_count);
1015 
1016     int frame_count = stack_info->frame_count;
1017     jvmtiFrameInfo* frames = stack_info->frame_buffer;
1018     hash_code = hash(hash_code, frame_count);
1019     for (j = 0; j < frame_count; j++) {
1020       hash_code = hash(hash_code, (long) frames[i].method);
1021       hash_code = hash(hash_code, frames[i].location);
1022     }
1023   }
1024 
1025   return TRUE;
1026 }
1027 
1028 JNIEXPORT jlong JNICALL
1029 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env,
1030                                                        jclass cls) {
1031   // Get cached first, then get live.
1032   jvmtiAllocTraceInfo* cached_traces;
1033   jint cached_trace_counter;
1034   jvmtiError error =
1035       (*jvmti)->GetCachedLiveObjectAllocTraces(jvmti, &cached_traces,
1036                                                &cached_trace_counter);
1037 
1038   if (error != JVMTI_ERROR_NONE) {
1039     return 0;
1040   }
1041 
1042   long hash_code = get_hash_code(cached_traces, cached_trace_counter);
1043 
1044   if ((*jvmti)->Deallocate(jvmti, (unsigned char*) cached_traces) != JVMTI_ERROR_NONE) {
1045     return FALSE;
1046   }
1047 
1048   return hash_code;
1049 }
1050 
1051 JNIEXPORT jboolean JNICALL
1052 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
1053                                                 jclass cls,
1054                                                 jobjectArray frames) {
1055   return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
1056 }
1057 
1058 JNIEXPORT jboolean JNICALL
1059 Java_MyPackage_HeapMonitorEventNoCapabilityTest_eventSamplingFail(JNIEnv *env,
1060                                                                   jclass cls) {
1061   jvmtiCapabilities caps;
1062   memset(&caps, 0, sizeof(caps));
1063   caps.can_generate_sampled_object_alloc_events = 1;
1064   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
1065                   "Add capabilities\n")){
1066     return FALSE;
1067   }
1068 
1069   if (check_capability_error(
1070       (*jvmti)->SetEventNotificationMode(jvmti, JVMTI_ENABLE, JVMTI_EVENT_SAMPLED_OBJECT_ALLOC, NULL),
1071       "Set Tlab Heap Sampling")) {
1072     return FALSE;
1073   }
1074   return TRUE;
1075 }
1076 
1077 JNIEXPORT jboolean JNICALL
1078 Java_MyPackage_HeapMonitor_eventStorageIsEmpty(JNIEnv* env, jclass cls) {
1079   return event_storage_get_count(&global_event_storage) == 0;
1080 }
1081 
1082 JNIEXPORT jboolean JNICALL
1083 Java_MyPackage_HeapMonitor_obtainedEvents(JNIEnv* env, jclass cls, jobjectArray frames) {
1084   jsize size = (*env)->GetArrayLength(env, frames);
1085   ExpectedContentFrame native_frames[size];
1086   fill_native_frames(env, frames, native_frames, size);
1087   return event_storage_contains(env, &global_event_storage, native_frames, size);
1088 }
1089 
1090 JNIEXPORT void JNICALL
1091 Java_MyPackage_HeapMonitor_resetEventStorage(JNIEnv* env, jclass cls) {
1092   return event_storage_reset(&global_event_storage);
1093 }
1094 
1095 #ifdef __cplusplus
1096 }
1097 #endif