1 /*
2 * Copyright (c) 2003, 2026, Oracle 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
25 #include "classfile/classLoader.hpp"
26 #include "classfile/systemDictionary.hpp"
27 #include "classfile/vmClasses.hpp"
28 #include "compiler/compileBroker.hpp"
29 #include "gc/shared/collectedHeap.hpp"
30 #include "jmm.h"
31 #include "memory/allocation.inline.hpp"
32 #include "memory/iterator.hpp"
33 #include "memory/oopFactory.hpp"
34 #include "memory/resourceArea.hpp"
35 #include "memory/universe.hpp"
36 #include "oops/klass.hpp"
37 #include "oops/klass.inline.hpp"
38 #include "oops/objArrayKlass.hpp"
39 #include "oops/objArrayOop.inline.hpp"
40 #include "oops/oop.inline.hpp"
41 #include "oops/oopCast.inline.hpp"
42 #include "oops/oopHandle.inline.hpp"
43 #include "oops/typeArrayOop.inline.hpp"
44 #include "runtime/flags/jvmFlag.hpp"
45 #include "runtime/globals.hpp"
46 #include "runtime/handles.inline.hpp"
47 #include "runtime/interfaceSupport.inline.hpp"
48 #include "runtime/javaCalls.hpp"
49 #include "runtime/jniHandles.inline.hpp"
50 #include "runtime/mutexLocker.hpp"
51 #include "runtime/notificationThread.hpp"
52 #include "runtime/os.hpp"
53 #include "runtime/thread.inline.hpp"
54 #include "runtime/threads.hpp"
55 #include "runtime/threadSMR.hpp"
56 #include "runtime/vmOperations.hpp"
57 #include "services/classLoadingService.hpp"
58 #include "services/cpuTimeUsage.hpp"
59 #include "services/diagnosticCommand.hpp"
60 #include "services/diagnosticFramework.hpp"
61 #include "services/finalizerService.hpp"
62 #include "services/gcNotifier.hpp"
63 #include "services/heapDumper.hpp"
64 #include "services/lowMemoryDetector.hpp"
65 #include "services/management.hpp"
66 #include "services/memoryManager.hpp"
67 #include "services/memoryPool.hpp"
68 #include "services/memoryService.hpp"
69 #include "services/runtimeService.hpp"
70 #include "services/threadService.hpp"
71 #include "services/writeableFlags.hpp"
72 #include "utilities/debug.hpp"
73 #include "utilities/formatBuffer.hpp"
74 #include "utilities/macros.hpp"
75
76 PerfVariable* Management::_begin_vm_creation_time = nullptr;
77 PerfVariable* Management::_end_vm_creation_time = nullptr;
78 PerfVariable* Management::_vm_init_done_time = nullptr;
79
80 InstanceKlass* Management::_diagnosticCommandImpl_klass = nullptr;
81 InstanceKlass* Management::_garbageCollectorExtImpl_klass = nullptr;
82 InstanceKlass* Management::_garbageCollectorMXBean_klass = nullptr;
83 InstanceKlass* Management::_gcInfo_klass = nullptr;
84 InstanceKlass* Management::_managementFactoryHelper_klass = nullptr;
85 InstanceKlass* Management::_memoryManagerMXBean_klass = nullptr;
86 InstanceKlass* Management::_memoryPoolMXBean_klass = nullptr;
87 InstanceKlass* Management::_memoryUsage_klass = nullptr;
88 InstanceKlass* Management::_sensor_klass = nullptr;
89 InstanceKlass* Management::_threadInfo_klass = nullptr;
90
91 jmmOptionalSupport Management::_optional_support = {0};
92 TimeStamp Management::_stamp;
93
94 void management_init() {
95 #if INCLUDE_MANAGEMENT
96 Management::init();
97 ThreadService::init();
98 RuntimeService::init();
99 ClassLoadingService::init();
100 FinalizerService::init();
101 #else
102 ThreadService::init();
103 #endif // INCLUDE_MANAGEMENT
104 }
105
106 #if INCLUDE_MANAGEMENT
107
108 void Management::init() {
109 EXCEPTION_MARK;
110
111 // These counters are for java.lang.management API support.
112 // They are created even if -XX:-UsePerfData is set and in
113 // that case, they will be allocated on C heap.
114
115 _begin_vm_creation_time =
116 PerfDataManager::create_variable(SUN_RT, "createVmBeginTime",
117 PerfData::U_None, CHECK);
118
119 _end_vm_creation_time =
120 PerfDataManager::create_variable(SUN_RT, "createVmEndTime",
121 PerfData::U_None, CHECK);
122
123 _vm_init_done_time =
124 PerfDataManager::create_variable(SUN_RT, "vmInitDoneTime",
125 PerfData::U_None, CHECK);
126
127 // Initialize optional support
128 _optional_support.isLowMemoryDetectionSupported = 1;
129 _optional_support.isCompilationTimeMonitoringSupported = 1;
130 _optional_support.isThreadContentionMonitoringSupported = 1;
131
132 if (os::is_thread_cpu_time_supported()) {
133 _optional_support.isCurrentThreadCpuTimeSupported = 1;
134 _optional_support.isOtherThreadCpuTimeSupported = 1;
135 } else {
136 _optional_support.isCurrentThreadCpuTimeSupported = 0;
137 _optional_support.isOtherThreadCpuTimeSupported = 0;
138 }
139
140 _optional_support.isObjectMonitorUsageSupported = 1;
141 #if INCLUDE_SERVICES
142 // This depends on the heap inspector
143 _optional_support.isSynchronizerUsageSupported = 1;
144 #endif // INCLUDE_SERVICES
145 _optional_support.isThreadAllocatedMemorySupported = 1;
146 _optional_support.isRemoteDiagnosticCommandsSupported = 1;
147
148 // Registration of the diagnostic commands
149 DCmd::register_dcmds();
150 }
151
152 void Management::initialize(TRAPS) {
153 NotificationThread::initialize();
154
155 if (ManagementServer) {
156 ResourceMark rm(THREAD);
157 HandleMark hm(THREAD);
158
159 // Load and initialize the jdk.internal.agent.Agent class
160 // invoke startAgent method to start the management server
161 Handle loader = Handle(THREAD, SystemDictionary::java_system_loader());
162 Klass* k = SystemDictionary::resolve_or_null(vmSymbols::jdk_internal_agent_Agent(),
163 loader,
164 THREAD);
165 if (k == nullptr) {
166 vm_exit_during_initialization("Management agent initialization failure: "
167 "class jdk.internal.agent.Agent not found.");
168 }
169
170 JavaValue result(T_VOID);
171 JavaCalls::call_static(&result,
172 k,
173 vmSymbols::startAgent_name(),
174 vmSymbols::void_method_signature(),
175 CHECK);
176 }
177 }
178
179 void Management::get_optional_support(jmmOptionalSupport* support) {
180 memcpy(support, &_optional_support, sizeof(jmmOptionalSupport));
181 }
182
183 InstanceKlass* Management::load_and_initialize_klass(Symbol* sh, TRAPS) {
184 Klass* k = SystemDictionary::resolve_or_fail(sh, true, CHECK_NULL);
185 return initialize_klass(k, THREAD);
186 }
187
188 InstanceKlass* Management::load_and_initialize_klass_or_null(Symbol* sh, TRAPS) {
189 Klass* k = SystemDictionary::resolve_or_null(sh, CHECK_NULL);
190 if (k == nullptr) {
191 return nullptr;
192 }
193 return initialize_klass(k, THREAD);
194 }
195
196 InstanceKlass* Management::initialize_klass(Klass* k, TRAPS) {
197 InstanceKlass* ik = InstanceKlass::cast(k);
198 if (ik->should_be_initialized()) {
199 ik->initialize(CHECK_NULL);
200 }
201 // If these classes change to not be owned by the boot loader, they need
202 // to be walked to keep their class loader alive in oops_do.
203 assert(ik->class_loader() == nullptr, "need to follow in oops_do");
204 return ik;
205 }
206
207
208 void Management::record_vm_init_completed() {
209 // Initialize the timestamp to get the current time
210 _vm_init_done_time->set_value(os::javaTimeMillis());
211
212 // Update the timestamp to the vm init done time
213 _stamp.update();
214 }
215
216 void Management::record_vm_startup_time(jlong begin, jlong duration) {
217 // if the performance counter is not initialized,
218 // then vm initialization failed; simply return.
219 if (_begin_vm_creation_time == nullptr) return;
220
221 _begin_vm_creation_time->set_value(begin);
222 _end_vm_creation_time->set_value(begin + duration);
223 PerfMemory::set_accessible(true);
224 }
225
226 jlong Management::begin_vm_creation_time() {
227 return _begin_vm_creation_time->get_value();
228 }
229
230 jlong Management::vm_init_done_time() {
231 return _vm_init_done_time->get_value();
232 }
233
234 jlong Management::timestamp() {
235 TimeStamp t;
236 t.update();
237 return t.ticks() - _stamp.ticks();
238 }
239
240 InstanceKlass* Management::java_lang_management_ThreadInfo_klass(TRAPS) {
241 if (_threadInfo_klass == nullptr) {
242 _threadInfo_klass = load_and_initialize_klass(vmSymbols::java_lang_management_ThreadInfo(), CHECK_NULL);
243 }
244 return _threadInfo_klass;
245 }
246
247 InstanceKlass* Management::java_lang_management_MemoryUsage_klass(TRAPS) {
248 if (_memoryUsage_klass == nullptr) {
249 _memoryUsage_klass = load_and_initialize_klass(vmSymbols::java_lang_management_MemoryUsage(), CHECK_NULL);
250 }
251 return _memoryUsage_klass;
252 }
253
254 InstanceKlass* Management::java_lang_management_MemoryPoolMXBean_klass(TRAPS) {
255 if (_memoryPoolMXBean_klass == nullptr) {
256 _memoryPoolMXBean_klass = load_and_initialize_klass(vmSymbols::java_lang_management_MemoryPoolMXBean(), CHECK_NULL);
257 }
258 return _memoryPoolMXBean_klass;
259 }
260
261 InstanceKlass* Management::java_lang_management_MemoryManagerMXBean_klass(TRAPS) {
262 if (_memoryManagerMXBean_klass == nullptr) {
263 _memoryManagerMXBean_klass = load_and_initialize_klass(vmSymbols::java_lang_management_MemoryManagerMXBean(), CHECK_NULL);
264 }
265 return _memoryManagerMXBean_klass;
266 }
267
268 InstanceKlass* Management::java_lang_management_GarbageCollectorMXBean_klass(TRAPS) {
269 if (_garbageCollectorMXBean_klass == nullptr) {
270 _garbageCollectorMXBean_klass = load_and_initialize_klass(vmSymbols::java_lang_management_GarbageCollectorMXBean(), CHECK_NULL);
271 }
272 return _garbageCollectorMXBean_klass;
273 }
274
275 InstanceKlass* Management::sun_management_Sensor_klass(TRAPS) {
276 if (_sensor_klass == nullptr) {
277 _sensor_klass = load_and_initialize_klass(vmSymbols::sun_management_Sensor(), CHECK_NULL);
278 }
279 return _sensor_klass;
280 }
281
282 InstanceKlass* Management::sun_management_ManagementFactoryHelper_klass(TRAPS) {
283 if (_managementFactoryHelper_klass == nullptr) {
284 _managementFactoryHelper_klass = load_and_initialize_klass(vmSymbols::sun_management_ManagementFactoryHelper(), CHECK_NULL);
285 }
286 return _managementFactoryHelper_klass;
287 }
288
289 InstanceKlass* Management::com_sun_management_internal_GarbageCollectorExtImpl_klass(TRAPS) {
290 if (_garbageCollectorExtImpl_klass == nullptr) {
291 _garbageCollectorExtImpl_klass =
292 load_and_initialize_klass_or_null(vmSymbols::com_sun_management_internal_GarbageCollectorExtImpl(), CHECK_NULL);
293 }
294 return _garbageCollectorExtImpl_klass;
295 }
296
297 InstanceKlass* Management::com_sun_management_GcInfo_klass(TRAPS) {
298 if (_gcInfo_klass == nullptr) {
299 _gcInfo_klass = load_and_initialize_klass(vmSymbols::com_sun_management_GcInfo(), CHECK_NULL);
300 }
301 return _gcInfo_klass;
302 }
303
304 InstanceKlass* Management::com_sun_management_internal_DiagnosticCommandImpl_klass(TRAPS) {
305 if (_diagnosticCommandImpl_klass == nullptr) {
306 _diagnosticCommandImpl_klass = load_and_initialize_klass(vmSymbols::com_sun_management_internal_DiagnosticCommandImpl(), CHECK_NULL);
307 }
308 return _diagnosticCommandImpl_klass;
309 }
310
311 static void initialize_ThreadInfo_constructor_arguments(JavaCallArguments* args, ThreadSnapshot* snapshot, TRAPS) {
312 Handle snapshot_thread(THREAD, snapshot->threadObj());
313
314 jlong contended_time;
315 jlong waited_time;
316 if (ThreadService::is_thread_monitoring_contention()) {
317 contended_time = Management::ticks_to_ms(snapshot->contended_enter_ticks());
318 waited_time = Management::ticks_to_ms(snapshot->monitor_wait_ticks() + snapshot->sleep_ticks());
319 } else {
320 // set them to -1 if thread contention monitoring is disabled.
321 contended_time = max_julong;
322 waited_time = max_julong;
323 }
324
325 int thread_status = static_cast<int>(snapshot->thread_status());
326 assert((thread_status & JMM_THREAD_STATE_FLAG_MASK) == 0, "Flags already set in thread_status in Thread object");
327 if (snapshot->is_suspended()) {
328 thread_status |= JMM_THREAD_STATE_FLAG_SUSPENDED;
329 }
330 if (snapshot->is_in_native()) {
331 thread_status |= JMM_THREAD_STATE_FLAG_NATIVE;
332 }
333
334 ThreadStackTrace* st = snapshot->get_stack_trace();
335 Handle stacktrace_h;
336 if (st != nullptr) {
337 stacktrace_h = st->allocate_fill_stack_trace_element_array(CHECK);
338 } else {
339 stacktrace_h = Handle();
340 }
341
342 args->push_oop(snapshot_thread);
343 args->push_int(thread_status);
344 args->push_oop(Handle(THREAD, snapshot->blocker_object()));
345 args->push_oop(Handle(THREAD, snapshot->blocker_object_owner()));
346 args->push_long(snapshot->contended_enter_count());
347 args->push_long(contended_time);
348 args->push_long(snapshot->monitor_wait_count() + snapshot->sleep_count());
349 args->push_long(waited_time);
350 args->push_oop(stacktrace_h);
351 }
352
353 // Helper function to construct a ThreadInfo object
354 instanceOop Management::create_thread_info_instance(ThreadSnapshot* snapshot, TRAPS) {
355 InstanceKlass* ik = Management::java_lang_management_ThreadInfo_klass(CHECK_NULL);
356 JavaCallArguments args(14);
357
358 // initialize the arguments for the ThreadInfo constructor
359 initialize_ThreadInfo_constructor_arguments(&args, snapshot, CHECK_NULL);
360
361 // Call ThreadInfo constructor with no locked monitors and synchronizers
362 Handle element = JavaCalls::construct_new_instance(
363 ik,
364 vmSymbols::java_lang_management_ThreadInfo_constructor_signature(),
365 &args,
366 CHECK_NULL);
367 return (instanceOop) element();
368 }
369
370 instanceOop Management::create_thread_info_instance(ThreadSnapshot* snapshot,
371 objArrayHandle monitors_array,
372 typeArrayHandle depths_array,
373 objArrayHandle synchronizers_array,
374 TRAPS) {
375 InstanceKlass* ik = Management::java_lang_management_ThreadInfo_klass(CHECK_NULL);
376 JavaCallArguments args(17);
377
378 // initialize the arguments for the ThreadInfo constructor
379 initialize_ThreadInfo_constructor_arguments(&args, snapshot, CHECK_NULL);
380
381 // push the locked monitors and synchronizers in the arguments
382 args.push_oop(monitors_array);
383 args.push_oop(depths_array);
384 args.push_oop(synchronizers_array);
385
386 // Call ThreadInfo constructor with locked monitors and synchronizers
387 Handle element = JavaCalls::construct_new_instance(
388 ik,
389 vmSymbols::java_lang_management_ThreadInfo_with_locks_constructor_signature(),
390 &args,
391 CHECK_NULL);
392 return (instanceOop) element();
393 }
394
395
396 static GCMemoryManager* get_gc_memory_manager_from_jobject(jobject mgr, TRAPS) {
397 if (mgr == nullptr) {
398 THROW_(vmSymbols::java_lang_NullPointerException(), nullptr);
399 }
400 oop mgr_obj = JNIHandles::resolve(mgr);
401 instanceHandle h(THREAD, (instanceOop) mgr_obj);
402
403 InstanceKlass* k = Management::java_lang_management_GarbageCollectorMXBean_klass(CHECK_NULL);
404 if (!h->is_a(k)) {
405 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
406 "the object is not an instance of java.lang.management.GarbageCollectorMXBean class",
407 nullptr);
408 }
409
410 MemoryManager* gc = MemoryService::get_memory_manager(h);
411 if (gc == nullptr || !gc->is_gc_memory_manager()) {
412 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
413 "Invalid GC memory manager",
414 nullptr);
415 }
416 return (GCMemoryManager*) gc;
417 }
418
419 static MemoryPool* get_memory_pool_from_jobject(jobject obj, TRAPS) {
420 if (obj == nullptr) {
421 THROW_(vmSymbols::java_lang_NullPointerException(), nullptr);
422 }
423
424 oop pool_obj = JNIHandles::resolve(obj);
425 assert(pool_obj->is_instance(), "Should be an instanceOop");
426 instanceHandle ph(THREAD, (instanceOop) pool_obj);
427
428 return MemoryService::get_memory_pool(ph);
429 }
430
431 static void validate_thread_id_array(typeArrayHandle ids_ah, TRAPS) {
432 int num_threads = ids_ah->length();
433
434 // Validate input thread IDs
435 int i = 0;
436 for (i = 0; i < num_threads; i++) {
437 jlong tid = ids_ah->long_at(i);
438 if (tid <= 0) {
439 // throw exception if invalid thread id.
440 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
441 "Invalid thread ID entry");
442 }
443 }
444 }
445
446 // Returns true if the JavaThread's Java object is a platform thread
447 static bool is_platform_thread(JavaThread* jt) {
448 if (jt != nullptr) {
449 oop thread_obj = jt->threadObj();
450 return (thread_obj != nullptr) && !thread_obj->is_a(vmClasses::BoundVirtualThread_klass());
451 } else {
452 return false;
453 }
454 }
455
456 static void validate_thread_info_array(objArrayHandle infoArray_h, TRAPS) {
457 // check if the element of infoArray is of type ThreadInfo class
458 Klass* threadinfo_klass = Management::java_lang_management_ThreadInfo_klass(CHECK);
459 Klass* element_klass = ObjArrayKlass::cast(infoArray_h->klass())->element_klass();
460 if (element_klass != threadinfo_klass) {
461 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
462 "infoArray element type is not ThreadInfo class");
463 }
464 }
465
466 // Returns true if the ThreadSnapshot's Java object is a platform thread
467 static bool is_platform_thread(ThreadSnapshot* ts) {
468 oop thread_obj = ts->threadObj();
469 return (thread_obj != nullptr) && !thread_obj->is_a(vmClasses::BoundVirtualThread_klass());
470 }
471
472 static MemoryManager* get_memory_manager_from_jobject(jobject obj, TRAPS) {
473 if (obj == nullptr) {
474 THROW_(vmSymbols::java_lang_NullPointerException(), nullptr);
475 }
476
477 oop mgr_obj = JNIHandles::resolve(obj);
478 assert(mgr_obj->is_instance(), "Should be an instanceOop");
479 instanceHandle mh(THREAD, (instanceOop) mgr_obj);
480
481 return MemoryService::get_memory_manager(mh);
482 }
483
484 // Returns a version string and sets major and minor version if
485 // the input parameters are non-null.
486 JVM_LEAF(jint, jmm_GetVersion(JNIEnv *env))
487 return JMM_VERSION;
488 JVM_END
489
490 // Gets the list of VM monitoring and management optional supports
491 // Returns 0 if succeeded; otherwise returns non-zero.
492 JVM_LEAF(jint, jmm_GetOptionalSupport(JNIEnv *env, jmmOptionalSupport* support))
493 if (support == nullptr) {
494 return -1;
495 }
496 Management::get_optional_support(support);
497 return 0;
498 JVM_END
499
500 // Returns an array of java/lang/management/MemoryPoolMXBean object
501 // one for each memory pool if obj == null; otherwise returns
502 // an array of memory pools for a given memory manager if
503 // it is a valid memory manager.
504 JVM_ENTRY(jobjectArray, jmm_GetMemoryPools(JNIEnv* env, jobject obj))
505 ResourceMark rm(THREAD);
506
507 int num_memory_pools;
508 MemoryManager* mgr = nullptr;
509 if (obj == nullptr) {
510 num_memory_pools = MemoryService::num_memory_pools();
511 } else {
512 mgr = get_memory_manager_from_jobject(obj, CHECK_NULL);
513 if (mgr == nullptr) {
514 return nullptr;
515 }
516 num_memory_pools = mgr->num_memory_pools();
517 }
518
519 // Allocate the resulting MemoryPoolMXBean[] object
520 InstanceKlass* ik = Management::java_lang_management_MemoryPoolMXBean_klass(CHECK_NULL);
521 objArrayOop r = oopFactory::new_objArray(ik, num_memory_pools, CHECK_NULL);
522 objArrayHandle poolArray(THREAD, r);
523
524 if (mgr == nullptr) {
525 // Get all memory pools
526 for (int i = 0; i < num_memory_pools; i++) {
527 MemoryPool* pool = MemoryService::get_memory_pool(i);
528 instanceOop p = pool->get_memory_pool_instance(CHECK_NULL);
529 instanceHandle ph(THREAD, p);
530 poolArray->obj_at_put(i, ph());
531 }
532 } else {
533 // Get memory pools managed by a given memory manager
534 for (int i = 0; i < num_memory_pools; i++) {
535 MemoryPool* pool = mgr->get_memory_pool(i);
536 instanceOop p = pool->get_memory_pool_instance(CHECK_NULL);
537 instanceHandle ph(THREAD, p);
538 poolArray->obj_at_put(i, ph());
539 }
540 }
541 return (jobjectArray) JNIHandles::make_local(THREAD, poolArray());
542 JVM_END
543
544 // Returns an array of java/lang/management/MemoryManagerMXBean object
545 // one for each memory manager if obj == null; otherwise returns
546 // an array of memory managers for a given memory pool if
547 // it is a valid memory pool.
548 JVM_ENTRY(jobjectArray, jmm_GetMemoryManagers(JNIEnv* env, jobject obj))
549 ResourceMark rm(THREAD);
550
551 int num_mgrs;
552 MemoryPool* pool = nullptr;
553 if (obj == nullptr) {
554 num_mgrs = MemoryService::num_memory_managers();
555 } else {
556 pool = get_memory_pool_from_jobject(obj, CHECK_NULL);
557 if (pool == nullptr) {
558 return nullptr;
559 }
560 num_mgrs = pool->num_memory_managers();
561 }
562
563 // Allocate the resulting MemoryManagerMXBean[] object
564 InstanceKlass* ik = Management::java_lang_management_MemoryManagerMXBean_klass(CHECK_NULL);
565 objArrayOop r = oopFactory::new_objArray(ik, num_mgrs, CHECK_NULL);
566 objArrayHandle mgrArray(THREAD, r);
567
568 if (pool == nullptr) {
569 // Get all memory managers
570 for (int i = 0; i < num_mgrs; i++) {
571 MemoryManager* mgr = MemoryService::get_memory_manager(i);
572 instanceOop p = mgr->get_memory_manager_instance(CHECK_NULL);
573 instanceHandle ph(THREAD, p);
574 mgrArray->obj_at_put(i, ph());
575 }
576 } else {
577 // Get memory managers for a given memory pool
578 for (int i = 0; i < num_mgrs; i++) {
579 MemoryManager* mgr = pool->get_memory_manager(i);
580 instanceOop p = mgr->get_memory_manager_instance(CHECK_NULL);
581 instanceHandle ph(THREAD, p);
582 mgrArray->obj_at_put(i, ph());
583 }
584 }
585 return (jobjectArray) JNIHandles::make_local(THREAD, mgrArray());
586 JVM_END
587
588
589 // Returns a java/lang/management/MemoryUsage object containing the memory usage
590 // of a given memory pool.
591 JVM_ENTRY(jobject, jmm_GetMemoryPoolUsage(JNIEnv* env, jobject obj))
592 ResourceMark rm(THREAD);
593
594 MemoryPool* pool = get_memory_pool_from_jobject(obj, CHECK_NULL);
595 if (pool != nullptr) {
596 MemoryUsage usage = pool->get_memory_usage();
597 Handle h = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL);
598 return JNIHandles::make_local(THREAD, h());
599 } else {
600 return nullptr;
601 }
602 JVM_END
603
604 // Returns a java/lang/management/MemoryUsage object containing the memory usage
605 // of a given memory pool.
606 JVM_ENTRY(jobject, jmm_GetPeakMemoryPoolUsage(JNIEnv* env, jobject obj))
607 ResourceMark rm(THREAD);
608
609 MemoryPool* pool = get_memory_pool_from_jobject(obj, CHECK_NULL);
610 if (pool != nullptr) {
611 MemoryUsage usage = pool->get_peak_memory_usage();
612 Handle h = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL);
613 return JNIHandles::make_local(THREAD, h());
614 } else {
615 return nullptr;
616 }
617 JVM_END
618
619 // Returns a java/lang/management/MemoryUsage object containing the memory usage
620 // of a given memory pool after most recent GC.
621 JVM_ENTRY(jobject, jmm_GetPoolCollectionUsage(JNIEnv* env, jobject obj))
622 ResourceMark rm(THREAD);
623
624 MemoryPool* pool = get_memory_pool_from_jobject(obj, CHECK_NULL);
625 if (pool != nullptr && pool->is_collected_pool()) {
626 MemoryUsage usage = pool->get_last_collection_usage();
627 Handle h = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL);
628 return JNIHandles::make_local(THREAD, h());
629 } else {
630 return nullptr;
631 }
632 JVM_END
633
634 // Sets the memory pool sensor for a threshold type
635 JVM_ENTRY(void, jmm_SetPoolSensor(JNIEnv* env, jobject obj, jmmThresholdType type, jobject sensorObj))
636 if (obj == nullptr || sensorObj == nullptr) {
637 THROW(vmSymbols::java_lang_NullPointerException());
638 }
639
640 InstanceKlass* sensor_klass = Management::sun_management_Sensor_klass(CHECK);
641 oop s = JNIHandles::resolve(sensorObj);
642 assert(s->is_instance(), "Sensor should be an instanceOop");
643 instanceHandle sensor_h(THREAD, (instanceOop) s);
644 if (!sensor_h->is_a(sensor_klass)) {
645 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
646 "Sensor is not an instance of sun.management.Sensor class");
647 }
648
649 MemoryPool* mpool = get_memory_pool_from_jobject(obj, CHECK);
650 assert(mpool != nullptr, "MemoryPool should exist");
651
652 switch (type) {
653 case JMM_USAGE_THRESHOLD_HIGH:
654 case JMM_USAGE_THRESHOLD_LOW:
655 // have only one sensor for threshold high and low
656 mpool->set_usage_sensor_obj(sensor_h);
657 break;
658 case JMM_COLLECTION_USAGE_THRESHOLD_HIGH:
659 case JMM_COLLECTION_USAGE_THRESHOLD_LOW:
660 // have only one sensor for threshold high and low
661 mpool->set_gc_usage_sensor_obj(sensor_h);
662 break;
663 default:
664 assert(false, "Unrecognized type");
665 }
666
667 JVM_END
668
669
670 // Sets the threshold of a given memory pool.
671 // Returns the previous threshold.
672 //
673 // Input parameters:
674 // pool - the MemoryPoolMXBean object
675 // type - threshold type
676 // threshold - the new threshold (must not be negative)
677 //
678 JVM_ENTRY(jlong, jmm_SetPoolThreshold(JNIEnv* env, jobject obj, jmmThresholdType type, jlong threshold))
679 if (threshold < 0) {
680 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
681 "Invalid threshold value",
682 -1);
683 }
684
685 if ((size_t)threshold > max_uintx) {
686 stringStream st;
687 st.print("Invalid valid threshold value. Threshold value (" JLONG_FORMAT ") > max value of size_t (%zu)", threshold, max_uintx);
688 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(), st.as_string(), -1);
689 }
690
691 MemoryPool* pool = get_memory_pool_from_jobject(obj, CHECK_(0L));
692 assert(pool != nullptr, "MemoryPool should exist");
693
694 jlong prev = 0;
695 switch (type) {
696 case JMM_USAGE_THRESHOLD_HIGH:
697 if (!pool->usage_threshold()->is_high_threshold_supported()) {
698 return -1;
699 }
700 prev = pool->usage_threshold()->set_high_threshold((size_t) threshold);
701 break;
702
703 case JMM_USAGE_THRESHOLD_LOW:
704 if (!pool->usage_threshold()->is_low_threshold_supported()) {
705 return -1;
706 }
707 prev = pool->usage_threshold()->set_low_threshold((size_t) threshold);
708 break;
709
710 case JMM_COLLECTION_USAGE_THRESHOLD_HIGH:
711 if (!pool->gc_usage_threshold()->is_high_threshold_supported()) {
712 return -1;
713 }
714 // return and the new threshold is effective for the next GC
715 return pool->gc_usage_threshold()->set_high_threshold((size_t) threshold);
716
717 case JMM_COLLECTION_USAGE_THRESHOLD_LOW:
718 if (!pool->gc_usage_threshold()->is_low_threshold_supported()) {
719 return -1;
720 }
721 // return and the new threshold is effective for the next GC
722 return pool->gc_usage_threshold()->set_low_threshold((size_t) threshold);
723
724 default:
725 assert(false, "Unrecognized type");
726 return -1;
727 }
728
729 // When the threshold is changed, reevaluate if the low memory
730 // detection is enabled.
731 if (prev != threshold) {
732 LowMemoryDetector::recompute_enabled_for_collected_pools();
733 LowMemoryDetector::detect_low_memory(pool);
734 }
735 return prev;
736 JVM_END
737
738 // Returns a java/lang/management/MemoryUsage object representing
739 // the memory usage for the heap or non-heap memory.
740 JVM_ENTRY(jobject, jmm_GetMemoryUsage(JNIEnv* env, jboolean heap))
741 ResourceMark rm(THREAD);
742
743 MemoryUsage usage;
744
745 if (heap) {
746 usage = Universe::heap()->memory_usage();
747 } else {
748 // Calculate the memory usage by summing up the pools.
749 size_t total_init = 0;
750 size_t total_used = 0;
751 size_t total_committed = 0;
752 size_t total_max = 0;
753 bool has_undefined_init_size = false;
754 bool has_undefined_max_size = false;
755
756 for (int i = 0; i < MemoryService::num_memory_pools(); i++) {
757 MemoryPool* pool = MemoryService::get_memory_pool(i);
758 if (pool->is_non_heap()) {
759 MemoryUsage u = pool->get_memory_usage();
760 total_used += u.used();
761 total_committed += u.committed();
762
763 if (u.init_size() == MemoryUsage::undefined_size()) {
764 has_undefined_init_size = true;
765 }
766 if (!has_undefined_init_size) {
767 total_init += u.init_size();
768 }
769
770 if (u.max_size() == MemoryUsage::undefined_size()) {
771 has_undefined_max_size = true;
772 }
773 if (!has_undefined_max_size) {
774 total_max += u.max_size();
775 }
776 }
777 }
778
779 // if any one of the memory pool has undefined init_size or max_size,
780 // set it to MemoryUsage::undefined_size()
781 if (has_undefined_init_size) {
782 total_init = MemoryUsage::undefined_size();
783 }
784 if (has_undefined_max_size) {
785 total_max = MemoryUsage::undefined_size();
786 }
787
788 usage = MemoryUsage(total_init, total_used, total_committed, total_max);
789 }
790
791 Handle obj = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL);
792 return JNIHandles::make_local(THREAD, obj());
793 JVM_END
794
795 // Returns the boolean value of a given attribute.
796 JVM_LEAF(jboolean, jmm_GetBoolAttribute(JNIEnv *env, jmmBoolAttribute att))
797 switch (att) {
798 case JMM_VERBOSE_GC:
799 return MemoryService::get_verbose();
800 case JMM_VERBOSE_CLASS:
801 return ClassLoadingService::get_verbose();
802 case JMM_THREAD_CONTENTION_MONITORING:
803 return ThreadService::is_thread_monitoring_contention();
804 case JMM_THREAD_CPU_TIME:
805 return ThreadService::is_thread_cpu_time_enabled();
806 case JMM_THREAD_ALLOCATED_MEMORY:
807 return ThreadService::is_thread_allocated_memory_enabled();
808 default:
809 assert(0, "Unrecognized attribute");
810 return false;
811 }
812 JVM_END
813
814 // Sets the given boolean attribute and returns the previous value.
815 JVM_ENTRY(jboolean, jmm_SetBoolAttribute(JNIEnv *env, jmmBoolAttribute att, jboolean flag))
816 switch (att) {
817 case JMM_VERBOSE_GC:
818 return MemoryService::set_verbose(flag != 0);
819 case JMM_VERBOSE_CLASS:
820 return ClassLoadingService::set_verbose(flag != 0);
821 case JMM_THREAD_CONTENTION_MONITORING:
822 return ThreadService::set_thread_monitoring_contention(flag != 0);
823 case JMM_THREAD_CPU_TIME:
824 return ThreadService::set_thread_cpu_time_enabled(flag != 0);
825 case JMM_THREAD_ALLOCATED_MEMORY:
826 return ThreadService::set_thread_allocated_memory_enabled(flag != 0);
827 default:
828 assert(0, "Unrecognized attribute");
829 return false;
830 }
831 JVM_END
832
833
834 static jlong get_gc_attribute(GCMemoryManager* mgr, jmmLongAttribute att) {
835 switch (att) {
836 case JMM_GC_TIME_MS:
837 return mgr->gc_time_ms();
838
839 case JMM_GC_COUNT:
840 return mgr->gc_count();
841
842 case JMM_GC_EXT_ATTRIBUTE_INFO_SIZE:
843 // current implementation only has 1 ext attribute
844 return 1;
845
846 default:
847 assert(0, "Unrecognized GC attribute");
848 return -1;
849 }
850 }
851
852 class VmThreadCountClosure: public ThreadClosure {
853 private:
854 int _count;
855 public:
856 VmThreadCountClosure() : _count(0) {};
857 void do_thread(Thread* thread);
858 int count() { return _count; }
859 };
860
861 void VmThreadCountClosure::do_thread(Thread* thread) {
862 // exclude externally visible JavaThreads
863 if (thread->is_Java_thread() && !thread->is_hidden_from_external_view()) {
864 return;
865 }
866
867 _count++;
868 }
869
870 static jint get_vm_thread_count() {
871 VmThreadCountClosure vmtcc;
872 {
873 MutexLocker ml(Threads_lock);
874 Threads::threads_do(&vmtcc);
875 }
876
877 return vmtcc.count();
878 }
879
880 static jint get_num_flags() {
881 // last flag entry is always null, so subtract 1
882 int nFlags = (int) JVMFlag::numFlags - 1;
883 int count = 0;
884 for (int i = 0; i < nFlags; i++) {
885 JVMFlag* flag = &JVMFlag::flags[i];
886 // Exclude the locked (diagnostic, experimental) flags
887 if (flag->is_unlocked() || flag->is_unlocker()) {
888 count++;
889 }
890 }
891 return count;
892 }
893
894 static jlong get_gc_cpu_time() {
895 if (!os::is_thread_cpu_time_supported()) {
896 return -1;
897 }
898
899 {
900 MutexLocker hl(Heap_lock);
901 if (Universe::heap()->is_shutting_down()) {
902 return -1;
903 }
904
905 return CPUTimeUsage::GC::total();
906 }
907 }
908
909 static jlong get_long_attribute(jmmLongAttribute att) {
910 switch (att) {
911 case JMM_CLASS_LOADED_COUNT:
912 return ClassLoadingService::loaded_class_count();
913
914 case JMM_CLASS_UNLOADED_COUNT:
915 return ClassLoadingService::unloaded_class_count();
916
917 case JMM_THREAD_TOTAL_COUNT:
918 return ThreadService::get_total_thread_count();
919
920 case JMM_THREAD_LIVE_COUNT:
921 return ThreadService::get_live_thread_count();
922
923 case JMM_THREAD_PEAK_COUNT:
924 return ThreadService::get_peak_thread_count();
925
926 case JMM_THREAD_DAEMON_COUNT:
927 return ThreadService::get_daemon_thread_count();
928
929 case JMM_JVM_INIT_DONE_TIME_MS:
930 return Management::vm_init_done_time();
931
932 case JMM_JVM_UPTIME_MS:
933 return Management::ticks_to_ms(os::elapsed_counter());
934
935 case JMM_TOTAL_GC_CPU_TIME:
936 return get_gc_cpu_time();
937
938 case JMM_COMPILE_TOTAL_TIME_MS:
939 return Management::ticks_to_ms(CompileBroker::total_compilation_ticks());
940
941 case JMM_OS_PROCESS_ID:
942 return os::current_process_id();
943
944 // Hotspot-specific counters
945 case JMM_CLASS_LOADED_BYTES:
946 return ClassLoadingService::loaded_class_bytes();
947
948 case JMM_CLASS_UNLOADED_BYTES:
949 return ClassLoadingService::unloaded_class_bytes();
950
951 case JMM_SHARED_CLASS_LOADED_COUNT:
952 return ClassLoadingService::loaded_shared_class_count();
953
954 case JMM_SHARED_CLASS_UNLOADED_COUNT:
955 return ClassLoadingService::unloaded_shared_class_count();
956
957
958 case JMM_SHARED_CLASS_LOADED_BYTES:
959 return ClassLoadingService::loaded_shared_class_bytes();
960
961 case JMM_SHARED_CLASS_UNLOADED_BYTES:
962 return ClassLoadingService::unloaded_shared_class_bytes();
963
964 case JMM_TOTAL_CLASSLOAD_TIME_MS:
965 return ClassLoader::classloader_time_ms();
966
967 case JMM_VM_GLOBAL_COUNT:
968 return get_num_flags();
969
970 case JMM_SAFEPOINT_COUNT:
971 return RuntimeService::safepoint_count();
972
973 case JMM_TOTAL_SAFEPOINTSYNC_TIME_MS:
974 return RuntimeService::safepoint_sync_time_ms();
975
976 case JMM_TOTAL_STOPPED_TIME_MS:
977 return RuntimeService::safepoint_time_ms();
978
979 case JMM_TOTAL_APP_TIME_MS:
980 return RuntimeService::application_time_ms();
981
982 case JMM_VM_THREAD_COUNT:
983 return get_vm_thread_count();
984
985 case JMM_CLASS_INIT_TOTAL_COUNT:
986 return ClassLoader::class_init_count();
987
988 case JMM_CLASS_INIT_TOTAL_TIME_MS:
989 return ClassLoader::class_init_time_ms();
990
991 case JMM_CLASS_VERIFY_TOTAL_TIME_MS:
992 return ClassLoader::class_verify_time_ms();
993
994 case JMM_METHOD_DATA_SIZE_BYTES:
995 return ClassLoadingService::class_method_data_size();
996
997 case JMM_OS_MEM_TOTAL_PHYSICAL_BYTES:
998 return static_cast<jlong>(os::physical_memory());
999
1000 default:
1001 return -1;
1002 }
1003 }
1004
1005
1006 // Returns the long value of a given attribute.
1007 JVM_ENTRY(jlong, jmm_GetLongAttribute(JNIEnv *env, jobject obj, jmmLongAttribute att))
1008 if (obj == nullptr) {
1009 return get_long_attribute(att);
1010 } else {
1011 GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK_(0L));
1012 if (mgr != nullptr) {
1013 return get_gc_attribute(mgr, att);
1014 }
1015 }
1016 return -1;
1017 JVM_END
1018
1019 // Gets the value of all attributes specified in the given array
1020 // and sets the value in the result array.
1021 // Returns the number of attributes found.
1022 JVM_ENTRY(jint, jmm_GetLongAttributes(JNIEnv *env,
1023 jobject obj,
1024 jmmLongAttribute* atts,
1025 jint count,
1026 jlong* result))
1027
1028 int num_atts = 0;
1029 if (obj == nullptr) {
1030 for (int i = 0; i < count; i++) {
1031 result[i] = get_long_attribute(atts[i]);
1032 if (result[i] != -1) {
1033 num_atts++;
1034 }
1035 }
1036 } else {
1037 GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK_0);
1038 for (int i = 0; i < count; i++) {
1039 result[i] = get_gc_attribute(mgr, atts[i]);
1040 if (result[i] != -1) {
1041 num_atts++;
1042 }
1043 }
1044 }
1045 return num_atts;
1046 JVM_END
1047
1048 // Helper function to do thread dump for a specific list of threads
1049 static void do_thread_dump(ThreadDumpResult* dump_result,
1050 typeArrayHandle ids_ah, // array of thread ID (long[])
1051 int num_threads,
1052 int max_depth,
1053 bool with_locked_monitors,
1054 bool with_locked_synchronizers,
1055 TRAPS) {
1056 // no need to actually perform thread dump if no TIDs are specified
1057 if (num_threads == 0) return;
1058
1059 // First get an array of threadObj handles.
1060 // A JavaThread may terminate before we get the stack trace.
1061 GrowableArray<instanceHandle>* thread_handle_array = new GrowableArray<instanceHandle>(num_threads);
1062
1063 {
1064 // Need this ThreadsListHandle for converting Java thread IDs into
1065 // threadObj handles; dump_result->set_t_list() is called in the
1066 // VM op below so we can't use it yet.
1067 ThreadsListHandle tlh;
1068 for (int i = 0; i < num_threads; i++) {
1069 jlong tid = ids_ah->long_at(i);
1070 JavaThread* jt = tlh.list()->find_JavaThread_from_java_tid(tid);
1071 oop thread_obj = is_platform_thread(jt) ? jt->threadObj() : (oop)nullptr;
1072 instanceHandle threadObj_h(THREAD, (instanceOop) thread_obj);
1073 thread_handle_array->append(threadObj_h);
1074 }
1075 }
1076
1077 // Obtain thread dumps and thread snapshot information
1078 VM_ThreadDump op(dump_result,
1079 thread_handle_array,
1080 num_threads,
1081 max_depth, /* stack depth */
1082 with_locked_monitors,
1083 with_locked_synchronizers);
1084 VMThread::execute(&op);
1085 }
1086
1087 // Gets an array of ThreadInfo objects. Each element is the ThreadInfo
1088 // for the thread ID specified in the corresponding entry in
1089 // the given array of thread IDs; or null if the thread does not exist
1090 // or has terminated.
1091 //
1092 // Input parameters:
1093 // ids - array of thread IDs
1094 // maxDepth - the maximum depth of stack traces to be dumped:
1095 // maxDepth == -1 requests to dump entire stack trace.
1096 // maxDepth == 0 requests no stack trace.
1097 // infoArray - array of ThreadInfo objects
1098 //
1099 // QQQ - Why does this method return a value instead of void?
1100 JVM_ENTRY(jint, jmm_GetThreadInfo(JNIEnv *env, jlongArray ids, jint maxDepth, jobjectArray infoArray))
1101 // Check if threads is null
1102 if (ids == nullptr || infoArray == nullptr) {
1103 THROW_(vmSymbols::java_lang_NullPointerException(), -1);
1104 }
1105
1106 if (maxDepth < -1) {
1107 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
1108 "Invalid maxDepth", -1);
1109 }
1110
1111 ResourceMark rm(THREAD);
1112 typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids));
1113 typeArrayHandle ids_ah(THREAD, ta);
1114
1115 oop infoArray_obj = JNIHandles::resolve_non_null(infoArray);
1116 objArrayOop oa = objArrayOop(infoArray_obj);
1117 objArrayHandle infoArray_h(THREAD, oa);
1118
1119 // validate the thread id array
1120 validate_thread_id_array(ids_ah, CHECK_0);
1121
1122 // validate the ThreadInfo[] parameters
1123 validate_thread_info_array(infoArray_h, CHECK_0);
1124
1125 // infoArray must be of the same length as the given array of thread IDs
1126 int num_threads = ids_ah->length();
1127 if (num_threads != infoArray_h->length()) {
1128 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
1129 "The length of the given ThreadInfo array does not match the length of the given array of thread IDs", -1);
1130 }
1131
1132 // Must use ThreadDumpResult to store the ThreadSnapshot.
1133 // GC may occur after the thread snapshots are taken but before
1134 // this function returns. The threadObj and other oops kept
1135 // in the ThreadSnapshot are marked and adjusted during GC.
1136 ThreadDumpResult dump_result(num_threads);
1137
1138 if (maxDepth == 0) {
1139 // No stack trace to dump so we do not need to stop the world.
1140 // Since we never do the VM op here we must set the threads list.
1141 dump_result.set_t_list();
1142 for (int i = 0; i < num_threads; i++) {
1143 jlong tid = ids_ah->long_at(i);
1144 JavaThread* jt = dump_result.t_list()->find_JavaThread_from_java_tid(tid);
1145 if (jt == nullptr) {
1146 // if the thread does not exist or now it is terminated,
1147 // create dummy snapshot
1148 dump_result.add_thread_snapshot();
1149 } else {
1150 dump_result.add_thread_snapshot(jt);
1151 }
1152 }
1153 } else {
1154 // obtain thread dump with the specific list of threads with stack trace
1155 do_thread_dump(&dump_result,
1156 ids_ah,
1157 num_threads,
1158 maxDepth,
1159 false, /* no locked monitor */
1160 false, /* no locked synchronizers */
1161 CHECK_0);
1162 }
1163
1164 int num_snapshots = dump_result.num_snapshots();
1165 assert(num_snapshots == num_threads, "Must match the number of thread snapshots");
1166 assert(num_snapshots == 0 || dump_result.t_list_has_been_set(), "ThreadsList must have been set if we have a snapshot");
1167 int index = 0;
1168 for (ThreadSnapshot* ts = dump_result.snapshots(); ts != nullptr; index++, ts = ts->next()) {
1169 // For each thread, create an java/lang/management/ThreadInfo object
1170 // and fill with the thread information
1171
1172 if (!is_platform_thread(ts)) {
1173 // if the thread does not exist, has terminated, or is a virtual thread, then set threadinfo to null
1174 infoArray_h->obj_at_put(index, nullptr);
1175 continue;
1176 }
1177
1178 // Create java.lang.management.ThreadInfo object
1179 instanceOop info_obj = Management::create_thread_info_instance(ts, CHECK_0);
1180 infoArray_h->obj_at_put(index, info_obj);
1181 }
1182 return 0;
1183 JVM_END
1184
1185 // Dump thread info for the specified threads.
1186 // It returns an array of ThreadInfo objects. Each element is the ThreadInfo
1187 // for the thread ID specified in the corresponding entry in
1188 // the given array of thread IDs; or null if the thread does not exist
1189 // or has terminated.
1190 //
1191 // Input parameter:
1192 // ids - array of thread IDs; null indicates all live threads
1193 // locked_monitors - if true, dump locked object monitors
1194 // locked_synchronizers - if true, dump locked JSR-166 synchronizers
1195 //
1196 JVM_ENTRY(jobjectArray, jmm_DumpThreads(JNIEnv *env, jlongArray thread_ids, jboolean locked_monitors,
1197 jboolean locked_synchronizers, jint maxDepth))
1198 ResourceMark rm(THREAD);
1199
1200 typeArrayOop ta = typeArrayOop(JNIHandles::resolve(thread_ids));
1201 int num_threads = (ta != nullptr ? ta->length() : 0);
1202 typeArrayHandle ids_ah(THREAD, ta);
1203
1204 ThreadDumpResult dump_result(num_threads); // can safepoint
1205
1206 if (ids_ah() != nullptr) {
1207
1208 // validate the thread id array
1209 validate_thread_id_array(ids_ah, CHECK_NULL);
1210
1211 // obtain thread dump of a specific list of threads
1212 do_thread_dump(&dump_result,
1213 ids_ah,
1214 num_threads,
1215 maxDepth, /* stack depth */
1216 (locked_monitors ? true : false), /* with locked monitors */
1217 (locked_synchronizers ? true : false), /* with locked synchronizers */
1218 CHECK_NULL);
1219 } else {
1220 // obtain thread dump of all threads
1221 VM_ThreadDump op(&dump_result,
1222 maxDepth, /* stack depth */
1223 (locked_monitors ? true : false), /* with locked monitors */
1224 (locked_synchronizers ? true : false) /* with locked synchronizers */);
1225 VMThread::execute(&op);
1226 }
1227
1228 int num_snapshots = dump_result.num_snapshots();
1229 assert(num_snapshots == 0 || dump_result.t_list_has_been_set(), "ThreadsList must have been set if we have a snapshot");
1230
1231 // create the result ThreadInfo[] object
1232 InstanceKlass* ik = Management::java_lang_management_ThreadInfo_klass(CHECK_NULL);
1233 objArrayOop r = oopFactory::new_objArray(ik, num_snapshots, CHECK_NULL);
1234 objArrayHandle result_h(THREAD, r);
1235
1236 int index = 0;
1237 for (ThreadSnapshot* ts = dump_result.snapshots(); ts != nullptr; ts = ts->next(), index++) {
1238 if (!is_platform_thread(ts)) {
1239 // if the thread does not exist, has terminated, or is a virtual thread, then set threadinfo to null
1240 result_h->obj_at_put(index, nullptr);
1241 continue;
1242 }
1243
1244 ThreadStackTrace* stacktrace = ts->get_stack_trace();
1245 assert(stacktrace != nullptr, "Must have a stack trace dumped");
1246
1247 // Create Object[] filled with locked monitors
1248 // Create int[] filled with the stack depth where a monitor was locked
1249 int num_frames = stacktrace->get_stack_depth();
1250 int num_locked_monitors = stacktrace->num_jni_locked_monitors();
1251
1252 // Count the total number of locked monitors
1253 for (int i = 0; i < num_frames; i++) {
1254 StackFrameInfo* frame = stacktrace->stack_frame_at(i);
1255 num_locked_monitors += frame->num_locked_monitors();
1256 }
1257
1258 objArrayHandle monitors_array;
1259 typeArrayHandle depths_array;
1260 objArrayHandle synchronizers_array;
1261
1262 if (locked_monitors) {
1263 // Constructs Object[] and int[] to contain the object monitor and the stack depth
1264 // where the thread locked it
1265 objArrayOop array = oopFactory::new_objArray(vmClasses::Object_klass(), num_locked_monitors, CHECK_NULL);
1266 objArrayHandle mh(THREAD, array);
1267 monitors_array = mh;
1268
1269 typeArrayOop tarray = oopFactory::new_typeArray(T_INT, num_locked_monitors, CHECK_NULL);
1270 typeArrayHandle dh(THREAD, tarray);
1271 depths_array = dh;
1272
1273 int count = 0;
1274 int j = 0;
1275 for (int depth = 0; depth < num_frames; depth++) {
1276 StackFrameInfo* frame = stacktrace->stack_frame_at(depth);
1277 int len = frame->num_locked_monitors();
1278 GrowableArray<OopHandle>* locked_monitors = frame->locked_monitors();
1279 for (j = 0; j < len; j++) {
1280 oop monitor = locked_monitors->at(j).resolve();
1281 assert(monitor != nullptr, "must be a Java object");
1282 monitors_array->obj_at_put(count, monitor);
1283 depths_array->int_at_put(count, depth);
1284 count++;
1285 }
1286 }
1287
1288 GrowableArray<OopHandle>* jni_locked_monitors = stacktrace->jni_locked_monitors();
1289 for (j = 0; j < jni_locked_monitors->length(); j++) {
1290 oop object = jni_locked_monitors->at(j).resolve();
1291 assert(object != nullptr, "must be a Java object");
1292 monitors_array->obj_at_put(count, object);
1293 // Monitor locked via JNI MonitorEnter call doesn't have stack depth info
1294 depths_array->int_at_put(count, -1);
1295 count++;
1296 }
1297 assert(count == num_locked_monitors, "number of locked monitors doesn't match");
1298 }
1299
1300 if (locked_synchronizers) {
1301 // Create Object[] filled with locked JSR-166 synchronizers
1302 assert(ts->threadObj() != nullptr, "Must be a valid JavaThread");
1303 ThreadConcurrentLocks* tcl = ts->get_concurrent_locks();
1304 GrowableArray<OopHandle>* locks = (tcl != nullptr ? tcl->owned_locks() : nullptr);
1305 int num_locked_synchronizers = (locks != nullptr ? locks->length() : 0);
1306
1307 objArrayOop array = oopFactory::new_objArray(vmClasses::Object_klass(), num_locked_synchronizers, CHECK_NULL);
1308 objArrayHandle sh(THREAD, array);
1309 synchronizers_array = sh;
1310
1311 for (int k = 0; k < num_locked_synchronizers; k++) {
1312 synchronizers_array->obj_at_put(k, locks->at(k).resolve());
1313 }
1314 }
1315
1316 // Create java.lang.management.ThreadInfo object
1317 instanceOop info_obj = Management::create_thread_info_instance(ts,
1318 monitors_array,
1319 depths_array,
1320 synchronizers_array,
1321 CHECK_NULL);
1322 result_h->obj_at_put(index, info_obj);
1323 }
1324
1325 return (jobjectArray) JNIHandles::make_local(THREAD, result_h());
1326 JVM_END
1327
1328 // Reset statistic. Return true if the requested statistic is reset.
1329 // Otherwise, return false.
1330 //
1331 // Input parameters:
1332 // obj - specify which instance the statistic associated with to be reset
1333 // For PEAK_POOL_USAGE stat, obj is required to be a memory pool object.
1334 // For THREAD_CONTENTION_COUNT and TIME stat, obj is required to be a thread ID.
1335 // type - the type of statistic to be reset
1336 //
1337 JVM_ENTRY(jboolean, jmm_ResetStatistic(JNIEnv *env, jvalue obj, jmmStatisticType type))
1338 ResourceMark rm(THREAD);
1339
1340 switch (type) {
1341 case JMM_STAT_PEAK_THREAD_COUNT:
1342 ThreadService::reset_peak_thread_count();
1343 return true;
1344
1345 case JMM_STAT_THREAD_CONTENTION_COUNT:
1346 case JMM_STAT_THREAD_CONTENTION_TIME: {
1347 jlong tid = obj.j;
1348 if (tid < 0) {
1349 THROW_(vmSymbols::java_lang_IllegalArgumentException(), JNI_FALSE);
1350 }
1351
1352 // Look for the JavaThread of this given tid
1353 JavaThreadIteratorWithHandle jtiwh;
1354 if (tid == 0) {
1355 // reset contention statistics for all threads if tid == 0
1356 for (; JavaThread *java_thread = jtiwh.next(); ) {
1357 if (type == JMM_STAT_THREAD_CONTENTION_COUNT) {
1358 ThreadService::reset_contention_count_stat(java_thread);
1359 } else {
1360 ThreadService::reset_contention_time_stat(java_thread);
1361 }
1362 }
1363 } else {
1364 // reset contention statistics for a given thread
1365 JavaThread* java_thread = jtiwh.list()->find_JavaThread_from_java_tid(tid);
1366 if (java_thread == nullptr) {
1367 return false;
1368 }
1369
1370 if (type == JMM_STAT_THREAD_CONTENTION_COUNT) {
1371 ThreadService::reset_contention_count_stat(java_thread);
1372 } else {
1373 ThreadService::reset_contention_time_stat(java_thread);
1374 }
1375 }
1376 return true;
1377 break;
1378 }
1379 case JMM_STAT_PEAK_POOL_USAGE: {
1380 jobject o = obj.l;
1381 if (o == nullptr) {
1382 THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE);
1383 }
1384
1385 oop pool_obj = JNIHandles::resolve(o);
1386 assert(pool_obj->is_instance(), "Should be an instanceOop");
1387 instanceHandle ph(THREAD, (instanceOop) pool_obj);
1388
1389 MemoryPool* pool = MemoryService::get_memory_pool(ph);
1390 if (pool != nullptr) {
1391 pool->reset_peak_memory_usage();
1392 return true;
1393 }
1394 break;
1395 }
1396 case JMM_STAT_GC_STAT: {
1397 jobject o = obj.l;
1398 if (o == nullptr) {
1399 THROW_(vmSymbols::java_lang_NullPointerException(), JNI_FALSE);
1400 }
1401
1402 GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(o, CHECK_false);
1403 if (mgr != nullptr) {
1404 mgr->reset_gc_stat();
1405 return true;
1406 }
1407 break;
1408 }
1409 default:
1410 assert(0, "Unknown Statistic Type");
1411 }
1412 return false;
1413 JVM_END
1414
1415 // Returns the fast estimate of CPU time consumed by
1416 // a given thread (in nanoseconds).
1417 // If thread_id == 0, return CPU time for the current thread.
1418 JVM_ENTRY(jlong, jmm_GetThreadCpuTime(JNIEnv *env, jlong thread_id))
1419 if (!os::is_thread_cpu_time_supported()) {
1420 return -1;
1421 }
1422
1423 if (thread_id < 0) {
1424 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
1425 "Invalid thread ID", -1);
1426 }
1427
1428 JavaThread* java_thread = nullptr;
1429 if (thread_id == 0) {
1430 // current thread
1431 return os::current_thread_cpu_time();
1432 } else {
1433 ThreadsListHandle tlh;
1434 java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id);
1435 if (is_platform_thread(java_thread)) {
1436 return os::thread_cpu_time((Thread*) java_thread);
1437 }
1438 }
1439 return -1;
1440 JVM_END
1441
1442 // Returns a String array of all VM global flag names
1443 JVM_ENTRY(jobjectArray, jmm_GetVMGlobalNames(JNIEnv *env))
1444 // last flag entry is always null, so subtract 1
1445 int nFlags = (int) JVMFlag::numFlags - 1;
1446 // allocate a temp array
1447 refArrayOop r = oopFactory::new_refArray(vmClasses::String_klass(),
1448 nFlags,
1449 CHECK_NULL);
1450 refArrayHandle flags_ah(THREAD, r);
1451 int num_entries = 0;
1452 for (int i = 0; i < nFlags; i++) {
1453 JVMFlag* flag = &JVMFlag::flags[i];
1454 // Exclude develop flags in product builds.
1455 if (flag->is_constant_in_binary()) {
1456 continue;
1457 }
1458 // Exclude the locked (experimental, diagnostic) flags
1459 if (flag->is_unlocked() || flag->is_unlocker()) {
1460 Handle s = java_lang_String::create_from_str(flag->name(), CHECK_NULL);
1461 flags_ah->obj_at_put(num_entries, s());
1462 num_entries++;
1463 }
1464 }
1465
1466 if (num_entries < nFlags) {
1467 // Return array of right length
1468 refArrayOop res = oopFactory::new_refArray(vmClasses::String_klass(), num_entries, CHECK_NULL);
1469 for(int i = 0; i < num_entries; i++) {
1470 res->obj_at_put(i, flags_ah->obj_at(i));
1471 }
1472 return (jobjectArray)JNIHandles::make_local(THREAD, res);
1473 }
1474
1475 return (jobjectArray)JNIHandles::make_local(THREAD, flags_ah());
1476 JVM_END
1477
1478 // Utility function used by jmm_GetVMGlobals. Returns false if flag type
1479 // can't be determined, true otherwise. If false is returned, then *global
1480 // will be incomplete and invalid.
1481 static bool add_global_entry(Handle name, jmmVMGlobal *global, JVMFlag *flag, TRAPS) {
1482 Handle flag_name;
1483 if (name() == nullptr) {
1484 flag_name = java_lang_String::create_from_str(flag->name(), CHECK_false);
1485 } else {
1486 flag_name = name;
1487 }
1488 global->name = (jstring)JNIHandles::make_local(THREAD, flag_name());
1489
1490 if (flag->is_bool()) {
1491 global->value.z = flag->get_bool() ? JNI_TRUE : JNI_FALSE;
1492 global->type = JMM_VMGLOBAL_TYPE_JBOOLEAN;
1493 } else if (flag->is_int()) {
1494 global->value.j = (jlong)flag->get_int();
1495 global->type = JMM_VMGLOBAL_TYPE_JLONG;
1496 } else if (flag->is_uint()) {
1497 global->value.j = (jlong)flag->get_uint();
1498 global->type = JMM_VMGLOBAL_TYPE_JLONG;
1499 } else if (flag->is_intx()) {
1500 global->value.j = (jlong)flag->get_intx();
1501 global->type = JMM_VMGLOBAL_TYPE_JLONG;
1502 } else if (flag->is_uintx()) {
1503 global->value.j = (jlong)flag->get_uintx();
1504 global->type = JMM_VMGLOBAL_TYPE_JLONG;
1505 } else if (flag->is_uint64_t()) {
1506 global->value.j = (jlong)flag->get_uint64_t();
1507 global->type = JMM_VMGLOBAL_TYPE_JLONG;
1508 } else if (flag->is_double()) {
1509 global->value.d = (jdouble)flag->get_double();
1510 global->type = JMM_VMGLOBAL_TYPE_JDOUBLE;
1511 } else if (flag->is_size_t()) {
1512 global->value.j = (jlong)flag->get_size_t();
1513 global->type = JMM_VMGLOBAL_TYPE_JLONG;
1514 } else if (flag->is_ccstr()) {
1515 Handle str = java_lang_String::create_from_str(flag->get_ccstr(), CHECK_false);
1516 global->value.l = (jobject)JNIHandles::make_local(THREAD, str());
1517 global->type = JMM_VMGLOBAL_TYPE_JSTRING;
1518 } else {
1519 global->type = JMM_VMGLOBAL_TYPE_UNKNOWN;
1520 return false;
1521 }
1522
1523 global->writeable = flag->is_writeable();
1524 global->external = flag->is_external();
1525 switch (flag->get_origin()) {
1526 case JVMFlagOrigin::DEFAULT:
1527 global->origin = JMM_VMGLOBAL_ORIGIN_DEFAULT;
1528 break;
1529 case JVMFlagOrigin::COMMAND_LINE:
1530 global->origin = JMM_VMGLOBAL_ORIGIN_COMMAND_LINE;
1531 break;
1532 case JVMFlagOrigin::ENVIRON_VAR:
1533 global->origin = JMM_VMGLOBAL_ORIGIN_ENVIRON_VAR;
1534 break;
1535 case JVMFlagOrigin::CONFIG_FILE:
1536 global->origin = JMM_VMGLOBAL_ORIGIN_CONFIG_FILE;
1537 break;
1538 case JVMFlagOrigin::MANAGEMENT:
1539 global->origin = JMM_VMGLOBAL_ORIGIN_MANAGEMENT;
1540 break;
1541 case JVMFlagOrigin::ERGONOMIC:
1542 global->origin = JMM_VMGLOBAL_ORIGIN_ERGONOMIC;
1543 break;
1544 case JVMFlagOrigin::ATTACH_ON_DEMAND:
1545 global->origin = JMM_VMGLOBAL_ORIGIN_ATTACH_ON_DEMAND;
1546 break;
1547 default:
1548 global->origin = JMM_VMGLOBAL_ORIGIN_OTHER;
1549 }
1550
1551 return true;
1552 }
1553
1554 // Fill globals array of count length with jmmVMGlobal entries
1555 // specified by names. If names == null, fill globals array
1556 // with all Flags. Return value is number of entries
1557 // created in globals.
1558 // If a JVMFlag with a given name in an array element does not
1559 // exist, globals[i].name will be set to null.
1560 JVM_ENTRY(jint, jmm_GetVMGlobals(JNIEnv *env,
1561 jobjectArray names,
1562 jmmVMGlobal *globals,
1563 jint count))
1564
1565
1566 if (globals == nullptr) {
1567 THROW_(vmSymbols::java_lang_NullPointerException(), 0);
1568 }
1569
1570 ResourceMark rm(THREAD);
1571
1572 if (names != nullptr) {
1573 // return the requested globals
1574 refArrayOop ta = oop_cast<refArrayOop>(JNIHandles::resolve_non_null(names));
1575 refArrayHandle names_ah(THREAD, ta);
1576 // Make sure we have a String array
1577 Klass* element_klass = RefArrayKlass::cast(names_ah->klass())->element_klass();
1578 if (element_klass != vmClasses::String_klass()) {
1579 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
1580 "Array element type is not String class", 0);
1581 }
1582
1583 int names_length = names_ah->length();
1584 int num_entries = 0;
1585 for (int i = 0; i < names_length && i < count; i++) {
1586 oop s = names_ah->obj_at(i);
1587 if (s == nullptr) {
1588 THROW_(vmSymbols::java_lang_NullPointerException(), 0);
1589 }
1590
1591 Handle sh(THREAD, s);
1592 char* str = java_lang_String::as_utf8_string(s);
1593 JVMFlag* flag = JVMFlag::find_flag(str);
1594 if (flag != nullptr &&
1595 add_global_entry(sh, &globals[i], flag, THREAD)) {
1596 num_entries++;
1597 } else {
1598 globals[i].name = nullptr;
1599 }
1600 }
1601 return num_entries;
1602 } else {
1603 // return all globals if names == null
1604
1605 // last flag entry is always null, so subtract 1
1606 int nFlags = (int) JVMFlag::numFlags - 1;
1607 Handle null_h;
1608 int num_entries = 0;
1609 for (int i = 0; i < nFlags && num_entries < count; i++) {
1610 JVMFlag* flag = &JVMFlag::flags[i];
1611 // Exclude develop flags in product builds.
1612 if (flag->is_constant_in_binary()) {
1613 continue;
1614 }
1615 // Exclude the locked (diagnostic, experimental) flags
1616 if ((flag->is_unlocked() || flag->is_unlocker()) &&
1617 add_global_entry(null_h, &globals[num_entries], flag, THREAD)) {
1618 num_entries++;
1619 }
1620 }
1621 return num_entries;
1622 }
1623 JVM_END
1624
1625 JVM_ENTRY(void, jmm_SetVMGlobal(JNIEnv *env, jstring flag_name, jvalue new_value))
1626 ResourceMark rm(THREAD);
1627
1628 oop fn = JNIHandles::resolve_external_guard(flag_name);
1629 if (fn == nullptr) {
1630 THROW_MSG(vmSymbols::java_lang_NullPointerException(),
1631 "The flag name cannot be null.");
1632 }
1633 char* name = java_lang_String::as_utf8_string(fn);
1634
1635 FormatBuffer<80> error_msg("%s", "");
1636 int succeed = WriteableFlags::set_flag(name, new_value, JVMFlagOrigin::MANAGEMENT, error_msg);
1637
1638 if (succeed != JVMFlag::SUCCESS) {
1639 if (succeed == JVMFlag::MISSING_VALUE) {
1640 // missing value causes NPE to be thrown
1641 THROW(vmSymbols::java_lang_NullPointerException());
1642 } else {
1643 // all the other errors are reported as IAE with the appropriate error message
1644 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
1645 error_msg.buffer());
1646 }
1647 }
1648 assert(succeed == JVMFlag::SUCCESS, "Setting flag should succeed");
1649 JVM_END
1650
1651 class ThreadTimesClosure: public ThreadClosure {
1652 private:
1653 objArrayHandle _names_strings;
1654 char **_names_chars;
1655 typeArrayHandle _times;
1656 int _names_len;
1657 int _times_len;
1658 int _count;
1659
1660 public:
1661 ThreadTimesClosure(objArrayHandle names, typeArrayHandle times);
1662 ~ThreadTimesClosure();
1663 virtual void do_thread(Thread* thread);
1664 void do_unlocked(TRAPS);
1665 int count() { return _count; }
1666 };
1667
1668 ThreadTimesClosure::ThreadTimesClosure(objArrayHandle names,
1669 typeArrayHandle times) {
1670 assert(names() != nullptr, "names was null");
1671 assert(times() != nullptr, "times was null");
1672 _names_strings = names;
1673 _names_len = names->length();
1674 _names_chars = NEW_C_HEAP_ARRAY(char*, _names_len, mtInternal);
1675 _times = times;
1676 _times_len = times->length();
1677 _count = 0;
1678 }
1679
1680 //
1681 // Called with Threads_lock held
1682 //
1683 void ThreadTimesClosure::do_thread(Thread* thread) {
1684 assert(Threads_lock->owned_by_self(), "Must hold Threads_lock");
1685 assert(thread != nullptr, "thread was null");
1686
1687 // exclude externally visible JavaThreads
1688 if (thread->is_Java_thread() && !thread->is_hidden_from_external_view()) {
1689 return;
1690 }
1691
1692 if (_count >= _names_len || _count >= _times_len) {
1693 // skip if the result array is not big enough
1694 return;
1695 }
1696
1697 ResourceMark rm; // thread->name() uses ResourceArea
1698
1699 assert(thread->name() != nullptr, "All threads should have a name");
1700 _names_chars[_count] = os::strdup_check_oom(thread->name());
1701 _times->long_at_put(_count, os::is_thread_cpu_time_supported() ?
1702 os::thread_cpu_time(thread) : -1);
1703 _count++;
1704 }
1705
1706 // Called without Threads_lock, we can allocate String objects.
1707 void ThreadTimesClosure::do_unlocked(TRAPS) {
1708
1709 for (int i = 0; i < _count; i++) {
1710 Handle s = java_lang_String::create_from_str(_names_chars[i], CHECK);
1711 _names_strings->obj_at_put(i, s());
1712 }
1713 }
1714
1715 ThreadTimesClosure::~ThreadTimesClosure() {
1716 for (int i = 0; i < _count; i++) {
1717 os::free(_names_chars[i]);
1718 }
1719 FREE_C_HEAP_ARRAY(char *, _names_chars);
1720 }
1721
1722 // Fills names with VM internal thread names and times with the corresponding
1723 // CPU times. If names or times is null, a NullPointerException is thrown.
1724 // If the element type of names is not String, an IllegalArgumentException is
1725 // thrown.
1726 // If an array is not large enough to hold all the entries, only the entries
1727 // that fit will be returned. Return value is the number of VM internal
1728 // threads entries.
1729 JVM_ENTRY(jint, jmm_GetInternalThreadTimes(JNIEnv *env,
1730 jobjectArray names,
1731 jlongArray times))
1732 if (names == nullptr || times == nullptr) {
1733 THROW_(vmSymbols::java_lang_NullPointerException(), 0);
1734 }
1735 objArrayOop na = objArrayOop(JNIHandles::resolve_non_null(names));
1736 objArrayHandle names_ah(THREAD, na);
1737
1738 // Make sure we have a String array
1739 Klass* element_klass = ObjArrayKlass::cast(names_ah->klass())->element_klass();
1740 if (element_klass != vmClasses::String_klass()) {
1741 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
1742 "Array element type is not String class", 0);
1743 }
1744
1745 typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(times));
1746 typeArrayHandle times_ah(THREAD, ta);
1747
1748 ThreadTimesClosure ttc(names_ah, times_ah);
1749 {
1750 MutexLocker ml(THREAD, Threads_lock);
1751 Threads::threads_do(&ttc);
1752 }
1753 ttc.do_unlocked(THREAD);
1754 return ttc.count();
1755 JVM_END
1756
1757 static Handle find_deadlocks(bool object_monitors_only, TRAPS) {
1758 ResourceMark rm(THREAD);
1759
1760 VM_FindDeadlocks op(!object_monitors_only /* also check concurrent locks? */);
1761 VMThread::execute(&op);
1762
1763 DeadlockCycle* deadlocks = op.result();
1764 if (deadlocks == nullptr) {
1765 // no deadlock found and return
1766 return Handle();
1767 }
1768
1769 int num_threads = 0;
1770 DeadlockCycle* cycle;
1771 for (cycle = deadlocks; cycle != nullptr; cycle = cycle->next()) {
1772 num_threads += cycle->num_threads();
1773 }
1774
1775 objArrayOop r = oopFactory::new_objArray(vmClasses::Thread_klass(), num_threads, CHECK_NH);
1776 objArrayHandle threads_ah(THREAD, r);
1777
1778 int index = 0;
1779 for (cycle = deadlocks; cycle != nullptr; cycle = cycle->next()) {
1780 GrowableArray<JavaThread*>* deadlock_threads = cycle->threads();
1781 int len = deadlock_threads->length();
1782 for (int i = 0; i < len; i++) {
1783 threads_ah->obj_at_put(index, deadlock_threads->at(i)->threadObj());
1784 index++;
1785 }
1786 }
1787 return threads_ah;
1788 }
1789
1790 // Finds cycles of threads that are deadlocked involved in object monitors
1791 // and JSR-166 synchronizers.
1792 // Returns an array of Thread objects which are in deadlock, if any.
1793 // Otherwise, returns null.
1794 //
1795 // Input parameter:
1796 // object_monitors_only - if true, only check object monitors
1797 //
1798 JVM_ENTRY(jobjectArray, jmm_FindDeadlockedThreads(JNIEnv *env, jboolean object_monitors_only))
1799 Handle result = find_deadlocks(object_monitors_only != 0, CHECK_NULL);
1800 return (jobjectArray) JNIHandles::make_local(THREAD, result());
1801 JVM_END
1802
1803 // Finds cycles of threads that are deadlocked on monitor locks
1804 // Returns an array of Thread objects which are in deadlock, if any.
1805 // Otherwise, returns null.
1806 JVM_ENTRY(jobjectArray, jmm_FindMonitorDeadlockedThreads(JNIEnv *env))
1807 Handle result = find_deadlocks(true, CHECK_NULL);
1808 return (jobjectArray) JNIHandles::make_local(THREAD, result());
1809 JVM_END
1810
1811 // Gets the information about GC extension attributes including
1812 // the name of the attribute, its type, and a short description.
1813 //
1814 // Input parameters:
1815 // mgr - GC memory manager
1816 // info - caller allocated array of jmmExtAttributeInfo
1817 // count - number of elements of the info array
1818 //
1819 // Returns the number of GC extension attributes filled in the info array; or
1820 // -1 if info is not big enough
1821 //
1822 JVM_ENTRY(jint, jmm_GetGCExtAttributeInfo(JNIEnv *env, jobject mgr, jmmExtAttributeInfo* info, jint count))
1823 // All GC memory managers have 1 attribute (number of GC threads)
1824 if (count == 0) {
1825 return 0;
1826 }
1827
1828 if (info == nullptr) {
1829 THROW_(vmSymbols::java_lang_NullPointerException(), 0);
1830 }
1831
1832 info[0].name = "GcThreadCount";
1833 info[0].type = 'I';
1834 info[0].description = "Number of GC threads";
1835 return 1;
1836 JVM_END
1837
1838 // verify the given array is an array of java/lang/management/MemoryUsage objects
1839 // of a given length and return the objArrayOop
1840 static objArrayOop get_memory_usage_objArray(jobjectArray array, int length, TRAPS) {
1841 if (array == nullptr) {
1842 THROW_NULL(vmSymbols::java_lang_NullPointerException());
1843 }
1844
1845 objArrayOop oa = objArrayOop(JNIHandles::resolve_non_null(array));
1846 objArrayHandle array_h(THREAD, oa);
1847
1848 // array must be of the given length
1849 if (length != array_h->length()) {
1850 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
1851 "The length of the given MemoryUsage array does not match the number of memory pools.");
1852 }
1853
1854 // check if the element of array is of type MemoryUsage class
1855 Klass* usage_klass = Management::java_lang_management_MemoryUsage_klass(CHECK_NULL);
1856 Klass* element_klass = ObjArrayKlass::cast(array_h->klass())->element_klass();
1857 if (element_klass != usage_klass) {
1858 THROW_MSG_NULL(vmSymbols::java_lang_IllegalArgumentException(),
1859 "The element type is not MemoryUsage class");
1860 }
1861
1862 return array_h();
1863 }
1864
1865 // Gets the statistics of the last GC of a given GC memory manager.
1866 // Input parameters:
1867 // obj - GarbageCollectorMXBean object
1868 // gc_stat - caller allocated jmmGCStat where:
1869 // a. before_gc_usage - array of MemoryUsage objects
1870 // b. after_gc_usage - array of MemoryUsage objects
1871 // c. gc_ext_attributes_values_size is set to the
1872 // gc_ext_attribute_values array allocated
1873 // d. gc_ext_attribute_values is a caller allocated array of jvalue.
1874 //
1875 // On return,
1876 // gc_index == 0 indicates no GC statistics available
1877 //
1878 // before_gc_usage and after_gc_usage - filled with per memory pool
1879 // before and after GC usage in the same order as the memory pools
1880 // returned by GetMemoryPools for a given GC memory manager.
1881 // num_gc_ext_attributes indicates the number of elements in
1882 // the gc_ext_attribute_values array is filled; or
1883 // -1 if the gc_ext_attributes_values array is not big enough
1884 //
1885 JVM_ENTRY(void, jmm_GetLastGCStat(JNIEnv *env, jobject obj, jmmGCStat *gc_stat))
1886 ResourceMark rm(THREAD);
1887
1888 if (gc_stat->gc_ext_attribute_values_size > 0 && gc_stat->gc_ext_attribute_values == nullptr) {
1889 THROW(vmSymbols::java_lang_NullPointerException());
1890 }
1891
1892 // Get the GCMemoryManager
1893 GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK);
1894
1895 // Make a copy of the last GC statistics
1896 // GC may occur while constructing the last GC information
1897 int num_pools = MemoryService::num_memory_pools();
1898 GCStatInfo stat(num_pools);
1899 if (mgr->get_last_gc_stat(&stat) == 0) {
1900 gc_stat->gc_index = 0;
1901 return;
1902 }
1903
1904 gc_stat->gc_index = stat.gc_index();
1905 gc_stat->start_time = Management::ticks_to_ms(stat.start_time());
1906 gc_stat->end_time = Management::ticks_to_ms(stat.end_time());
1907
1908 // Current implementation does not have GC extension attributes
1909 gc_stat->num_gc_ext_attributes = 0;
1910
1911 // Fill the arrays of MemoryUsage objects with before and after GC
1912 // per pool memory usage
1913 objArrayOop bu = get_memory_usage_objArray(gc_stat->usage_before_gc,
1914 num_pools,
1915 CHECK);
1916 objArrayHandle usage_before_gc_ah(THREAD, bu);
1917
1918 objArrayOop au = get_memory_usage_objArray(gc_stat->usage_after_gc,
1919 num_pools,
1920 CHECK);
1921 objArrayHandle usage_after_gc_ah(THREAD, au);
1922
1923 for (int i = 0; i < num_pools; i++) {
1924 Handle before_usage = MemoryService::create_MemoryUsage_obj(stat.before_gc_usage_for_pool(i), CHECK);
1925 Handle after_usage;
1926
1927 MemoryUsage u = stat.after_gc_usage_for_pool(i);
1928 if (u.max_size() == 0 && u.used() > 0) {
1929 // If max size == 0, this pool is a survivor space.
1930 // Set max size = -1 since the pools will be swapped after GC.
1931 MemoryUsage usage(u.init_size(), u.used(), u.committed(), MemoryUsage::undefined_size());
1932 after_usage = MemoryService::create_MemoryUsage_obj(usage, CHECK);
1933 } else {
1934 after_usage = MemoryService::create_MemoryUsage_obj(stat.after_gc_usage_for_pool(i), CHECK);
1935 }
1936 usage_before_gc_ah->obj_at_put(i, before_usage());
1937 usage_after_gc_ah->obj_at_put(i, after_usage());
1938 }
1939
1940 if (gc_stat->gc_ext_attribute_values_size > 0) {
1941 // Current implementation only has 1 attribute (number of GC threads)
1942 // The type is 'I'
1943 gc_stat->gc_ext_attribute_values[0].i = mgr->num_gc_threads();
1944 }
1945 JVM_END
1946
1947 JVM_ENTRY(void, jmm_SetGCNotificationEnabled(JNIEnv *env, jobject obj, jboolean enabled))
1948 ResourceMark rm(THREAD);
1949 // Get the GCMemoryManager
1950 GCMemoryManager* mgr = get_gc_memory_manager_from_jobject(obj, CHECK);
1951 mgr->set_notification_enabled(enabled?true:false);
1952 JVM_END
1953
1954 // Dump heap - Returns 0 if succeeds.
1955 JVM_ENTRY(jint, jmm_DumpHeap0(JNIEnv *env, jstring outputfile, jboolean live))
1956 #if INCLUDE_SERVICES
1957 ResourceMark rm(THREAD);
1958 oop on = JNIHandles::resolve_external_guard(outputfile);
1959 if (on == nullptr) {
1960 THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
1961 "Output file name cannot be null.", -1);
1962 }
1963 Handle onhandle(THREAD, on);
1964 char* name = java_lang_String::as_platform_dependent_str(onhandle, CHECK_(-1));
1965 if (name == nullptr) {
1966 THROW_MSG_(vmSymbols::java_lang_NullPointerException(),
1967 "Output file name cannot be null.", -1);
1968 }
1969 HeapDumper dumper(live ? true : false);
1970 if (dumper.dump(name) != 0) {
1971 const char* errmsg = dumper.error_as_C_string();
1972 THROW_MSG_(vmSymbols::java_io_IOException(), errmsg, -1);
1973 }
1974 return 0;
1975 #else // INCLUDE_SERVICES
1976 return -1;
1977 #endif // INCLUDE_SERVICES
1978 JVM_END
1979
1980 JVM_ENTRY(jobjectArray, jmm_GetDiagnosticCommands(JNIEnv *env))
1981 ResourceMark rm(THREAD);
1982 GrowableArray<const char *>* dcmd_list = DCmdFactory::DCmd_list(DCmd_Source_MBean);
1983 objArrayOop cmd_array_oop = oopFactory::new_objArray(vmClasses::String_klass(),
1984 dcmd_list->length(), CHECK_NULL);
1985 objArrayHandle cmd_array(THREAD, cmd_array_oop);
1986 for (int i = 0; i < dcmd_list->length(); i++) {
1987 oop cmd_name = java_lang_String::create_oop_from_str(dcmd_list->at(i), CHECK_NULL);
1988 cmd_array->obj_at_put(i, cmd_name);
1989 }
1990 return (jobjectArray) JNIHandles::make_local(THREAD, cmd_array());
1991 JVM_END
1992
1993 JVM_ENTRY(void, jmm_GetDiagnosticCommandInfo(JNIEnv *env, jobjectArray cmds,
1994 dcmdInfo* infoArray))
1995 if (cmds == nullptr || infoArray == nullptr) {
1996 THROW(vmSymbols::java_lang_NullPointerException());
1997 }
1998
1999 ResourceMark rm(THREAD);
2000
2001 refArrayOop ca = oop_cast<refArrayOop>(JNIHandles::resolve_non_null(cmds));
2002 refArrayHandle cmds_ah(THREAD, ca);
2003
2004 // Make sure we have a String array
2005 Klass* element_klass = RefArrayKlass::cast(cmds_ah->klass())->element_klass();
2006 if (element_klass != vmClasses::String_klass()) {
2007 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
2008 "Array element type is not String class");
2009 }
2010
2011 GrowableArray<DCmdInfo *>* info_list = DCmdFactory::DCmdInfo_list(DCmd_Source_MBean);
2012
2013 int num_cmds = cmds_ah->length();
2014 for (int i = 0; i < num_cmds; i++) {
2015 oop cmd = cmds_ah->obj_at(i);
2016 if (cmd == nullptr) {
2017 THROW_MSG(vmSymbols::java_lang_NullPointerException(),
2018 "Command name cannot be null.");
2019 }
2020 char* cmd_name = java_lang_String::as_utf8_string(cmd);
2021 if (cmd_name == nullptr) {
2022 THROW_MSG(vmSymbols::java_lang_NullPointerException(),
2023 "Command name cannot be null.");
2024 }
2025 int pos = info_list->find_if([&](DCmdInfo* info) {
2026 return info->name_equals(cmd_name);
2027 });
2028 if (pos == -1) {
2029 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
2030 "Unknown diagnostic command");
2031 }
2032 DCmdInfo* info = info_list->at(pos);
2033 infoArray[i].name = info->name();
2034 infoArray[i].description = info->description();
2035 infoArray[i].impact = info->impact();
2036 infoArray[i].num_arguments = info->num_arguments();
2037
2038 // All registered DCmds are always enabled. We set the dcmdInfo::enabled
2039 // field to true to be compatible with the Java API
2040 // com.sun.management.internal.DiagnosticCommandInfo.
2041 infoArray[i].enabled = true;
2042 }
2043 JVM_END
2044
2045 JVM_ENTRY(void, jmm_GetDiagnosticCommandArgumentsInfo(JNIEnv *env,
2046 jstring command, dcmdArgInfo* infoArray, jint count))
2047 ResourceMark rm(THREAD);
2048 oop cmd = JNIHandles::resolve_external_guard(command);
2049 if (cmd == nullptr) {
2050 THROW_MSG(vmSymbols::java_lang_NullPointerException(),
2051 "Command line cannot be null.");
2052 }
2053 char* cmd_name = java_lang_String::as_utf8_string(cmd);
2054 if (cmd_name == nullptr) {
2055 THROW_MSG(vmSymbols::java_lang_NullPointerException(),
2056 "Command line content cannot be null.");
2057 }
2058 DCmd* dcmd = nullptr;
2059 DCmdFactory*factory = DCmdFactory::factory(DCmd_Source_MBean, cmd_name,
2060 strlen(cmd_name));
2061 if (factory != nullptr) {
2062 dcmd = factory->create_resource_instance(nullptr);
2063 }
2064 if (dcmd == nullptr) {
2065 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
2066 "Unknown diagnostic command");
2067 }
2068 DCmdMark mark(dcmd);
2069 GrowableArray<DCmdArgumentInfo*>* array = dcmd->argument_info_array();
2070 const int num_args = array->length();
2071 if (num_args != count) {
2072 assert(false, "jmm_GetDiagnosticCommandArgumentsInfo count mismatch (%d vs %d)", count, num_args);
2073 THROW_MSG(vmSymbols::java_lang_InternalError(), "jmm_GetDiagnosticCommandArgumentsInfo count mismatch");
2074 }
2075 for (int i = 0; i < num_args; i++) {
2076 infoArray[i].name = array->at(i)->name();
2077 infoArray[i].description = array->at(i)->description();
2078 infoArray[i].type = array->at(i)->type();
2079 infoArray[i].default_string = array->at(i)->default_string();
2080 infoArray[i].mandatory = array->at(i)->is_mandatory();
2081 infoArray[i].option = array->at(i)->is_option();
2082 infoArray[i].multiple = array->at(i)->is_multiple();
2083 infoArray[i].position = array->at(i)->position();
2084 }
2085 return;
2086 JVM_END
2087
2088 JVM_ENTRY(jstring, jmm_ExecuteDiagnosticCommand(JNIEnv *env, jstring commandline))
2089 ResourceMark rm(THREAD);
2090 oop cmd = JNIHandles::resolve_external_guard(commandline);
2091 if (cmd == nullptr) {
2092 THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(),
2093 "Command line cannot be null.");
2094 }
2095 char* cmdline = java_lang_String::as_utf8_string(cmd);
2096 if (cmdline == nullptr) {
2097 THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(),
2098 "Command line content cannot be null.");
2099 }
2100 bufferedStream output;
2101 DCmd::parse_and_execute(DCmd_Source_MBean, &output, cmdline, ' ', CHECK_NULL);
2102 oop result = java_lang_String::create_oop_from_str(output.as_string(), CHECK_NULL);
2103 return (jstring) JNIHandles::make_local(THREAD, result);
2104 JVM_END
2105
2106 JVM_ENTRY(void, jmm_SetDiagnosticFrameworkNotificationEnabled(JNIEnv *env, jboolean enabled))
2107 DCmdFactory::set_jmx_notification_enabled(enabled?true:false);
2108 JVM_END
2109
2110 jlong Management::ticks_to_ms(jlong ticks) {
2111 assert(os::elapsed_frequency() > 0, "Must be non-zero");
2112 return (jlong)(((double)ticks / (double)os::elapsed_frequency())
2113 * (double)1000.0);
2114 }
2115
2116 // Gets the amount of memory allocated on the Java heap since JVM launch.
2117 JVM_ENTRY(jlong, jmm_GetTotalThreadAllocatedMemory(JNIEnv *env))
2118 // A thread increments exited_allocated_bytes in ThreadService::remove_thread
2119 // only after it removes itself from the threads list, and once a TLH is
2120 // created, no thread it references can remove itself from the threads
2121 // list, so none can update exited_allocated_bytes. We therefore initialize
2122 // result with exited_allocated_bytes after after we create the TLH so that
2123 // the final result can only be short due to (1) threads that start after
2124 // the TLH is created, or (2) terminating threads that escape TLH creation
2125 // and don't update exited_allocated_bytes before we initialize result.
2126
2127 // We keep a high water mark to ensure monotonicity in case threads counted
2128 // on a previous call end up in state (2).
2129 static jlong high_water_result = 0;
2130
2131 JavaThreadIteratorWithHandle jtiwh;
2132 jlong result = ThreadService::exited_allocated_bytes();
2133 for (; JavaThread* thread = jtiwh.next();) {
2134 jlong size = thread->cooked_allocated_bytes();
2135 result += size;
2136 }
2137
2138 {
2139 assert(MonitoringSupport_lock != nullptr, "Must be");
2140 MutexLocker ml(MonitoringSupport_lock, Mutex::_no_safepoint_check_flag);
2141 if (result < high_water_result) {
2142 // Encountered (2) above, or result wrapped to a negative value. In
2143 // the latter case, it's pegged at the last positive value.
2144 result = high_water_result;
2145 } else {
2146 high_water_result = result;
2147 }
2148 }
2149 return result;
2150 JVM_END
2151
2152 // Gets the amount of memory allocated on the Java heap for a single thread.
2153 // Returns -1 if the thread does not exist or has terminated.
2154 JVM_ENTRY(jlong, jmm_GetOneThreadAllocatedMemory(JNIEnv *env, jlong thread_id))
2155 if (thread_id < 0) {
2156 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
2157 "Invalid thread ID", -1);
2158 }
2159
2160 if (thread_id == 0) { // current thread
2161 return thread->cooked_allocated_bytes();
2162 }
2163
2164 ThreadsListHandle tlh;
2165 JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id);
2166 if (is_platform_thread(java_thread)) {
2167 return java_thread->cooked_allocated_bytes();
2168 }
2169 return -1;
2170 JVM_END
2171
2172 // Gets an array containing the amount of memory allocated on the Java
2173 // heap for a set of threads (in bytes). Each element of the array is
2174 // the amount of memory allocated for the thread ID specified in the
2175 // corresponding entry in the given array of thread IDs; or -1 if the
2176 // thread does not exist or has terminated.
2177 JVM_ENTRY(void, jmm_GetThreadAllocatedMemory(JNIEnv *env, jlongArray ids,
2178 jlongArray sizeArray))
2179 // Check if threads is null
2180 if (ids == nullptr || sizeArray == nullptr) {
2181 THROW(vmSymbols::java_lang_NullPointerException());
2182 }
2183
2184 ResourceMark rm(THREAD);
2185 typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids));
2186 typeArrayHandle ids_ah(THREAD, ta);
2187
2188 typeArrayOop sa = typeArrayOop(JNIHandles::resolve_non_null(sizeArray));
2189 typeArrayHandle sizeArray_h(THREAD, sa);
2190
2191 // validate the thread id array
2192 validate_thread_id_array(ids_ah, CHECK);
2193
2194 // sizeArray must be of the same length as the given array of thread IDs
2195 int num_threads = ids_ah->length();
2196 if (num_threads != sizeArray_h->length()) {
2197 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
2198 "The length of the given long array does not match the length of "
2199 "the given array of thread IDs");
2200 }
2201
2202 ThreadsListHandle tlh;
2203 for (int i = 0; i < num_threads; i++) {
2204 JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(ids_ah->long_at(i));
2205 if (is_platform_thread(java_thread)) {
2206 sizeArray_h->long_at_put(i, java_thread->cooked_allocated_bytes());
2207 }
2208 }
2209 JVM_END
2210
2211 // Returns the CPU time consumed by a given thread (in nanoseconds).
2212 // If thread_id == 0, CPU time for the current thread is returned.
2213 // If user_sys_cpu_time = true, user level and system CPU time of
2214 // a given thread is returned; otherwise, only user level CPU time
2215 // is returned.
2216 JVM_ENTRY(jlong, jmm_GetThreadCpuTimeWithKind(JNIEnv *env, jlong thread_id, jboolean user_sys_cpu_time))
2217 if (!os::is_thread_cpu_time_supported()) {
2218 return -1;
2219 }
2220
2221 if (thread_id < 0) {
2222 THROW_MSG_(vmSymbols::java_lang_IllegalArgumentException(),
2223 "Invalid thread ID", -1);
2224 }
2225
2226 JavaThread* java_thread = nullptr;
2227 if (thread_id == 0) {
2228 // current thread
2229 return os::current_thread_cpu_time(user_sys_cpu_time != 0);
2230 } else {
2231 ThreadsListHandle tlh;
2232 java_thread = tlh.list()->find_JavaThread_from_java_tid(thread_id);
2233 if (is_platform_thread(java_thread)) {
2234 return os::thread_cpu_time((Thread*) java_thread, user_sys_cpu_time != 0);
2235 }
2236 }
2237 return -1;
2238 JVM_END
2239
2240 // Gets an array containing the CPU times consumed by a set of threads
2241 // (in nanoseconds). Each element of the array is the CPU time for the
2242 // thread ID specified in the corresponding entry in the given array
2243 // of thread IDs; or -1 if the thread does not exist or has terminated.
2244 // If user_sys_cpu_time = true, the sum of user level and system CPU time
2245 // for the given thread is returned; otherwise, only user level CPU time
2246 // is returned.
2247 JVM_ENTRY(void, jmm_GetThreadCpuTimesWithKind(JNIEnv *env, jlongArray ids,
2248 jlongArray timeArray,
2249 jboolean user_sys_cpu_time))
2250 // Check if threads is null
2251 if (ids == nullptr || timeArray == nullptr) {
2252 THROW(vmSymbols::java_lang_NullPointerException());
2253 }
2254
2255 ResourceMark rm(THREAD);
2256 typeArrayOop ta = typeArrayOop(JNIHandles::resolve_non_null(ids));
2257 typeArrayHandle ids_ah(THREAD, ta);
2258
2259 typeArrayOop tia = typeArrayOop(JNIHandles::resolve_non_null(timeArray));
2260 typeArrayHandle timeArray_h(THREAD, tia);
2261
2262 // validate the thread id array
2263 validate_thread_id_array(ids_ah, CHECK);
2264
2265 // timeArray must be of the same length as the given array of thread IDs
2266 int num_threads = ids_ah->length();
2267 if (num_threads != timeArray_h->length()) {
2268 THROW_MSG(vmSymbols::java_lang_IllegalArgumentException(),
2269 "The length of the given long array does not match the length of "
2270 "the given array of thread IDs");
2271 }
2272
2273 ThreadsListHandle tlh;
2274 for (int i = 0; i < num_threads; i++) {
2275 JavaThread* java_thread = tlh.list()->find_JavaThread_from_java_tid(ids_ah->long_at(i));
2276 if (is_platform_thread(java_thread)) {
2277 timeArray_h->long_at_put(i, os::thread_cpu_time((Thread*)java_thread,
2278 user_sys_cpu_time != 0));
2279 }
2280 }
2281 JVM_END
2282
2283 const struct jmmInterface_1_ jmm_interface = {
2284 nullptr,
2285 nullptr,
2286 jmm_GetVersion,
2287 jmm_GetOptionalSupport,
2288 jmm_GetThreadInfo,
2289 jmm_GetMemoryPools,
2290 jmm_GetMemoryManagers,
2291 jmm_GetMemoryPoolUsage,
2292 jmm_GetPeakMemoryPoolUsage,
2293 jmm_GetTotalThreadAllocatedMemory,
2294 jmm_GetOneThreadAllocatedMemory,
2295 jmm_GetThreadAllocatedMemory,
2296 jmm_GetMemoryUsage,
2297 jmm_GetLongAttribute,
2298 jmm_GetBoolAttribute,
2299 jmm_SetBoolAttribute,
2300 jmm_GetLongAttributes,
2301 jmm_FindMonitorDeadlockedThreads,
2302 jmm_GetThreadCpuTime,
2303 jmm_GetVMGlobalNames,
2304 jmm_GetVMGlobals,
2305 jmm_GetInternalThreadTimes,
2306 jmm_ResetStatistic,
2307 jmm_SetPoolSensor,
2308 jmm_SetPoolThreshold,
2309 jmm_GetPoolCollectionUsage,
2310 jmm_GetGCExtAttributeInfo,
2311 jmm_GetLastGCStat,
2312 jmm_GetThreadCpuTimeWithKind,
2313 jmm_GetThreadCpuTimesWithKind,
2314 jmm_DumpHeap0,
2315 jmm_FindDeadlockedThreads,
2316 jmm_SetVMGlobal,
2317 nullptr,
2318 jmm_DumpThreads,
2319 jmm_SetGCNotificationEnabled,
2320 jmm_GetDiagnosticCommands,
2321 jmm_GetDiagnosticCommandInfo,
2322 jmm_GetDiagnosticCommandArgumentsInfo,
2323 jmm_ExecuteDiagnosticCommand,
2324 jmm_SetDiagnosticFrameworkNotificationEnabled
2325 };
2326 #endif // INCLUDE_MANAGEMENT
2327
2328 void* Management::get_jmm_interface(int version) {
2329 #if INCLUDE_MANAGEMENT
2330 if (version == JMM_VERSION) {
2331 return (void*) &jmm_interface;
2332 }
2333 #endif // INCLUDE_MANAGEMENT
2334 return nullptr;
2335 }