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 <stdio.h>
  25 #include <stdlib.h>
  26 #include <string.h>
  27 #include "jvmti.h"
  28 
  29 #ifdef __cplusplus
  30 extern "C" {
  31 #endif
  32 
  33 #ifndef JNI_ENV_ARG
  34 
  35 #ifdef __cplusplus
  36 #define JNI_ENV_ARG(x, y) y
  37 #define JNI_ENV_PTR(x) x
  38 #else
  39 #define JNI_ENV_ARG(x,y) x, y
  40 #define JNI_ENV_PTR(x) (*x)
  41 #endif
  42 
  43 #endif
  44 
  45 #define TRUE 1
  46 #define FALSE 0
  47 #define PRINT_OUT 1
  48 #define MAX_TRACES 400
  49 
  50 static const char *EXC_CNAME = "java/lang/Exception";
  51 static jvmtiEnv *jvmti = NULL;
  52 
  53 static int check_error(jvmtiError err, const char *s) {
  54   if (err != JVMTI_ERROR_NONE) {
  55     printf("  ## %s error: %d\n", s, err);
  56     return 1;
  57   }
  58   return 0;
  59 }
  60 
  61 static int check_capability_error(jvmtiError err, const char *s) {
  62   if (err != JVMTI_ERROR_NONE) {
  63     if (err == JVMTI_ERROR_MUST_POSSESS_CAPABILITY) {
  64       return 0;
  65     }
  66     printf("  ## %s error: %d\n", s, err);
  67     return 1;
  68   }
  69   return 1;
  70 }
  71 
  72 static
  73 jint throw_exc(JNIEnv *env, char *msg) {
  74   jclass exc_class = JNI_ENV_PTR(env)->FindClass(JNI_ENV_ARG(env, EXC_CNAME));
  75 
  76   if (exc_class == NULL) {
  77     printf("throw_exc: Error in FindClass(env, %s)\n", EXC_CNAME);
  78     return -1;
  79   }
  80   return JNI_ENV_PTR(env)->ThrowNew(JNI_ENV_ARG(env, exc_class), msg);
  81 }
  82 
  83 static jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved);
  84 
  85 JNIEXPORT
  86 jint JNICALL Agent_OnLoad(JavaVM *jvm, char *options, void *reserved) {
  87   return Agent_Initialize(jvm, options, reserved);
  88 }
  89 
  90 JNIEXPORT
  91 jint JNICALL Agent_OnAttach(JavaVM *jvm, char *options, void *reserved) {
  92   return Agent_Initialize(jvm, options, reserved);
  93 }
  94 
  95 JNIEXPORT
  96 jint JNICALL JNI_OnLoad(JavaVM *jvm, void *reserved) {
  97   return JNI_VERSION_1_8;
  98 }
  99 
 100 static
 101 jint Agent_Initialize(JavaVM *jvm, char *options, void *reserved) {
 102   jint res;
 103 
 104   res = JNI_ENV_PTR(jvm)->GetEnv(JNI_ENV_ARG(jvm, (void **) &jvmti),
 105                                  JVMTI_VERSION_9);
 106   if (res != JNI_OK || jvmti == NULL) {
 107     printf("    Error: wrong result of a valid call to GetEnv!\n");
 108     return JNI_ERR;
 109   }
 110 
 111   jvmtiEventCallbacks callbacks;
 112   memset(&callbacks, 0, sizeof(callbacks));
 113 
 114   jvmtiCapabilities caps;
 115   memset(&caps, 0, sizeof(caps));
 116   // Get line numbers, sample heap, and filename for the test.
 117   caps.can_get_line_numbers = 1;
 118   caps.can_sample_heap = 1;
 119   caps.can_get_source_file_name = 1;
 120   if (check_error((*jvmti)->AddCapabilities(jvmti, &caps),
 121                   "Add capabilities\n")){
 122     return JNI_ERR;
 123   }
 124   if (check_error((*jvmti)->SetEventCallbacks(jvmti, &callbacks,
 125                                               sizeof(jvmtiEventCallbacks)),
 126                   " Set Event Callbacks")) {
 127     return JNI_ERR;
 128   }
 129   return JNI_OK;
 130 }
 131 
 132 // Given a method and a location, this method gets the line number.
 133 static
 134 jint get_line_number(jvmtiEnv *jvmti, jmethodID method,
 135                      jlocation location) {
 136   // Read the line number table.
 137   jvmtiLineNumberEntry *table_ptr = 0;
 138   jint line_number_table_entries;
 139   int jvmti_error = (*jvmti)->GetLineNumberTable(jvmti, method,
 140                                                  &line_number_table_entries,
 141                                                  &table_ptr);
 142 
 143   if (JVMTI_ERROR_NONE != jvmti_error) {
 144     return -1;
 145   }
 146   if (line_number_table_entries <= 0) {
 147     return -1;
 148   }
 149   if (line_number_table_entries == 1) {
 150     return table_ptr[0].line_number;
 151   }
 152 
 153   // Go through all the line numbers...
 154   jint last_location = table_ptr[0].start_location;
 155   int l;
 156   for (l = 1; l < line_number_table_entries; l++) {
 157     // ... and if you see one that is in the right place for your
 158     // location, you've found the line number!
 159     if ((location < table_ptr[l].start_location) &&
 160         (location >= last_location)) {
 161       return table_ptr[l - 1].line_number;
 162     }
 163     last_location = table_ptr[l].start_location;
 164   }
 165 
 166   if (location >= last_location) {
 167     return table_ptr[line_number_table_entries - 1].line_number;
 168   } else {
 169     return -1;
 170   }
 171 }
 172 
 173 typedef struct _ExpectedContentFrame {
 174   const char *name;
 175   const char *signature;
 176   const char *file_name;
 177   int line_number;
 178 } ExpectedContentFrame;
 179 
 180 static jboolean check_sample_content(JNIEnv *env,
 181                                      jvmtiStackTrace *trace,
 182                                      ExpectedContentFrame *expected,
 183                                      int expected_count,
 184                                      int print_out_comparisons) {
 185   int i;
 186 
 187   if (expected_count > trace->frame_count) {
 188     return FALSE;
 189   }
 190 
 191   for (i = 0; i < expected_count; i++) {
 192     // Get basic information out of the trace.
 193     int bci = trace->frames[i].location;
 194     jmethodID methodid = trace->frames[i].method;
 195     char *name = NULL, *signature = NULL, *file_name = NULL;
 196 
 197     if (bci < 0) {
 198       return FALSE;
 199     }
 200 
 201     // Transform into usable information.
 202     int line_number = get_line_number(jvmti, methodid, bci);
 203     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 204 
 205     jclass declaring_class;
 206     if (JVMTI_ERROR_NONE !=
 207         (*jvmti)->GetMethodDeclaringClass(jvmti, methodid, &declaring_class)) {
 208       return FALSE;
 209     }
 210 
 211     jvmtiError err = (*jvmti)->GetSourceFileName(jvmti, declaring_class,
 212                                                  &file_name);
 213     if (err != JVMTI_ERROR_NONE) {
 214       return FALSE;
 215     }
 216 
 217     // Compare now, none should be NULL.
 218     if (name == NULL) {
 219       return FALSE;
 220     }
 221 
 222     if (file_name == NULL) {
 223       return FALSE;
 224     }
 225 
 226     if (signature == NULL) {
 227       return FALSE;
 228     }
 229 
 230     if (print_out_comparisons) {
 231       fprintf(stderr, "Comparing:\n");
 232       fprintf(stderr, "\tNames: %s and %s\n", name, expected[i].name);
 233       fprintf(stderr, "\tSignatures: %s and %s\n", signature, expected[i].signature);
 234       fprintf(stderr, "\tFile name: %s and %s\n", file_name, expected[i].file_name);
 235       fprintf(stderr, "\tLines: %d and %d\n", line_number, expected[i].line_number);
 236       fprintf(stderr, "\tResult is %d\n",
 237               (strcmp(name, expected[i].name) ||
 238                strcmp(signature, expected[i].signature) ||
 239                strcmp(file_name, expected[i].file_name) ||
 240                line_number != expected[i].line_number));
 241     }
 242 
 243     if (strcmp(name, expected[i].name) ||
 244         strcmp(signature, expected[i].signature) ||
 245         strcmp(file_name, expected[i].file_name) ||
 246         line_number != expected[i].line_number) {
 247       return FALSE;
 248     }
 249   }
 250 
 251   return TRUE;
 252 }
 253 
 254 static jboolean compare_samples(JNIEnv* env, jvmtiStackTrace* traces,
 255                                 int trace_count,
 256                                 ExpectedContentFrame* expected_content,
 257                                 size_t size,
 258                                 int print_out_comparisons) {
 259   // We expect the code to record correctly the bci, retrieve the line
 260   // number, have the right method and the class name of the first frames.
 261   int i;
 262   for (i = 0; i < trace_count; i++) {
 263     jvmtiStackTrace *trace = traces + i;
 264     if (check_sample_content(env, trace, expected_content, size,
 265                              print_out_comparisons)) {
 266       // At least one frame matched what we were looking for.
 267       return TRUE;
 268     }
 269   }
 270 
 271   return FALSE;
 272 }
 273 
 274 static jboolean
 275 check_samples(JNIEnv* env,
 276               ExpectedContentFrame* expected,
 277               size_t size,
 278               jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*),
 279               int print_out_comparisons) {
 280   jvmtiStackTraces traces;
 281   jvmtiError error = get_traces(jvmti, &traces);
 282 
 283   if (error != JVMTI_ERROR_NONE) {
 284     return FALSE;
 285   }
 286 
 287   int result = compare_samples(env, traces.stack_traces, traces.trace_count,
 288                                expected, size, print_out_comparisons);
 289   (*jvmti)->ReleaseTraces(jvmti, &traces);
 290   return result;
 291 }
 292 
 293 static jboolean frames_exist_live(JNIEnv* env,
 294                                   ExpectedContentFrame* expected,
 295                                   size_t size,
 296                                   int print_out_comparisons) {
 297   return check_samples(env, expected, size, (*jvmti)->GetLiveTraces,
 298                        print_out_comparisons);
 299 }
 300 
 301 static jboolean frames_exist_recent(JNIEnv* env,
 302                                     ExpectedContentFrame* expected,
 303                                     size_t size,
 304                                     int print_out_comparisons) {
 305   return check_samples(env, expected, size, (*jvmti)->GetGarbageTraces,
 306                        print_out_comparisons);
 307 }
 308 
 309 static jboolean frames_exist_frequent(JNIEnv* env,
 310                                       ExpectedContentFrame* expected,
 311                                       size_t size,
 312                                       int print_out_comparisons) {
 313   return check_samples(env, expected, size, (*jvmti)->GetFrequentGarbageTraces,
 314                        print_out_comparisons);
 315 }
 316 
 317 // Static native API for various tests.
 318 static void fill_native_frames(JNIEnv* env, jobjectArray frames,
 319                                ExpectedContentFrame* native_frames, size_t size) {
 320   size_t i;
 321   for(i = 0; i < size; i++) {
 322     jobject obj = (*env)->GetObjectArrayElement(env, frames, i);
 323     jclass frame_class = (*env)->GetObjectClass(env, obj);
 324     jfieldID line_number_field_id = (*env)->GetFieldID(env, frame_class,
 325                                                        "lineNumber", "I");
 326     int line_number = (*env)->GetIntField(env, obj, line_number_field_id);
 327 
 328     jfieldID string_id = (*env)->GetFieldID(env, frame_class, "method",
 329                                             "Ljava/lang/String;");
 330     jstring string_object = (jstring) (*env)->GetObjectField(env, obj,
 331                                                              string_id);
 332     const char* method = (*env)->GetStringUTFChars(env, string_object, 0);
 333 
 334     string_id = (*env)->GetFieldID(env, frame_class, "fileName",
 335                                    "Ljava/lang/String;");
 336     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 337     const char* file_name = (*env)->GetStringUTFChars(env, string_object, 0);
 338 
 339     string_id = (*env)->GetFieldID(env, frame_class, "signature",
 340                                    "Ljava/lang/String;");
 341     string_object = (jstring) (*env)->GetObjectField(env, obj, string_id);
 342     const char* signature= (*env)->GetStringUTFChars(env, string_object, 0);
 343 
 344     native_frames[i].name = method;
 345     native_frames[i].file_name = file_name;
 346     native_frames[i].signature = signature;
 347     native_frames[i].line_number = line_number;
 348   }
 349 }
 350 
 351 static jboolean check_and(JNIEnv *env, jobjectArray frames, int live,
 352                           int recent, int frequent, int print_out) {
 353   jobject loader = NULL;
 354 
 355   if (frames == NULL) {
 356     return FALSE;
 357   }
 358 
 359   // Start by transforming the frames into a C-friendly structure.
 360   jsize size = (*env)->GetArrayLength(env, frames);
 361   ExpectedContentFrame native_frames[size];
 362   fill_native_frames(env, frames, native_frames, size);
 363 
 364   if (jvmti == NULL) {
 365     throw_exc(env, "JVMTI client was not properly loaded!\n");
 366     return FALSE;
 367   }
 368 
 369   int result = TRUE;
 370 
 371   if (live) {
 372     result = frames_exist_live(env, native_frames, size, print_out);
 373   }
 374 
 375   if (recent) {
 376     result = result &&
 377         frames_exist_recent(env, native_frames, size, print_out);
 378   }
 379 
 380   if (frequent) {
 381     result = result &&
 382         frames_exist_frequent(env, native_frames, size, print_out);
 383   }
 384 
 385   return result;
 386 }
 387 
 388 static jboolean check_or(JNIEnv *env, jobjectArray frames, int live, int recent,
 389                          int frequent, int print_out) {
 390   jobject loader = NULL;
 391 
 392   if (frames == NULL) {
 393     return FALSE;
 394   }
 395 
 396   // Start by transforming the frames into a C-friendly structure.
 397   jsize size = (*env)->GetArrayLength(env, frames);
 398   ExpectedContentFrame native_frames[size];
 399   fill_native_frames(env, frames, native_frames, size);
 400 
 401   if (jvmti == NULL) {
 402     throw_exc(env, "JVMTI client was not properly loaded!\n");
 403     return FALSE;
 404   }
 405 
 406   jboolean result = FALSE;
 407 
 408   if (live) {
 409     result = frames_exist_live(env, native_frames, size, print_out);
 410   }
 411 
 412   if (recent) {
 413     result = result ||
 414         frames_exist_recent(env, native_frames, size, print_out);
 415   }
 416 
 417   if (frequent) {
 418     result = result ||
 419         frames_exist_frequent(env, native_frames, size, print_out);
 420   }
 421 
 422   return result;
 423 }
 424 
 425 static jboolean checkAll(JNIEnv *env, jobjectArray frames, int print_out) {
 426   return check_and(env, frames, 1, 1, 1, print_out);
 427 }
 428 
 429 static jboolean checkNone(JNIEnv *env, jobjectArray frames,
 430                           int print_out) {
 431   jobject loader = NULL;
 432 
 433   if (frames == NULL) {
 434     return FALSE;
 435   }
 436 
 437   // Start by transforming the frames into a C-friendly structure.
 438   jsize size = (*env)->GetArrayLength(env, frames);
 439   ExpectedContentFrame native_frames[size];
 440   fill_native_frames(env, frames, native_frames, size);
 441 
 442   if (jvmti == NULL) {
 443     throw_exc(env, "JVMTI client was not properly loaded!\n");
 444     return FALSE ;
 445   }
 446 
 447   if ((!frames_exist_live(env, native_frames, size, print_out)) &&
 448       (!frames_exist_recent(env, native_frames, size, print_out)) &&
 449       (!frames_exist_frequent(env, native_frames, size, print_out))) {
 450     return TRUE;
 451   }
 452   return FALSE;
 453 }
 454 
 455 JNIEXPORT void JNICALL
 456 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate,
 457                                           int max_traces) {
 458   check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces),
 459               "Start Heap Sampling");
 460 }
 461 
 462 JNIEXPORT void JNICALL
 463 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) {
 464   check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
 465 }
 466 
 467 JNIEXPORT jboolean JNICALL
 468 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) {
 469   jvmtiHeapSamplingStats stats;
 470   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 471               "Heap Sampling Statistics");
 472 
 473   jvmtiHeapSamplingStats zero;
 474   memset(&zero, 0, sizeof(zero));
 475   return memcmp(&stats, &zero, sizeof(zero)) == 0;
 476 }
 477 
 478 JNIEXPORT jboolean JNICALL
 479 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls,
 480                                                  jobjectArray frames) {
 481   // We want the frames in each part.
 482   return checkAll(env, frames, PRINT_OUT);
 483 }
 484 
 485 JNIEXPORT jboolean JNICALL
 486 Java_MyPackage_HeapMonitor_framesExistNowhere(JNIEnv *env, jclass cls,
 487                                               jobjectArray frames) {
 488   // We want the frames in none of the parts.
 489   return checkNone(env, frames, PRINT_OUT);
 490 }
 491 
 492 JNIEXPORT jboolean JNICALL
 493 Java_MyPackage_HeapMonitor_framesExistSomewhere(JNIEnv *env, jclass cls,
 494                                                 jobjectArray frames) {
 495   return check_or(env, frames, TRUE, TRUE, TRUE, PRINT_OUT);
 496 }
 497 
 498 JNIEXPORT jboolean JNICALL
 499 Java_MyPackage_HeapMonitorRecentTest_framesNotInLiveOrRecent(JNIEnv *env,
 500                                                              jclass cls,
 501                                                              jobjectArray frames) {
 502   return !check_or(env, frames, TRUE, TRUE, FALSE, PRINT_OUT);
 503 }
 504 
 505 JNIEXPORT jboolean JNICALL
 506 Java_MyPackage_HeapMonitorRecentTest_framesExistInRecent(JNIEnv *env,
 507                                                          jclass cls,
 508                                                          jobjectArray frames) {
 509   return check_and(env, frames, FALSE, TRUE, FALSE, PRINT_OUT);
 510 }
 511 
 512 JNIEXPORT jboolean JNICALL
 513 Java_MyPackage_HeapMonitorFrequentTest_framesExistInFrequent(JNIEnv *env,
 514                                                              jclass cls,
 515                                                              jobjectArray frames) {
 516   return check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
 517 }
 518 
 519 JNIEXPORT jboolean JNICALL
 520 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 521                                                                   jclass cls) {
 522   jvmtiCapabilities caps;
 523   memset(&caps, 0, sizeof(caps));
 524   caps.can_sample_heap= 1;
 525   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 526                   "Add capabilities\n")){
 527     return FALSE;
 528   }
 529 
 530   if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
 531                                                          MAX_TRACES),
 532                              "Start Heap Sampling")) {
 533     return FALSE;
 534   }
 535 
 536   if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
 537                              "Stop Heap Sampling")) {
 538     return FALSE;
 539   }
 540 
 541   if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL),
 542                              "Release Traces")) {
 543     return FALSE;
 544   }
 545 
 546   if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
 547                              "Get Heap Sampling Stats")) {
 548     return FALSE;
 549   }
 550 
 551   if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL),
 552                              "Get Garbage Traces")) {
 553     return FALSE;
 554   }
 555 
 556   if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL),
 557                              "Get Frequent Garbage Traces")) {
 558     return FALSE;
 559   }
 560 
 561   if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL),
 562                              "Get Live Traces")) {
 563     return FALSE;
 564   }
 565   return TRUE;
 566 }
 567 
 568 JNIEXPORT jboolean JNICALL
 569 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env,
 570                                                           jclass cls,
 571                                                           int expected,
 572                                                           int percent_error) {
 573   jvmtiHeapSamplingStats stats;
 574   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 575               "Heap Sampling Statistics");
 576 
 577   double diff_ratio = (stats.sample_count - expected);
 578   diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
 579   diff_ratio /= expected;
 580 
 581   if (diff_ratio * 100 >= percent_error) {
 582     fprintf(stderr, "Problem with sample count, obtained %ld and expected %d\n",
 583             stats.sample_count, expected);
 584   }
 585   return diff_ratio * 100 < percent_error;
 586 }
 587 
 588 JNIEXPORT jdouble JNICALL
 589 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 590   jvmtiHeapSamplingStats stats;
 591   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 592               "Heap Sampling Statistics");
 593   return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count;
 594 }
 595 
 596 static double calculate_average_stack_depth(
 597     jvmtiError (*const get_traces)(jvmtiEnv*, jvmtiStackTraces*)) {
 598   jvmtiStackTraces traces;
 599 
 600   jvmtiError error = get_traces(jvmti, &traces);;
 601 
 602   if (error != JVMTI_ERROR_NONE) {
 603     return 0;
 604   }
 605 
 606   int trace_count = traces.trace_count;
 607 
 608   if (trace_count == 0) {
 609     return 0;
 610   }
 611 
 612   int i;
 613   jvmtiStackTrace* stack_traces = traces.stack_traces;
 614   double sum = 0;
 615   for (i = 0; i < trace_count; i++) {
 616     jvmtiStackTrace *stack_trace = stack_traces + i;
 617     sum += stack_trace->frame_count;
 618   }
 619 
 620   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 621     return 0;
 622   }
 623 
 624   return sum / i;
 625 }
 626 
 627 JNIEXPORT jdouble JNICALL
 628 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env,
 629                                                               jclass cls) {
 630   double result = calculate_average_stack_depth((*jvmti)->GetLiveTraces);
 631 
 632   if (result != 0) {
 633     return result;
 634   }
 635 
 636   // It is possible all the live objects got collected, check the garbage traces
 637   // in case.
 638   return calculate_average_stack_depth((*jvmti)->GetGarbageTraces);
 639 }
 640 
 641 typedef struct sThreadsFound {
 642   jint *threads;
 643   int num_threads;
 644 } ThreadsFound;
 645 
 646 static void find_threads_in_traces(jvmtiStackTraces* traces,
 647                                    ThreadsFound* thread_data) {
 648   int i;
 649   jvmtiStackTrace* stack_traces = traces->stack_traces;
 650   int trace_count = traces->trace_count;
 651 
 652   jint *threads = thread_data->threads;
 653   int num_threads = thread_data->num_threads;
 654 
 655   // We are looking for at last expected_num_threads different traces.
 656   for (i = 0; i < trace_count; i++) {
 657     jvmtiStackTrace *stack_trace = stack_traces + i;
 658     jlong thread_id = stack_trace->thread_id;
 659 
 660     // Check it is the right frame: only accept helper top framed traces.
 661     jmethodID methodid = stack_trace->frames[0].method;
 662     char *name = NULL, *signature = NULL, *file_name = NULL;
 663     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 664 
 665     if (strcmp(name, "helper")) {
 666       continue;
 667     }
 668 
 669     // Really not efficient look-up but it's for a test...
 670     int found = 0;
 671     int j;
 672     for (j = 0; j < num_threads; j++) {
 673       if (thread_id == threads[j]) {
 674         found = 1;
 675         break;
 676       }
 677     }
 678 
 679     if (!found) {
 680       threads[num_threads] = thread_id;
 681       num_threads++;
 682     }
 683   }
 684   thread_data->num_threads = num_threads;
 685 }
 686 
 687 JNIEXPORT jboolean JNICALL
 688 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
 689                                                   jintArray threads) {
 690   jvmtiStackTraces traces;
 691   ThreadsFound thread_data;
 692   thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0);
 693   thread_data.num_threads = 0;
 694 
 695   // Get live and garbage traces to ensure we capture all the threads that have
 696   // been sampled.
 697   if ((*jvmti)->GetLiveTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 698     return FALSE;
 699   }
 700 
 701   find_threads_in_traces(&traces, &thread_data);
 702 
 703   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 704     return FALSE;
 705   }
 706 
 707   if ((*jvmti)->GetGarbageTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 708     return FALSE;
 709   }
 710 
 711   find_threads_in_traces(&traces, &thread_data);
 712 
 713   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 714     return FALSE;
 715   }
 716 
 717   (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0);
 718   return TRUE;
 719 }
 720 
 721 JNIEXPORT void JNICALL
 722 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env,
 723                                                             jclass cls) {
 724   jvmtiStackTraces live_traces;
 725   jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &live_traces);
 726 
 727   if (error != JVMTI_ERROR_NONE) {
 728     return;
 729   }
 730 
 731   (*jvmti)->ReleaseTraces(jvmti, &live_traces);
 732 }
 733 
 734 static jboolean compare_traces(jvmtiStackTraces* traces,
 735                                jvmtiStackTraces* other_traces,
 736                                int print_out_comparisons) {
 737   int trace_count = traces->trace_count;
 738   if (trace_count != other_traces->trace_count) {
 739     return FALSE;
 740   }
 741 
 742   int i;
 743   for (i = 0; i < trace_count; i++) {
 744     jvmtiStackTrace* trace = traces->stack_traces + i;
 745     jvmtiStackTrace* other_trace = other_traces->stack_traces + i;
 746 
 747     if (trace->frame_count != other_trace->frame_count) {
 748       return FALSE;
 749     }
 750 
 751     if (trace->size != other_trace->size) {
 752       return FALSE;
 753     }
 754 
 755     if (trace->thread_id != other_trace->thread_id) {
 756       return FALSE;
 757     }
 758 
 759     jvmtiFrameInfo* frames = trace->frames;
 760     jvmtiFrameInfo* other_frames = other_trace->frames;
 761     if (memcmp(frames, other_frames, sizeof(*frames) * trace->frame_count)) {
 762       return FALSE;
 763     }
 764   }
 765 
 766   return TRUE;
 767 }
 768 
 769 JNIEXPORT jboolean JNICALL
 770 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
 771                                                           jclass cls) {
 772   // Get cached first, then get live (since live performs a GC).
 773   jvmtiStackTraces cached_traces;
 774   jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces);
 775 
 776   if (error != JVMTI_ERROR_NONE) {
 777     return FALSE;
 778   }
 779 
 780   jvmtiStackTraces live_traces;
 781   error = (*jvmti)->GetLiveTraces(jvmti, &live_traces);
 782 
 783   if (error != JVMTI_ERROR_NONE) {
 784     return FALSE;
 785   }
 786 
 787   int result = compare_traces(&cached_traces, &live_traces, PRINT_OUT);
 788 
 789   (*jvmti)->ReleaseTraces(jvmti, &cached_traces);
 790   (*jvmti)->ReleaseTraces(jvmti, &live_traces);
 791   return result;
 792 }
 793 
 794 static long hash(long hash_code, long value) {
 795   return hash_code * 31 + value;
 796 }
 797 
 798 static long get_hash_code(jvmtiStackTraces* traces) {
 799   int trace_count = traces->trace_count;
 800   int hash_code = 17;
 801 
 802   int i;
 803   hash_code = hash(hash_code, trace_count);
 804   for (i = 0; i < trace_count; i++) {
 805     jvmtiStackTrace* trace = traces->stack_traces + i;
 806     hash_code = hash(hash_code, trace->frame_count);
 807     hash_code = hash(hash_code, trace->size);
 808     hash_code = hash(hash_code, trace->thread_id);
 809 
 810     int j;
 811     int frame_count = trace->frame_count;
 812     jvmtiFrameInfo* frames = trace->frames;
 813     hash_code = hash(hash_code, frame_count);
 814     for (j = 0; j < frame_count; j++) {
 815       hash_code = hash(hash_code, (long) frames[i].method);
 816       hash_code = hash(hash_code, frames[i].location);
 817     }
 818   }
 819 
 820   return TRUE;
 821 }
 822 
 823 JNIEXPORT jlong JNICALL
 824 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env,
 825                                                        jclass cls) {
 826   // Get cached first, then get live.
 827   jvmtiStackTraces cached_traces;
 828   jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces);
 829 
 830   if (error != JVMTI_ERROR_NONE) {
 831     return 0;
 832   }
 833 
 834   long hash_code = get_hash_code(&cached_traces);
 835   (*jvmti)->ReleaseTraces(jvmti, &cached_traces);
 836 
 837   return hash_code;
 838 }
 839 
 840 JNIEXPORT jboolean JNICALL
 841 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
 842                                                 jclass cls,
 843                                                 jobjectArray frames) {
 844   return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
 845 }
 846 
 847 #ifdef __cplusplus
 848 }
 849 #endif