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   fprintf(stderr, "Checking all!!!\n");
 427   return check_and(env, frames, 1, 1, 1, print_out);
 428 }
 429 
 430 static jboolean checkNone(JNIEnv *env, jobjectArray frames,
 431                           int print_out) {
 432   fprintf(stderr, "Checking none!!!\n");
 433   jobject loader = NULL;
 434 
 435   if (frames == NULL) {
 436     return FALSE;
 437   }
 438 
 439   // Start by transforming the frames into a C-friendly structure.
 440   jsize size = (*env)->GetArrayLength(env, frames);
 441   ExpectedContentFrame native_frames[size];
 442   fill_native_frames(env, frames, native_frames, size);
 443 
 444   if (jvmti == NULL) {
 445     throw_exc(env, "JVMTI client was not properly loaded!\n");
 446     return FALSE ;
 447   }
 448 
 449   if ((!frames_exist_live(env, native_frames, size, print_out)) &&
 450       (!frames_exist_recent(env, native_frames, size, print_out)) &&
 451       (!frames_exist_frequent(env, native_frames, size, print_out))) {
 452     return TRUE;
 453   }
 454   return FALSE;
 455 }
 456 
 457 JNIEXPORT void JNICALL
 458 Java_MyPackage_HeapMonitor_enableSampling(JNIEnv *env, jclass cls, int rate,
 459                                           int max_traces) {
 460   check_error((*jvmti)->StartHeapSampling(jvmti, rate, max_traces),
 461               "Start Heap Sampling");
 462 }
 463 
 464 JNIEXPORT void JNICALL
 465 Java_MyPackage_HeapMonitor_disableSampling(JNIEnv *env, jclass cls) {
 466   check_error((*jvmti)->StopHeapSampling(jvmti), "Stop Heap Sampling");
 467 }
 468 
 469 JNIEXPORT jboolean JNICALL
 470 Java_MyPackage_HeapMonitor_areSamplingStatisticsZero(JNIEnv *env, jclass cls) {
 471   jvmtiHeapSamplingStats stats;
 472   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 473               "Heap Sampling Statistics");
 474 
 475   jvmtiHeapSamplingStats zero;
 476   memset(&zero, 0, sizeof(zero));
 477   return memcmp(&stats, &zero, sizeof(zero)) == 0;
 478 }
 479 
 480 JNIEXPORT jboolean JNICALL
 481 Java_MyPackage_HeapMonitor_framesExistEverywhere(JNIEnv *env, jclass cls,
 482                                                  jobjectArray frames) {
 483   // We want the frames in each part.
 484   return checkAll(env, frames, PRINT_OUT);
 485 }
 486 
 487 JNIEXPORT jboolean JNICALL
 488 Java_MyPackage_HeapMonitor_framesExistNowhere(JNIEnv *env, jclass cls,
 489                                               jobjectArray frames) {
 490   // We want the frames in none of the parts.
 491   return checkNone(env, frames, PRINT_OUT);
 492 }
 493 
 494 JNIEXPORT jboolean JNICALL
 495 Java_MyPackage_HeapMonitorRecentTest_framesNotInLiveOrRecent(JNIEnv *env,
 496                                                              jclass cls,
 497                                                              jobjectArray frames) {
 498   return !check_or(env, frames, TRUE, TRUE, FALSE, PRINT_OUT);
 499 }
 500 
 501 JNIEXPORT jboolean JNICALL
 502 Java_MyPackage_HeapMonitorRecentTest_framesExistInLiveAndRecent(JNIEnv *env,
 503                                                                 jclass cls,
 504                                                                 jobjectArray frames) {
 505   return check_and(env, frames, TRUE, TRUE, FALSE, PRINT_OUT);
 506 }
 507 
 508 JNIEXPORT jboolean JNICALL
 509 Java_MyPackage_HeapMonitorFrequentTest_framesExistInFrequent(JNIEnv *env,
 510                                                              jclass cls,
 511                                                              jobjectArray frames) {
 512   return check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
 513 }
 514 
 515 JNIEXPORT jboolean JNICALL
 516 Java_MyPackage_HeapMonitorNoCapabilityTest_allSamplingMethodsFail(JNIEnv *env,
 517                                                                   jclass cls) {
 518   jvmtiCapabilities caps;
 519   memset(&caps, 0, sizeof(caps));
 520   caps.can_sample_heap= 1;
 521   if (check_error((*jvmti)->RelinquishCapabilities(jvmti, &caps),
 522                   "Add capabilities\n")){
 523     return FALSE;
 524   }
 525 
 526   if (check_capability_error((*jvmti)->StartHeapSampling(jvmti, 1<<19,
 527                                                          MAX_TRACES),
 528                              "Start Heap Sampling")) {
 529     return FALSE;
 530   }
 531 
 532   if (check_capability_error((*jvmti)->StopHeapSampling(jvmti),
 533                              "Stop Heap Sampling")) {
 534     return FALSE;
 535   }
 536 
 537   if (check_capability_error((*jvmti)->ReleaseTraces(jvmti, NULL),
 538                              "Release Traces")) {
 539     return FALSE;
 540   }
 541 
 542   if (check_capability_error((*jvmti)->GetHeapSamplingStats(jvmti, NULL),
 543                              "Get Heap Sampling Stats")) {
 544     return FALSE;
 545   }
 546 
 547   if (check_capability_error((*jvmti)->GetGarbageTraces(jvmti, NULL),
 548                              "Get Garbage Traces")) {
 549     return FALSE;
 550   }
 551 
 552   if (check_capability_error((*jvmti)->GetFrequentGarbageTraces(jvmti, NULL),
 553                              "Get Frequent Garbage Traces")) {
 554     return FALSE;
 555   }
 556 
 557   if (check_capability_error((*jvmti)->GetLiveTraces(jvmti, NULL),
 558                              "Get Live Traces")) {
 559     return FALSE;
 560   }
 561   return TRUE;
 562 }
 563 
 564 JNIEXPORT jboolean JNICALL
 565 Java_MyPackage_HeapMonitor_statsHaveExpectedNumberSamples(JNIEnv *env,
 566                                                           jclass cls,
 567                                                           int expected,
 568                                                           int percent_error) {
 569   jvmtiHeapSamplingStats stats;
 570   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 571               "Heap Sampling Statistics");
 572 
 573   fprintf(stderr, "Sample data count %ld, rate %ld, rate count %ld\n",
 574           stats.sample_count, stats.sample_rate_accumulation, stats.sample_rate_count);
 575   double diff_ratio = (stats.sample_count - expected);
 576   diff_ratio = (diff_ratio < 0) ? -diff_ratio : diff_ratio;
 577   diff_ratio /= expected;
 578 
 579   return diff_ratio * 100 < percent_error;
 580 }
 581 
 582 JNIEXPORT jdouble JNICALL
 583 Java_MyPackage_HeapMonitorStatRateTest_getAverageRate(JNIEnv *env, jclass cls) {
 584   jvmtiHeapSamplingStats stats;
 585   check_error((*jvmti)->GetHeapSamplingStats(jvmti, &stats),
 586               "Heap Sampling Statistics");
 587   return ((double) stats.sample_rate_accumulation) / stats.sample_rate_count;
 588 }
 589 
 590 JNIEXPORT jdouble JNICALL
 591 Java_MyPackage_HeapMonitorStackDepthTest_getAverageStackDepth(JNIEnv *env,
 592                                                               jclass cls) {
 593   jvmtiStackTraces traces;
 594   jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &traces);;
 595 
 596   if (error != JVMTI_ERROR_NONE) {
 597     return 0;
 598   }
 599 
 600   int trace_count = traces.trace_count;
 601 
 602   if (trace_count == 0) {
 603     return 0;
 604   }
 605 
 606   int i;
 607   jvmtiStackTrace* stack_traces = traces.stack_traces;
 608   double sum = 0;
 609   for (i = 0; i < trace_count; i++) {
 610     jvmtiStackTrace *stack_trace = stack_traces + i;
 611     sum += stack_trace->frame_count;
 612   }
 613 
 614   return sum / i;
 615 }
 616 
 617 typedef struct sThreadsFound {
 618   jint *threads;
 619   int num_threads;
 620 } ThreadsFound;
 621 
 622 static void find_threads_in_traces(jvmtiStackTraces* traces,
 623                                    ThreadsFound* thread_data) {
 624   int i;
 625   jvmtiStackTrace* stack_traces = traces->stack_traces;
 626   int trace_count = traces->trace_count;
 627 
 628   jint *threads = thread_data->threads;
 629   int num_threads = thread_data->num_threads;
 630 
 631   // We are looking for at last expected_num_threads different traces.
 632   for (i = 0; i < trace_count; i++) {
 633     jvmtiStackTrace *stack_trace = stack_traces + i;
 634     jlong thread_id = stack_trace->thread_id;
 635 
 636     // Check it is the right frame: only accept helper top framed traces.
 637     jmethodID methodid = stack_trace->frames[0].method;
 638     char *name = NULL, *signature = NULL, *file_name = NULL;
 639     (*jvmti)->GetMethodName(jvmti, methodid, &name, &signature, 0);
 640 
 641     if (strcmp(name, "helper")) {
 642       continue;
 643     }
 644 
 645     // Really not efficient look-up but it's for a test...
 646     int found = 0;
 647     int j;
 648     for (j = 0; j < num_threads; j++) {
 649       if (thread_id == threads[j]) {
 650         found = 1;
 651         break;
 652       }
 653     }
 654 
 655     if (!found) {
 656       threads[num_threads] = thread_id;
 657       num_threads++;
 658     }
 659   }
 660   thread_data->num_threads = num_threads;
 661 }
 662 
 663 JNIEXPORT jboolean JNICALL
 664 Java_MyPackage_HeapMonitorThreadTest_checkSamples(JNIEnv* env, jclass cls,
 665                                                   jintArray threads) {
 666   jvmtiStackTraces traces;
 667   ThreadsFound thread_data;
 668   thread_data.threads = (*env)->GetIntArrayElements(env, threads, 0);
 669   thread_data.num_threads = 0;
 670 
 671   // Get live and garbage traces to ensure we capture all the threads that have
 672   // been sampled.
 673   if ((*jvmti)->GetLiveTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 674     return FALSE;
 675   }
 676 
 677   find_threads_in_traces(&traces, &thread_data);
 678 
 679   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 680     return FALSE;
 681   }
 682 
 683   if ((*jvmti)->GetGarbageTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 684     return FALSE;
 685   }
 686 
 687   find_threads_in_traces(&traces, &thread_data);
 688 
 689   if ((*jvmti)->ReleaseTraces(jvmti, &traces) != JVMTI_ERROR_NONE) {
 690     return FALSE;
 691   }
 692 
 693   (*env)->ReleaseIntArrayElements(env, threads, thread_data.threads, 0);
 694   return TRUE;
 695 }
 696 
 697 JNIEXPORT void JNICALL
 698 Java_MyPackage_HeapMonitorCachedTest_getLiveTracesToForceGc(JNIEnv *env,
 699                                                             jclass cls) {
 700   jvmtiStackTraces live_traces;
 701   jvmtiError error = (*jvmti)->GetLiveTraces(jvmti, &live_traces);
 702 
 703   if (error != JVMTI_ERROR_NONE) {
 704     return;
 705   }
 706 
 707   (*jvmti)->ReleaseTraces(jvmti, &live_traces);
 708 }
 709 
 710 static jboolean compare_traces(jvmtiStackTraces* traces,
 711                                jvmtiStackTraces* other_traces,
 712                                int print_out_comparisons) {
 713   int trace_count = traces->trace_count;
 714   if (trace_count != other_traces->trace_count) {
 715     return FALSE;
 716   }
 717 
 718   int i;
 719   for (i = 0; i < trace_count; i++) {
 720     jvmtiStackTrace* trace = traces->stack_traces + i;
 721     jvmtiStackTrace* other_trace = other_traces->stack_traces + i;
 722 
 723     if (trace->frame_count != other_trace->frame_count) {
 724       return FALSE;
 725     }
 726 
 727     if (trace->size != other_trace->size) {
 728       return FALSE;
 729     }
 730 
 731     if (trace->thread_id != other_trace->thread_id) {
 732       return FALSE;
 733     }
 734 
 735     jvmtiFrameInfo* frames = trace->frames;
 736     jvmtiFrameInfo* other_frames = other_trace->frames;
 737     if (memcmp(frames, other_frames, sizeof(*frames) * trace->frame_count)) {
 738       return FALSE;
 739     }
 740   }
 741 
 742   return TRUE;
 743 }
 744 
 745 JNIEXPORT jboolean JNICALL
 746 Java_MyPackage_HeapMonitorCachedTest_cachedAndLiveAreSame(JNIEnv *env,
 747                                                           jclass cls) {
 748   // Get cached first, then get live (since live performs a GC).
 749   jvmtiStackTraces cached_traces;
 750   jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces);
 751 
 752   if (error != JVMTI_ERROR_NONE) {
 753     return FALSE;
 754   }
 755 
 756   jvmtiStackTraces live_traces;
 757   error = (*jvmti)->GetLiveTraces(jvmti, &live_traces);
 758 
 759   if (error != JVMTI_ERROR_NONE) {
 760     return FALSE;
 761   }
 762 
 763   int result = compare_traces(&cached_traces, &live_traces, PRINT_OUT);
 764 
 765   (*jvmti)->ReleaseTraces(jvmti, &cached_traces);
 766   (*jvmti)->ReleaseTraces(jvmti, &live_traces);
 767   return result;
 768 }
 769 
 770 static long hash(long hash_code, long value) {
 771   return hash_code * 31 + value;
 772 }
 773 
 774 static long get_hash_code(jvmtiStackTraces* traces) {
 775   int trace_count = traces->trace_count;
 776   int hash_code = 17;
 777 
 778   int i;
 779   hash_code = hash(hash_code, trace_count);
 780   for (i = 0; i < trace_count; i++) {
 781     jvmtiStackTrace* trace = traces->stack_traces + i;
 782     hash_code = hash(hash_code, trace->frame_count);
 783     hash_code = hash(hash_code, trace->size);
 784     hash_code = hash(hash_code, trace->thread_id);
 785 
 786     int j;
 787     int frame_count = trace->frame_count;
 788     jvmtiFrameInfo* frames = trace->frames;
 789     hash_code = hash(hash_code, frame_count);
 790     for (j = 0; j < frame_count; j++) {
 791       hash_code = hash(hash_code, (long) frames[i].method);
 792       hash_code = hash(hash_code, frames[i].location);
 793     }
 794   }
 795 
 796   return TRUE;
 797 }
 798 
 799 JNIEXPORT jlong JNICALL
 800 Java_MyPackage_HeapMonitorCachedTest_getCachedHashCode(JNIEnv *env,
 801                                                        jclass cls) {
 802   // Get cached first, then get live.
 803   jvmtiStackTraces cached_traces;
 804   jvmtiError error = (*jvmti)->GetCachedTraces(jvmti, &cached_traces);
 805 
 806   if (error != JVMTI_ERROR_NONE) {
 807     return 0;
 808   }
 809 
 810   long hash_code = get_hash_code(&cached_traces);
 811   (*jvmti)->ReleaseTraces(jvmti, &cached_traces);
 812 
 813   return hash_code;
 814 }
 815 
 816 JNIEXPORT jboolean JNICALL
 817 Java_MyPackage_HeapMonitorTest_framesAreNotLive(JNIEnv *env,
 818                                                 jclass cls,
 819                                                 jobjectArray frames) {
 820   return !check_and(env, frames, FALSE, FALSE, TRUE, PRINT_OUT);
 821 }
 822 
 823 #ifdef __cplusplus
 824 }
 825 #endif