|
19 | 19 | */
|
20 | 20 |
|
21 | 21 | #include <stdio.h>
|
| 22 | +#include <string.h> |
22 | 23 |
|
23 | 24 | #include <sys/types.h>
|
24 | 25 |
|
25 | 26 | #include <jni.h>
|
26 | 27 | #include <jvmti.h>
|
27 |
| -#include <string.h> |
| 28 | +#include <jvmticmlr.h> |
28 | 29 |
|
29 | 30 | #include "perf-map-file.h"
|
30 | 31 |
|
31 | 32 | FILE *method_file = NULL;
|
| 33 | +int unfold_inlined_methods = 0; |
32 | 34 |
|
33 | 35 | void ensure_open() {
|
34 | 36 | if (!method_file)
|
35 | 37 | method_file = perf_map_open(getpid());
|
36 | 38 | }
|
37 | 39 |
|
38 |
| -static void JNICALL |
39 |
| -cbCompiledMethodLoad(jvmtiEnv *env, |
40 |
| - jmethodID method, |
41 |
| - jint code_size, |
42 |
| - const void* code_addr, |
43 |
| - jint map_length, |
44 |
| - const jvmtiAddrLocationMap* map, |
45 |
| - const void* compile_info) { |
| 40 | +static int get_line_number(jvmtiLineNumberEntry *table, jint entry_count, jlocation loc) { |
| 41 | + int i; |
| 42 | + for (i = 0; i < entry_count; i++) |
| 43 | + if (table[i].start_location > loc) return table[i - 1].line_number; |
| 44 | + |
| 45 | + return -1; |
| 46 | +} |
| 47 | + |
| 48 | +static void sig_string(jvmtiEnv *jvmti, jmethodID method, char *output, size_t noutput) { |
46 | 49 | char *name;
|
47 | 50 | char *msig;
|
48 |
| - (*env)->GetMethodName(env, method, &name, &msig, NULL); |
49 |
| - |
50 | 51 | jclass class;
|
51 |
| - (*env)->GetMethodDeclaringClass(env, method, &class); |
52 | 52 | char *csig;
|
53 |
| - (*env)->GetClassSignature(env, class, &csig, NULL); |
54 | 53 |
|
55 |
| - char entry[100]; |
56 |
| - snprintf(entry, sizeof(entry), "%s.%s%s", csig, name, msig); |
| 54 | + (*jvmti)->GetMethodName(jvmti, method, &name, &msig, NULL); |
| 55 | + (*jvmti)->GetMethodDeclaringClass(jvmti, method, &class); |
| 56 | + (*jvmti)->GetClassSignature(jvmti, class, &csig, NULL); |
57 | 57 |
|
58 |
| - ensure_open(); |
| 58 | + snprintf(output, noutput, "%s.%s%s", csig, name, msig); |
| 59 | + |
| 60 | + (*jvmti)->Deallocate(jvmti, name); |
| 61 | + (*jvmti)->Deallocate(jvmti, msig); |
| 62 | + (*jvmti)->Deallocate(jvmti, csig); |
| 63 | +} |
| 64 | + |
| 65 | +void generate_single_entry(jvmtiEnv *jvmti, jmethodID method, const void *code_addr, jint code_size) { |
| 66 | + char entry[100]; |
| 67 | + sig_string(jvmti, method, entry, sizeof(entry)); |
59 | 68 | perf_map_write_entry(method_file, code_addr, code_size, entry);
|
| 69 | +} |
60 | 70 |
|
61 |
| - (*env)->Deallocate(env, name); |
62 |
| - (*env)->Deallocate(env, msig); |
63 |
| - (*env)->Deallocate(env, csig); |
| 71 | +void generate_unfolded_entries( |
| 72 | + jvmtiEnv *jvmti, |
| 73 | + jmethodID method, |
| 74 | + jint code_size, |
| 75 | + const void* code_addr, |
| 76 | + jint map_length, |
| 77 | + const jvmtiAddrLocationMap* map, |
| 78 | + const void* compile_info) { |
| 79 | + int i; |
| 80 | + const jvmtiCompiledMethodLoadRecordHeader *header = compile_info; |
| 81 | + char root_name[1000]; |
| 82 | + char entry_name[1000]; |
| 83 | + char entry[1000]; |
| 84 | + sig_string(jvmti, method, root_name, sizeof(root_name)); |
| 85 | + if (header->kind == JVMTI_CMLR_INLINE_INFO) { |
| 86 | + const char *entry_p; |
| 87 | + const jvmtiCompiledMethodLoadInlineRecord *record = (jvmtiCompiledMethodLoadInlineRecord *) header; |
| 88 | + |
| 89 | + const void *start_addr = code_addr; |
| 90 | + jmethodID cur_method = method; |
| 91 | + for (i = 0; i < record->numpcs; i++) { |
| 92 | + PCStackInfo *info = &record->pcinfo[i]; |
| 93 | + jmethodID top_method = info->methods[0]; |
| 94 | + if (cur_method != top_method) { |
| 95 | + void *end_addr = info->pc; |
| 96 | + |
| 97 | + if (top_method != method) { |
| 98 | + sig_string(jvmti, top_method, entry_name, sizeof(entry_name)); |
| 99 | + snprintf(entry, sizeof(entry), "%s in %s", entry_name, root_name); |
| 100 | + entry_p = entry; |
| 101 | + } else |
| 102 | + entry_p = root_name; |
| 103 | + |
| 104 | + perf_map_write_entry(method_file, start_addr, end_addr - start_addr, entry_p); |
| 105 | + |
| 106 | + start_addr = info->pc; |
| 107 | + cur_method = top_method; |
| 108 | + } |
| 109 | + } |
| 110 | + if (start_addr != code_addr + code_size) { |
| 111 | + const void *end_addr = code_addr + code_size; |
| 112 | + sig_string(jvmti, cur_method, entry_name, sizeof(entry_name)); |
| 113 | + snprintf(entry, sizeof(entry), "%s in %s", entry_name, root_name); |
| 114 | + |
| 115 | + perf_map_write_entry(method_file, start_addr, end_addr - start_addr, entry_p); |
| 116 | + } |
| 117 | + } else |
| 118 | + generate_single_entry(jvmti, method, code_addr, code_size); |
| 119 | +} |
| 120 | + |
| 121 | +static void JNICALL |
| 122 | +cbCompiledMethodLoad( |
| 123 | + jvmtiEnv *jvmti, |
| 124 | + jmethodID method, |
| 125 | + jint code_size, |
| 126 | + const void* code_addr, |
| 127 | + jint map_length, |
| 128 | + const jvmtiAddrLocationMap* map, |
| 129 | + const void* compile_info) { |
| 130 | + ensure_open(); |
| 131 | + if (unfold_inlined_methods) |
| 132 | + generate_unfolded_entries(jvmti, method, code_size, code_addr, map_length, map, compile_info); |
| 133 | + else |
| 134 | + generate_single_entry(jvmti, method, code_addr, code_size); |
64 | 135 | }
|
65 | 136 |
|
66 | 137 | void JNICALL
|
67 |
| -cbDynamicCodeGenerated(jvmtiEnv *jvmti_env, |
| 138 | +cbDynamicCodeGenerated(jvmtiEnv *jvmti, |
68 | 139 | const char* name,
|
69 | 140 | const void* address,
|
70 | 141 | jint length) {
|
@@ -109,6 +180,8 @@ Agent_OnAttach(JavaVM *vm, char *options, void *reserved) {
|
109 | 180 | ensure_open();
|
110 | 181 | ftruncate(fileno(method_file));
|
111 | 182 |
|
| 183 | + unfold_inlined_methods = strstr(options, "unfold") != NULL; |
| 184 | + |
112 | 185 | jvmtiEnv *jvmti;
|
113 | 186 | (*vm)->GetEnv(vm, (void **)&jvmti, JVMTI_VERSION_1);
|
114 | 187 | enable_capabilities(jvmti);
|
|
0 commit comments