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; |