135 log_error(jfr, system)("GetObjectArrayElement threw an exception"); |
146 log_error(jfr, system)("GetObjectArrayElement threw an exception"); |
136 return; |
147 return; |
137 } |
148 } |
138 } |
149 } |
139 |
150 |
|
151 static bool is_valid_jvmti_phase() { |
|
152 return JvmtiEnvBase::get_phase() == JVMTI_PHASE_LIVE; |
|
153 } |
|
154 |
140 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { |
155 void JfrJvmtiAgent::retransform_classes(JNIEnv* env, jobjectArray classes_array, TRAPS) { |
141 assert(env != NULL, "invariant"); |
156 assert(env != NULL, "invariant"); |
|
157 assert(classes_array != NULL, "invariant"); |
|
158 assert(is_valid_jvmti_phase(), "invariant"); |
142 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); |
159 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); |
143 if (classes_array == NULL) { |
|
144 return; |
|
145 } |
|
146 const jint classes_count = env->GetArrayLength(classes_array); |
160 const jint classes_count = env->GetArrayLength(classes_array); |
147 if (classes_count <= 0) { |
161 if (classes_count <= 0) { |
148 return; |
162 return; |
149 } |
163 } |
150 ResourceMark rm(THREAD); |
164 ResourceMark rm(THREAD); |
151 jclass* const classes = create_classes_array(classes_count, CHECK); |
165 jclass* const classes = create_classes_array(classes_count, CHECK); |
152 assert(classes != NULL, "invariant"); |
166 assert(classes != NULL, "invariant"); |
153 for (jint i = 0; i < classes_count; i++) { |
167 for (jint i = 0; i < classes_count; i++) { |
154 jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); |
168 jclass clz = (jclass)env->GetObjectArrayElement(classes_array, i); |
155 check_exception_and_log(env, THREAD); |
169 check_exception_and_log(env, THREAD); |
156 |
170 classes[i] = clz; |
|
171 } |
|
172 { |
157 // inspecting the oop/klass requires a thread transition |
173 // inspecting the oop/klass requires a thread transition |
158 { |
174 ThreadInVMfromNative transition((JavaThread*)THREAD); |
159 ThreadInVMfromNative transition((JavaThread*)THREAD); |
175 for (jint i = 0; i < classes_count; ++i) { |
160 if (JdkJfrEvent::is_a(clz)) { |
176 jclass clz = classes[i]; |
161 // should have been tagged already |
177 if (!JdkJfrEvent::is_a(clz)) { |
162 assert(JdkJfrEvent::is_subklass(clz), "invariant"); |
|
163 } else { |
|
164 // outside the event hierarchy |
178 // outside the event hierarchy |
165 JdkJfrEvent::tag_as_host(clz); |
179 JdkJfrEvent::tag_as_host(clz); |
166 } |
180 } |
167 } |
181 } |
168 |
182 } |
169 classes[i] = clz; |
183 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(THREAD)); |
170 } |
184 const jvmtiError result = jfr_jvmti_env->RetransformClasses(classes_count, classes); |
171 if (jfr_jvmti_env->RetransformClasses(classes_count, classes) != JVMTI_ERROR_NONE) { |
185 if (result != JVMTI_ERROR_NONE) { |
172 log_and_throw(THREAD); |
186 log_and_throw(result, THREAD); |
173 } |
187 } |
174 } |
188 } |
175 |
189 |
176 static jvmtiError register_callbacks(JavaThread* jt) { |
190 static bool register_callbacks(JavaThread* jt) { |
177 assert(jfr_jvmti_env != NULL, "invariant"); |
191 assert(jfr_jvmti_env != NULL, "invariant"); |
178 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); |
192 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); |
179 jvmtiEventCallbacks callbacks; |
193 jvmtiEventCallbacks callbacks; |
180 /* Set callbacks */ |
194 /* Set callbacks */ |
181 memset(&callbacks, 0, sizeof(callbacks)); |
195 memset(&callbacks, 0, sizeof(callbacks)); |
182 callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; |
196 callbacks.ClassFileLoadHook = jfr_on_class_file_load_hook; |
183 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); |
197 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); |
184 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); |
198 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); |
185 return jvmti_ret_code; |
199 return jvmti_ret_code == JVMTI_ERROR_NONE; |
186 } |
200 } |
187 |
201 |
188 static jvmtiError register_capabilities(JavaThread* jt) { |
202 static bool register_capabilities(JavaThread* jt) { |
189 assert(jfr_jvmti_env != NULL, "invariant"); |
203 assert(jfr_jvmti_env != NULL, "invariant"); |
190 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); |
204 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); |
191 jvmtiCapabilities capabilities; |
205 jvmtiCapabilities capabilities; |
192 /* Add JVMTI capabilities */ |
206 /* Add JVMTI capabilities */ |
193 (void)memset(&capabilities, 0, sizeof(capabilities)); |
207 (void)memset(&capabilities, 0, sizeof(capabilities)); |
194 capabilities.can_retransform_classes = 1; |
208 capabilities.can_retransform_classes = 1; |
195 capabilities.can_retransform_any_class = 1; |
209 capabilities.can_retransform_any_class = 1; |
196 const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); |
210 const jvmtiError jvmti_ret_code = jfr_jvmti_env->AddCapabilities(&capabilities); |
197 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); |
211 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "Add Capabilities"); |
198 return jvmti_ret_code; |
212 return jvmti_ret_code == JVMTI_ERROR_NONE; |
199 } |
213 } |
200 |
214 |
201 static jint create_jvmti_env(JavaThread* jt) { |
215 static jint create_jvmti_env(JavaThread* jt) { |
202 assert(jfr_jvmti_env == NULL, "invariant"); |
216 assert(jfr_jvmti_env == NULL, "invariant"); |
203 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); |
217 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_native(jt)); |
204 extern struct JavaVM_ main_vm; |
218 extern struct JavaVM_ main_vm; |
205 JavaVM* vm = &main_vm; |
219 JavaVM* vm = &main_vm; |
206 return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); |
220 return vm->GetEnv((void **)&jfr_jvmti_env, JVMTI_VERSION); |
207 } |
221 } |
208 |
222 |
209 static jvmtiError unregister_callbacks(JavaThread* jt) { |
223 static bool unregister_callbacks(JavaThread* jt) { |
210 if (jfr_jvmti_env == NULL) { |
224 assert(jfr_jvmti_env != NULL, "invariant"); |
211 return JVMTI_ERROR_NONE; |
|
212 } |
|
213 jvmtiEventCallbacks callbacks; |
225 jvmtiEventCallbacks callbacks; |
214 /* Set empty callbacks */ |
226 /* Set empty callbacks */ |
215 memset(&callbacks, 0, sizeof(callbacks)); |
227 memset(&callbacks, 0, sizeof(callbacks)); |
216 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); |
228 const jvmtiError jvmti_ret_code = jfr_jvmti_env->SetEventCallbacks(&callbacks, sizeof(callbacks)); |
217 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); |
229 check_jvmti_error(jfr_jvmti_env, jvmti_ret_code, "SetEventCallbacks"); |
218 return jvmti_ret_code; |
230 return jvmti_ret_code == JVMTI_ERROR_NONE; |
219 } |
231 } |
220 |
232 |
221 JfrJvmtiAgent::JfrJvmtiAgent() {} |
233 JfrJvmtiAgent::JfrJvmtiAgent() {} |
222 |
234 |
223 JfrJvmtiAgent::~JfrJvmtiAgent() { |
235 JfrJvmtiAgent::~JfrJvmtiAgent() { |
224 JavaThread* jt = current_java_thread(); |
236 JavaThread* jt = current_java_thread(); |
225 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); |
237 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); |
226 ThreadToNativeFromVM transition(jt); |
|
227 update_class_file_load_hook_event(JVMTI_DISABLE); |
|
228 unregister_callbacks(jt); |
|
229 if (jfr_jvmti_env != NULL) { |
238 if (jfr_jvmti_env != NULL) { |
|
239 ThreadToNativeFromVM transition(jt); |
|
240 update_class_file_load_hook_event(JVMTI_DISABLE); |
|
241 unregister_callbacks(jt); |
230 jfr_jvmti_env->DisposeEnvironment(); |
242 jfr_jvmti_env->DisposeEnvironment(); |
231 jfr_jvmti_env = NULL; |
243 jfr_jvmti_env = NULL; |
232 } |
244 } |
233 agent = NULL; |
245 } |
234 } |
246 |
235 |
247 static bool initialize(JavaThread* jt) { |
236 static bool initialize() { |
|
237 JavaThread* const jt = current_java_thread(); |
|
238 assert(jt != NULL, "invariant"); |
248 assert(jt != NULL, "invariant"); |
239 assert(jt->thread_state() == _thread_in_vm, "invariant"); |
|
240 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); |
249 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(jt)); |
241 ThreadToNativeFromVM transition(jt); |
250 ThreadToNativeFromVM transition(jt); |
242 if (create_jvmti_env(jt) != JNI_OK) { |
251 if (create_jvmti_env(jt) != JNI_OK) { |
243 assert(jfr_jvmti_env == NULL, "invariant"); |
252 assert(jfr_jvmti_env == NULL, "invariant"); |
244 return false; |
253 return false; |
245 } |
254 } |
246 assert(jfr_jvmti_env != NULL, "invariant"); |
255 assert(jfr_jvmti_env != NULL, "invariant"); |
247 if (register_capabilities(jt) != JVMTI_ERROR_NONE) { |
256 if (!register_capabilities(jt)) { |
248 return false; |
257 return false; |
249 } |
258 } |
250 if (register_callbacks(jt) != JVMTI_ERROR_NONE) { |
259 if (!register_callbacks(jt)) { |
251 return false; |
260 return false; |
252 } |
261 } |
253 if (update_class_file_load_hook_event(JVMTI_ENABLE) != JVMTI_ERROR_NONE) { |
262 return update_class_file_load_hook_event(JVMTI_ENABLE); |
254 return false; |
263 } |
255 } |
264 |
256 return true; |
265 static void log_and_throw_illegal_state_exception(TRAPS) { |
|
266 DEBUG_ONLY(JfrJavaSupport::check_java_thread_in_vm(THREAD)); |
|
267 const char* const illegal_state_msg = "An attempt was made to start JFR too early in the VM initialization sequence."; |
|
268 log_error(jfr, system)(illegal_state_msg); |
|
269 log_error(jfr, system)("JFR uses JVMTI RetransformClasses and requires the JVMTI state to have entered JVMTI_PHASE_LIVE."); |
|
270 log_error(jfr, system)("Please initialize JFR in response to event JVMTI_EVENT_VM_INIT instead of JVMTI_EVENT_VM_START."); |
|
271 JfrJavaSupport::throw_illegal_state_exception(illegal_state_msg, THREAD); |
257 } |
272 } |
258 |
273 |
259 bool JfrJvmtiAgent::create() { |
274 bool JfrJvmtiAgent::create() { |
260 assert(jfr_jvmti_env == NULL, "invariant"); |
275 assert(agent == NULL, "invariant"); |
|
276 JavaThread* const jt = current_java_thread(); |
|
277 if (!is_valid_jvmti_phase()) { |
|
278 log_and_throw_illegal_state_exception(jt); |
|
279 return false; |
|
280 } |
261 agent = new JfrJvmtiAgent(); |
281 agent = new JfrJvmtiAgent(); |
262 if (agent == NULL) { |
282 if (agent == NULL) { |
263 return false; |
283 return false; |
264 } |
284 } |
265 if (!initialize()) { |
285 if (!initialize(jt)) { |
266 delete agent; |
286 delete agent; |
267 agent = NULL; |
287 agent = NULL; |
268 return false; |
288 return false; |
269 } |
289 } |
270 return true; |
290 return true; |