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