src/share/vm/jfr/instrumentation/jfrJvmtiAgent.cpp

changeset 9925
30fb8c8cceb9
parent 9858
b985cbb00e68
child 9986
85e682d8ab91
equal deleted inserted replaced
9924:89fb452b3688 9925:30fb8c8cceb9
1 /* 1 /*
2 * Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved. 2 * Copyright (c) 2016, 2019, Oracle and/or its affiliates. All rights reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 * 4 *
5 * This code is free software; you can redistribute it and/or modify it 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 6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
29 #include "jfr/jni/jfrUpcalls.hpp" 29 #include "jfr/jni/jfrUpcalls.hpp"
30 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp" 30 #include "jfr/recorder/checkpoint/types/traceid/jfrTraceId.inline.hpp"
31 #include "jfr/recorder/service/jfrOptionSet.hpp" 31 #include "jfr/recorder/service/jfrOptionSet.hpp"
32 #include "jfr/support/jfrEventClass.hpp" 32 #include "jfr/support/jfrEventClass.hpp"
33 #include "memory/resourceArea.hpp" 33 #include "memory/resourceArea.hpp"
34 #include "prims/jvmtiEnvBase.hpp"
34 #include "prims/jvmtiExport.hpp" 35 #include "prims/jvmtiExport.hpp"
36 #include "prims/jvmtiUtil.hpp"
35 #include "runtime/interfaceSupport.hpp" 37 #include "runtime/interfaceSupport.hpp"
36 #include "runtime/thread.inline.hpp" 38 #include "runtime/thread.inline.hpp"
37 #include "utilities/exceptions.hpp" 39 #include "utilities/exceptions.hpp"
38 40
39 static const size_t ERROR_MSG_BUFFER_SIZE = 256; 41 static const size_t ERROR_MSG_BUFFER_SIZE = 256;
49 NULL == errnum_str ? "Unknown" : errnum_str, 51 NULL == errnum_str ? "Unknown" : errnum_str,
50 NULL == str ? "" : str); 52 NULL == str ? "" : str);
51 } 53 }
52 } 54 }
53 55
54 static jvmtiError set_event_notification_mode(jvmtiEventMode mode, 56 static bool set_event_notification_mode(jvmtiEventMode mode,
55 jvmtiEvent event, 57 jvmtiEvent event,
56 jthread event_thread, 58 jthread event_thread,
57 ...) { 59 ...) {
58 if (jfr_jvmti_env == NULL) { 60 assert(jfr_jvmti_env != NULL, "invariant");
59 return JVMTI_ERROR_NONE;
60 }
61 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread); 61 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventNotificationMode(mode, event, event_thread);
62 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode"); 62 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventNotificationMode");
63 return jvmti_ret_code; 63 return jvmti_ret_code == JVMTI_ERROR_NONE;
64 } 64 }
65 65
66 static jvmtiError update_class_file_load_hook_event(jvmtiEventMode mode) { 66 static bool update_class_file_load_hook_event(jvmtiEventMode mode) {
67 return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL); 67 return set_event_notification_mode(mode, JVMTI_EVENT_CLASS_FILE_LOAD_HOOK, NULL);
68 } 68 }
69 69
70 static JavaThread* current_java_thread() { 70 static JavaThread* current_java_thread() {
71 Thread* this_thread = Thread::current(); 71 Thread* this_thread = Thread::current();
114 JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL); 114 JfrJavaSupport::throw_out_of_memory_error(error_buffer, CHECK_NULL);
115 } 115 }
116 return classes; 116 return classes;
117 } 117 }
118 118
119 static void log_and_throw(TRAPS) { 119 // caller needs ResourceMark
120 static void log_and_throw(jvmtiError error, TRAPS) {
120 if (!HAS_PENDING_EXCEPTION) { 121 if (!HAS_PENDING_EXCEPTION) {
121 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); 122 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
122 ThreadInVMfromNative tvmfn((JavaThread*)THREAD); 123 ThreadInVMfromNative tvmfn((JavaThread*)THREAD);
123 if (true) tty->print_cr("JfrJvmtiAgent::retransformClasses failed"); 124 const char base_error_msg[] = "JfrJvmtiAgent::retransformClasses failed: ";
124 JfrJavaSupport::throw_class_format_error("JfrJvmtiAgent::retransformClasses failed", THREAD); 125 size_t length = sizeof base_error_msg; // includes terminating null
126 const char* const jvmti_error_name = JvmtiUtil::error_name(error);
127 assert(jvmti_error_name != NULL, "invariant");
128 length += strlen(jvmti_error_name);
129 char* error_msg = NEW_RESOURCE_ARRAY(char, length);
130 jio_snprintf(error_msg, length, "%s%s", base_error_msg, jvmti_error_name);
131 if (JVMTI_ERROR_INVALID_CLASS_FORMAT == error) {
132 JfrJavaSupport::throw_class_format_error(error_msg, THREAD);
133 } else {
134 JfrJavaSupport::throw_runtime_exception(error_msg, THREAD);
135 }
125 } 136 }
126 } 137 }
127 138
128 static void check_exception_and_log(JNIEnv* env, TRAPS) { 139 static void check_exception_and_log(JNIEnv* env, TRAPS) {
129 assert(env != NULL, "invariant"); 140 assert(env != NULL, "invariant");
134 if (true) tty->print_cr("GetObjectArrayElement threw an exception"); 145 if (true) tty->print_cr("GetObjectArrayElement threw an exception");
135 return; 146 return;
136 } 147 }
137 } 148 }
138 149
150 static bool is_valid_jvmti_phase() {
151 return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE;
152 }
153
139 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { 154 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) {
140 assert(env != NULL, "invariant"); 155 assert(env != NULL, "invariant");
156 assert(classes_array != NULL, "invariant");
157 assert(is_valid_jvmti_phase(), "invariant");
141 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); 158 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
142 if (classes_array == NULL) {
143 return;
144 }
145 const jint classes_count = env->GetArrayLength(classes_array); 159 const jint classes_count = env->GetArrayLength(classes_array);
146 if (classes_count <= 0) { 160 if (classes_count <= 0) {
147 return; 161 return;
148 } 162 }
149 ResourceMark rm(THREAD); 163 ResourceMark rm(THREAD);
150 jclass* const classes = create_classes_array(classes_count, CHECK); 164 jclass* const classes = create_classes_array(classes_count, CHECK);
151 assert(classes != NULL, "invariant"); 165 assert(classes != NULL, "invariant");
152 for (jint i = 0; i < classes_count; i++) { 166 for (jint i = 0; i < classes_count; i++) {
153 jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); 167 jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i);
154 check_exception_and_log(env, THREAD); 168 check_exception_and_log(env, THREAD);
155 169 classes[i] = clz;
170 }
171 {
156 // inspecting the oop/klass requires a thread transition 172 // inspecting the oop/klass requires a thread transition
157 { 173 ThreadInVMfromNative transition((JavaThread*)THREAD);
158 ThreadInVMfromNative transition((JavaThread*)THREAD); 174 for (jint i = 0; i < classes_count; ++i) {
159 if (JdkJfrEvent::is_a(clz)) { 175 jclass clz = classes[i];
160 // should have been tagged already 176 if (!JdkJfrEvent::is_a(clz)) {
161 assert(JdkJfrEvent::is_subklass(clz), "invariant");
162 } else {
163 // outside the event hierarchy 177 // outside the event hierarchy
164 JdkJfrEvent::tag_as_host(clz); 178 JdkJfrEvent::tag_as_host(clz);
165 } 179 }
166 } 180 }
167 181 }
168 classes[i] = clz; 182 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD));
169 } 183 const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes);
170 if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) { 184 if (result != JVMTI_ERROR_NONE) {
171 log_and_throw(THREAD); 185 log_and_throw(result, THREAD);
172 } 186 }
173 } 187 }
174 188
175 static jvmtiError register_callbacks(JavaThread* jt) { 189 static bool register_callbacks(JavaThread* jt) {
176 assert(jfr_jvmti_env != NULL, "invariant"); 190 assert(jfr_jvmti_env != NULL, "invariant");
177 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); 191 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
178 jvmtiEventCallbacks callbacks; 192 jvmtiEventCallbacks callbacks;
179 /* Set callbacks */ 193 /* Set callbacks */
180 memset(&callbacks, 0, sizeof(callbacks)); 194 memset(&callbacks, 0, sizeof(callbacks));
181 callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; 195 callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook;
182 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 196 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
183 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); 197 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
184 return jvmti_ret_code; 198 return jvmti_ret_code == JVMTI_ERROR_NONE;
185 } 199 }
186 200
187 static jvmtiError register_capabilities(JavaThread* jt) { 201 static bool register_capabilities(JavaThread* jt) {
188 assert(jfr_jvmti_env != NULL, "invariant"); 202 assert(jfr_jvmti_env != NULL, "invariant");
189 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); 203 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
190 jvmtiCapabilities capabilities; 204 jvmtiCapabilities capabilities;
191 /* Add JVMTI capabilities */ 205 /* Add JVMTI capabilities */
192 (void)memset(&capabilities, 0, sizeof(capabilities)); 206 (void)memset(&capabilities, 0, sizeof(capabilities));
193 capabilities.can_retransform_classes = 1; 207 capabilities.can_retransform_classes = 1;
194 capabilities.can_retransform_any_class = 1; 208 capabilities.can_retransform_any_class = 1;
195 const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); 209 const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities);
196 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); 210 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities");
197 return jvmti_ret_code; 211 return jvmti_ret_code == JVMTI_ERROR_NONE;
198 } 212 }
199 213
200 static jint create_jvmti_env(JavaThread* jt) { 214 static jint create_jvmti_env(JavaThread* jt) {
201 assert(jfr_jvmti_env == NULL, "invariant"); 215 assert(jfr_jvmti_env == NULL, "invariant");
202 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); 216 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt));
203 extern struct JavaVM_ main_vm; 217 extern struct JavaVM_ main_vm;
204 JavaVM* vm = &main_vm; 218 JavaVM* vm = &main_vm;
205 return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); 219 return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION);
206 } 220 }
207 221
208 static jvmtiError unregister_callbacks(JavaThread* jt) { 222 static bool unregister_callbacks(JavaThread* jt) {
209 if (jfr_jvmti_env == NULL) { 223 assert(jfr_jvmti_env != NULL, "invariant");
210 return JVMTI_ERROR_NONE;
211 }
212 jvmtiEventCallbacks callbacks; 224 jvmtiEventCallbacks callbacks;
213 /* Set empty callbacks */ 225 /* Set empty callbacks */
214 memset(&callbacks, 0, sizeof(callbacks)); 226 memset(&callbacks, 0, sizeof(callbacks));
215 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); 227 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks));
216 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); 228 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks");
217 return jvmti_ret_code; 229 return jvmti_ret_code == JVMTI_ERROR_NONE;
218 } 230 }
219 231
220 JfrJvmtiAgent::JfrJvmtiAgent() {} 232 JfrJvmtiAgent::JfrJvmtiAgent() {}
221 233
222 JfrJvmtiAgent::~JfrJvmtiAgent() { 234 JfrJvmtiAgent::~JfrJvmtiAgent() {
223 JavaThread* jt = current_java_thread(); 235 JavaThread* jt = current_java_thread();
224 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); 236 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
225 ThreadToNativeFromVM transition(jt);
226 update_class_file_load_hook_event(JVMTI_DISABLE);
227 unregister_callbacks(jt);
228 if (jfr_jvmti_env != NULL) { 237 if (jfr_jvmti_env != NULL) {
238 ThreadToNativeFromVM transition(jt);
239 update_class_file_load_hook_event(JVMTI_DISABLE);
240 unregister_callbacks(jt);
229 jfr_jvmti_env->DisposeEnvironment(); 241 jfr_jvmti_env->DisposeEnvironment();
230 jfr_jvmti_env = NULL; 242 jfr_jvmti_env = NULL;
231 } 243 }
232 agent = NULL; 244 }
233 } 245
234 246 static bool initialize(JavaThread* jt) {
235 static bool initialize() {
236 JavaThread* const jt = current_java_thread();
237 assert(jt != NULL, "invariant"); 247 assert(jt != NULL, "invariant");
238 assert(jt->thread_state() == _thread_in_vm, "invariant");
239 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); 248 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt));
240 ThreadToNativeFromVM transition(jt); 249 ThreadToNativeFromVM transition(jt);
241 if (create_jvmti_env(jt) != JNI_OK) { 250 if (create_jvmti_env(jt) != JNI_OK) {
242 assert(jfr_jvmti_env == NULL, "invariant"); 251 assert(jfr_jvmti_env == NULL, "invariant");
243 return false; 252 return false;
244 } 253 }
245 assert(jfr_jvmti_env != NULL, "invariant"); 254 assert(jfr_jvmti_env != NULL, "invariant");
246 if (register_capabilities(jt) != JVMTI_ERROR_NONE) { 255 if (!register_capabilities(jt)) {
247 return false; 256 return false;
248 } 257 }
249 if (register_callbacks(jt) != JVMTI_ERROR_NONE) { 258 if (!register_callbacks(jt)) {
250 return false; 259 return false;
251 } 260 }
252 if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) { 261 return update_class_file_load_hook_event(JVMTI_ENABLE);
253 return false; 262 }
254 } 263
255 return true; 264 static void log_and_throw_illegal_state_exception(TRAPS) {
265 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD));
266 const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence.";
267 if (true) {
268 tty->print_cr("%s\n", illegal_state_msg);
269 tty->print_cr("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE.\n");
270 tty->print_cr("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START.\n");
271 }
272 JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD);
256 } 273 }
257 274
258 bool JfrJvmtiAgent::create() { 275 bool JfrJvmtiAgent::create() {
259 assert(jfr_jvmti_env == NULL, "invariant"); 276 assert(agent == NULL, "invariant");
277 JavaThread* const jt = current_java_thread();
278 if (!is_valid_jvmti_phase()) {
279 log_and_throw_illegal_state_exception(jt);
280 return false;
281 }
260 agent = new JfrJvmtiAgent(); 282 agent = new JfrJvmtiAgent();
261 if (agent == NULL) { 283 if (agent == NULL) {
262 return false; 284 return false;
263 } 285 }
264 if (!initialize()) { 286 if (!initialize(jt)) {
265 delete agent; 287 delete agent;
266 agent = NULL; 288 agent = NULL;
267 return false; 289 return false;
268 } 290 }
269 return true; 291 return true;
273 if (agent != NULL) { 295 if (agent != NULL) {
274 delete agent; 296 delete agent;
275 agent = NULL; 297 agent = NULL;
276 } 298 }
277 } 299 }
278

mercurial