Wed, 27 Aug 2014 08:19:12 -0400
8046598: Scalable Native memory tracking development
Summary: Enhance scalability of native memory tracking
Reviewed-by: coleenp, ctornqvi, gtriantafill
1 /*
2 * Copyright (c) 2012, 2014, 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 */
25 #include "precompiled.hpp"
27 #include "memory/metadataFactory.hpp"
28 #include "memory/universe.hpp"
29 #include "oops/oop.inline.hpp"
31 #include "classfile/symbolTable.hpp"
32 #include "classfile/classLoaderData.hpp"
34 #include "prims/whitebox.hpp"
35 #include "prims/wbtestmethods/parserTests.hpp"
37 #include "runtime/arguments.hpp"
38 #include "runtime/interfaceSupport.hpp"
39 #include "runtime/os.hpp"
40 #include "utilities/array.hpp"
41 #include "utilities/debug.hpp"
42 #include "utilities/macros.hpp"
43 #include "utilities/exceptions.hpp"
45 #if INCLUDE_ALL_GCS
46 #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp"
47 #include "gc_implementation/g1/concurrentMark.hpp"
48 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
49 #include "gc_implementation/g1/heapRegionRemSet.hpp"
50 #endif // INCLUDE_ALL_GCS
52 #if INCLUDE_NMT
53 #include "services/mallocSiteTable.hpp"
54 #include "services/memTracker.hpp"
55 #include "utilities/nativeCallStack.hpp"
56 #endif // INCLUDE_NMT
58 #include "compiler/compileBroker.hpp"
59 #include "runtime/compilationPolicy.hpp"
61 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
63 #define SIZE_T_MAX_VALUE ((size_t) -1)
65 bool WhiteBox::_used = false;
67 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
68 return (jlong)(void*)JNIHandles::resolve(obj);
69 WB_END
71 WB_ENTRY(jint, WB_GetHeapOopSize(JNIEnv* env, jobject o))
72 return heapOopSize;
73 WB_END
76 class WBIsKlassAliveClosure : public KlassClosure {
77 Symbol* _name;
78 bool _found;
79 public:
80 WBIsKlassAliveClosure(Symbol* name) : _name(name), _found(false) {}
82 void do_klass(Klass* k) {
83 if (_found) return;
84 Symbol* ksym = k->name();
85 if (ksym->fast_compare(_name) == 0) {
86 _found = true;
87 }
88 }
90 bool found() const {
91 return _found;
92 }
93 };
95 WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name))
96 Handle h_name = JNIHandles::resolve(name);
97 if (h_name.is_null()) return false;
98 Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_false);
99 TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return
101 WBIsKlassAliveClosure closure(sym);
102 ClassLoaderDataGraph::classes_do(&closure);
104 return closure.found();
105 WB_END
107 WB_ENTRY(jlong, WB_GetCompressedOopsMaxHeapSize(JNIEnv* env, jobject o)) {
108 return (jlong)Arguments::max_heap_for_compressed_oops();
109 }
110 WB_END
112 WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) {
113 CollectorPolicy * p = Universe::heap()->collector_policy();
114 gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap "
115 SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Min alignment "SIZE_FORMAT" Max alignment "SIZE_FORMAT,
116 p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(),
117 p->space_alignment(), p->heap_alignment());
118 }
119 WB_END
121 #ifndef PRODUCT
122 // Forward declaration
123 void TestReservedSpace_test();
124 void TestReserveMemorySpecial_test();
125 void TestVirtualSpace_test();
126 void TestMetaspaceAux_test();
127 #endif
129 WB_ENTRY(void, WB_RunMemoryUnitTests(JNIEnv* env, jobject o))
130 #ifndef PRODUCT
131 TestReservedSpace_test();
132 TestReserveMemorySpecial_test();
133 TestVirtualSpace_test();
134 TestMetaspaceAux_test();
135 #endif
136 WB_END
138 WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o))
139 size_t granularity = os::vm_allocation_granularity();
140 ReservedHeapSpace rhs(100 * granularity, granularity, false, NULL);
141 VirtualSpace vs;
142 vs.initialize(rhs, 50 * granularity);
144 //Check if constraints are complied
145 if (!( UseCompressedOops && rhs.base() != NULL &&
146 Universe::narrow_oop_base() != NULL &&
147 Universe::narrow_oop_use_implicit_null_checks() )) {
148 tty->print_cr("WB_ReadFromNoaccessArea method is useless:\n "
149 "\tUseCompressedOops is %d\n"
150 "\trhs.base() is "PTR_FORMAT"\n"
151 "\tUniverse::narrow_oop_base() is "PTR_FORMAT"\n"
152 "\tUniverse::narrow_oop_use_implicit_null_checks() is %d",
153 UseCompressedOops,
154 rhs.base(),
155 Universe::narrow_oop_base(),
156 Universe::narrow_oop_use_implicit_null_checks());
157 return;
158 }
159 tty->print_cr("Reading from no access area... ");
160 tty->print_cr("*(vs.low_boundary() - rhs.noaccess_prefix() / 2 ) = %c",
161 *(vs.low_boundary() - rhs.noaccess_prefix() / 2 ));
162 WB_END
164 static jint wb_stress_virtual_space_resize(size_t reserved_space_size,
165 size_t magnitude, size_t iterations) {
166 size_t granularity = os::vm_allocation_granularity();
167 ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false, NULL);
168 VirtualSpace vs;
169 if (!vs.initialize(rhs, 0)) {
170 tty->print_cr("Failed to initialize VirtualSpace. Can't proceed.");
171 return 3;
172 }
174 long seed = os::random();
175 tty->print_cr("Random seed is %ld", seed);
176 os::init_random(seed);
178 for (size_t i = 0; i < iterations; i++) {
180 // Whether we will shrink or grow
181 bool shrink = os::random() % 2L == 0;
183 // Get random delta to resize virtual space
184 size_t delta = (size_t)os::random() % magnitude;
186 // If we are about to shrink virtual space below zero, then expand instead
187 if (shrink && vs.committed_size() < delta) {
188 shrink = false;
189 }
191 // Resizing by delta
192 if (shrink) {
193 vs.shrink_by(delta);
194 } else {
195 // If expanding fails expand_by will silently return false
196 vs.expand_by(delta, true);
197 }
198 }
199 return 0;
200 }
202 WB_ENTRY(jint, WB_StressVirtualSpaceResize(JNIEnv* env, jobject o,
203 jlong reserved_space_size, jlong magnitude, jlong iterations))
204 tty->print_cr("reservedSpaceSize="JLONG_FORMAT", magnitude="JLONG_FORMAT", "
205 "iterations="JLONG_FORMAT"\n", reserved_space_size, magnitude,
206 iterations);
207 if (reserved_space_size < 0 || magnitude < 0 || iterations < 0) {
208 tty->print_cr("One of variables printed above is negative. Can't proceed.\n");
209 return 1;
210 }
212 // sizeof(size_t) depends on whether OS is 32bit or 64bit. sizeof(jlong) is
213 // always 8 byte. That's why we should avoid overflow in case of 32bit platform.
214 if (sizeof(size_t) < sizeof(jlong)) {
215 jlong size_t_max_value = (jlong) SIZE_T_MAX_VALUE;
216 if (reserved_space_size > size_t_max_value || magnitude > size_t_max_value
217 || iterations > size_t_max_value) {
218 tty->print_cr("One of variables printed above overflows size_t. Can't proceed.\n");
219 return 2;
220 }
221 }
223 return wb_stress_virtual_space_resize((size_t) reserved_space_size,
224 (size_t) magnitude, (size_t) iterations);
225 WB_END
227 WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj))
228 oop p = JNIHandles::resolve(obj);
229 #if INCLUDE_ALL_GCS
230 if (UseG1GC) {
231 G1CollectedHeap* g1 = G1CollectedHeap::heap();
232 const HeapRegion* hr = g1->heap_region_containing(p);
233 if (hr == NULL) {
234 return false;
235 }
236 return !(hr->is_young());
237 } else if (UseParallelGC) {
238 ParallelScavengeHeap* psh = ParallelScavengeHeap::heap();
239 return !psh->is_in_young(p);
240 }
241 #endif // INCLUDE_ALL_GCS
242 GenCollectedHeap* gch = GenCollectedHeap::heap();
243 return !gch->is_in_young(p);
244 WB_END
246 WB_ENTRY(jlong, WB_GetObjectSize(JNIEnv* env, jobject o, jobject obj))
247 oop p = JNIHandles::resolve(obj);
248 return p->size() * HeapWordSize;
249 WB_END
251 #if INCLUDE_ALL_GCS
252 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
253 G1CollectedHeap* g1 = G1CollectedHeap::heap();
254 oop result = JNIHandles::resolve(obj);
255 const HeapRegion* hr = g1->heap_region_containing(result);
256 return hr->isHumongous();
257 WB_END
259 WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o))
260 G1CollectedHeap* g1 = G1CollectedHeap::heap();
261 size_t nr = g1->num_free_regions();
262 return (jlong)nr;
263 WB_END
265 WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o))
266 G1CollectedHeap* g1 = G1CollectedHeap::heap();
267 ConcurrentMark* cm = g1->concurrent_mark();
268 return cm->concurrent_marking_in_progress();
269 WB_END
271 WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
272 return (jint)HeapRegion::GrainBytes;
273 WB_END
274 #endif // INCLUDE_ALL_GCS
276 #if INCLUDE_NMT
277 // Alloc memory using the test memory type so that we can use that to see if
278 // NMT picks it up correctly
279 WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size))
280 jlong addr = 0;
281 addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
282 return addr;
283 WB_END
285 // Alloc memory with pseudo call stack. The test can create psudo malloc
286 // allocation site to stress the malloc tracking.
287 WB_ENTRY(jlong, WB_NMTMallocWithPseudoStack(JNIEnv* env, jobject o, jlong size, jint pseudo_stack))
288 address pc = (address)(size_t)pseudo_stack;
289 NativeCallStack stack(&pc, 1);
290 return (jlong)os::malloc(size, mtTest, stack);
291 WB_END
293 // Free the memory allocated by NMTAllocTest
294 WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem))
295 os::free((void*)(uintptr_t)mem, mtTest);
296 WB_END
298 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
299 jlong addr = 0;
301 addr = (jlong)(uintptr_t)os::reserve_memory(size);
302 MemTracker::record_virtual_memory_type((address)addr, mtTest);
304 return addr;
305 WB_END
308 WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
309 os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem);
310 MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
311 WB_END
313 WB_ENTRY(void, WB_NMTUncommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
314 os::uncommit_memory((char *)(uintptr_t)addr, size);
315 WB_END
317 WB_ENTRY(void, WB_NMTReleaseMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
318 os::release_memory((char *)(uintptr_t)addr, size);
319 WB_END
321 WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env))
322 return MemTracker::tracking_level() == NMT_detail;
323 WB_END
325 WB_ENTRY(void, WB_NMTOverflowHashBucket(JNIEnv* env, jobject o, jlong num))
326 address pc = (address)1;
327 for (jlong index = 0; index < num; index ++) {
328 NativeCallStack stack(&pc, 1);
329 os::malloc(0, mtTest, stack);
330 pc += MallocSiteTable::hash_buckets();
331 }
332 WB_END
335 #endif // INCLUDE_NMT
337 static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) {
338 assert(method != NULL, "method should not be null");
339 ThreadToNativeFromVM ttn(thread);
340 return env->FromReflectedMethod(method);
341 }
343 WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o))
344 MutexLockerEx mu(Compile_lock);
345 CodeCache::mark_all_nmethods_for_deoptimization();
346 VM_Deoptimize op;
347 VMThread::execute(&op);
348 WB_END
350 WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
351 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
352 int result = 0;
353 CHECK_JNI_EXCEPTION_(env, result);
354 MutexLockerEx mu(Compile_lock);
355 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
356 nmethod* code;
357 if (is_osr) {
358 int bci = InvocationEntryBci;
359 while ((code = mh->lookup_osr_nmethod_for(bci, CompLevel_none, false)) != NULL) {
360 code->mark_for_deoptimization();
361 ++result;
362 bci = code->osr_entry_bci() + 1;
363 }
364 } else {
365 code = mh->code();
366 }
367 if (code != NULL) {
368 code->mark_for_deoptimization();
369 ++result;
370 }
371 result += CodeCache::mark_for_deoptimization(mh());
372 if (result > 0) {
373 VM_Deoptimize op;
374 VMThread::execute(&op);
375 }
376 return result;
377 WB_END
379 WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
380 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
381 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
382 MutexLockerEx mu(Compile_lock);
383 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
384 nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
385 if (code == NULL) {
386 return JNI_FALSE;
387 }
388 return (code->is_alive() && !code->is_marked_for_deoptimization());
389 WB_END
391 WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr))
392 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
393 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
394 MutexLockerEx mu(Compile_lock);
395 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
396 if (is_osr) {
397 return CompilationPolicy::can_be_osr_compiled(mh, comp_level);
398 } else {
399 return CompilationPolicy::can_be_compiled(mh, comp_level);
400 }
401 WB_END
403 WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method))
404 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
405 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
406 MutexLockerEx mu(Compile_lock);
407 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
408 return mh->queued_for_compilation();
409 WB_END
411 WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
412 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
413 CHECK_JNI_EXCEPTION_(env, CompLevel_none);
414 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
415 nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
416 return (code != NULL ? code->comp_level() : CompLevel_none);
417 WB_END
419 WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr))
420 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
421 CHECK_JNI_EXCEPTION(env);
422 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
423 if (is_osr) {
424 mh->set_not_osr_compilable(comp_level, true /* report */, "WhiteBox");
425 } else {
426 mh->set_not_compilable(comp_level, true /* report */, "WhiteBox");
427 }
428 WB_END
430 WB_ENTRY(jint, WB_GetMethodEntryBci(JNIEnv* env, jobject o, jobject method))
431 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
432 CHECK_JNI_EXCEPTION_(env, InvocationEntryBci);
433 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
434 nmethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false);
435 return (code != NULL && code->is_osr_method() ? code->osr_entry_bci() : InvocationEntryBci);
436 WB_END
438 WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
439 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
440 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
441 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
442 bool result = mh->dont_inline();
443 mh->set_dont_inline(value == JNI_TRUE);
444 return result;
445 WB_END
447 WB_ENTRY(jint, WB_GetCompileQueueSize(JNIEnv* env, jobject o, jint comp_level))
448 if (comp_level == CompLevel_any) {
449 return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ +
450 CompileBroker::queue_size(CompLevel_full_profile) /* C1 */;
451 } else {
452 return CompileBroker::queue_size(comp_level);
453 }
454 WB_END
456 WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
457 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
458 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
459 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
460 bool result = mh->force_inline();
461 mh->set_force_inline(value == JNI_TRUE);
462 return result;
463 WB_END
465 WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level, jint bci))
466 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
467 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
468 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
469 nmethod* nm = CompileBroker::compile_method(mh, bci, comp_level, mh, mh->invocation_count(), "WhiteBox", THREAD);
470 MutexLockerEx mu(Compile_lock);
471 return (mh->queued_for_compilation() || nm != NULL);
472 WB_END
474 class VM_WhiteBoxOperation : public VM_Operation {
475 public:
476 VM_WhiteBoxOperation() { }
477 VMOp_Type type() const { return VMOp_WhiteBoxOperation; }
478 bool allow_nested_vm_operations() const { return true; }
479 };
481 class AlwaysFalseClosure : public BoolObjectClosure {
482 public:
483 bool do_object_b(oop p) { return false; }
484 };
486 static AlwaysFalseClosure always_false;
488 class VM_WhiteBoxCleanMethodData : public VM_WhiteBoxOperation {
489 public:
490 VM_WhiteBoxCleanMethodData(MethodData* mdo) : _mdo(mdo) { }
491 void doit() {
492 _mdo->clean_method_data(&always_false);
493 }
494 private:
495 MethodData* _mdo;
496 };
498 WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
499 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
500 CHECK_JNI_EXCEPTION(env);
501 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
502 MutexLockerEx mu(Compile_lock);
503 MethodData* mdo = mh->method_data();
504 MethodCounters* mcs = mh->method_counters();
506 if (mdo != NULL) {
507 mdo->init();
508 ResourceMark rm;
509 int arg_count = mdo->method()->size_of_parameters();
510 for (int i = 0; i < arg_count; i++) {
511 mdo->set_arg_modified(i, 0);
512 }
513 VM_WhiteBoxCleanMethodData op(mdo);
514 VMThread::execute(&op);
515 }
517 mh->clear_not_c1_compilable();
518 mh->clear_not_c2_compilable();
519 mh->clear_not_c2_osr_compilable();
520 NOT_PRODUCT(mh->set_compiled_invocation_count(0));
521 if (mcs != NULL) {
522 mcs->backedge_counter()->init();
523 mcs->invocation_counter()->init();
524 mcs->set_interpreter_invocation_count(0);
525 mcs->set_interpreter_throwout_count(0);
527 #ifdef TIERED
528 mcs->set_rate(0.0F);
529 mh->set_prev_event_count(0, THREAD);
530 mh->set_prev_time(0, THREAD);
531 #endif
532 }
533 WB_END
535 template <typename T>
536 static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, bool (*TAt)(const char*, T*)) {
537 if (name == NULL) {
538 return false;
539 }
540 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
541 const char* flag_name = env->GetStringUTFChars(name, NULL);
542 bool result = (*TAt)(flag_name, value);
543 env->ReleaseStringUTFChars(name, flag_name);
544 return result;
545 }
547 template <typename T>
548 static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, bool (*TAtPut)(const char*, T*, Flag::Flags)) {
549 if (name == NULL) {
550 return false;
551 }
552 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
553 const char* flag_name = env->GetStringUTFChars(name, NULL);
554 bool result = (*TAtPut)(flag_name, value, Flag::INTERNAL);
555 env->ReleaseStringUTFChars(name, flag_name);
556 return result;
557 }
559 template <typename T>
560 static jobject box(JavaThread* thread, JNIEnv* env, Symbol* name, Symbol* sig, T value) {
561 ResourceMark rm(thread);
562 jclass clazz = env->FindClass(name->as_C_string());
563 CHECK_JNI_EXCEPTION_(env, NULL);
564 jmethodID methodID = env->GetStaticMethodID(clazz,
565 vmSymbols::valueOf_name()->as_C_string(),
566 sig->as_C_string());
567 CHECK_JNI_EXCEPTION_(env, NULL);
568 jobject result = env->CallStaticObjectMethod(clazz, methodID, value);
569 CHECK_JNI_EXCEPTION_(env, NULL);
570 return result;
571 }
573 static jobject booleanBox(JavaThread* thread, JNIEnv* env, jboolean value) {
574 return box(thread, env, vmSymbols::java_lang_Boolean(), vmSymbols::Boolean_valueOf_signature(), value);
575 }
576 static jobject integerBox(JavaThread* thread, JNIEnv* env, jint value) {
577 return box(thread, env, vmSymbols::java_lang_Integer(), vmSymbols::Integer_valueOf_signature(), value);
578 }
579 static jobject longBox(JavaThread* thread, JNIEnv* env, jlong value) {
580 return box(thread, env, vmSymbols::java_lang_Long(), vmSymbols::Long_valueOf_signature(), value);
581 }
582 /* static jobject floatBox(JavaThread* thread, JNIEnv* env, jfloat value) {
583 return box(thread, env, vmSymbols::java_lang_Float(), vmSymbols::Float_valueOf_signature(), value);
584 }*/
585 static jobject doubleBox(JavaThread* thread, JNIEnv* env, jdouble value) {
586 return box(thread, env, vmSymbols::java_lang_Double(), vmSymbols::Double_valueOf_signature(), value);
587 }
589 WB_ENTRY(jobject, WB_GetBooleanVMFlag(JNIEnv* env, jobject o, jstring name))
590 bool result;
591 if (GetVMFlag <bool> (thread, env, name, &result, &CommandLineFlags::boolAt)) {
592 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
593 return booleanBox(thread, env, result);
594 }
595 return NULL;
596 WB_END
598 WB_ENTRY(jobject, WB_GetIntxVMFlag(JNIEnv* env, jobject o, jstring name))
599 intx result;
600 if (GetVMFlag <intx> (thread, env, name, &result, &CommandLineFlags::intxAt)) {
601 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
602 return longBox(thread, env, result);
603 }
604 return NULL;
605 WB_END
607 WB_ENTRY(jobject, WB_GetUintxVMFlag(JNIEnv* env, jobject o, jstring name))
608 uintx result;
609 if (GetVMFlag <uintx> (thread, env, name, &result, &CommandLineFlags::uintxAt)) {
610 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
611 return longBox(thread, env, result);
612 }
613 return NULL;
614 WB_END
616 WB_ENTRY(jobject, WB_GetUint64VMFlag(JNIEnv* env, jobject o, jstring name))
617 uint64_t result;
618 if (GetVMFlag <uint64_t> (thread, env, name, &result, &CommandLineFlags::uint64_tAt)) {
619 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
620 return longBox(thread, env, result);
621 }
622 return NULL;
623 WB_END
625 WB_ENTRY(jobject, WB_GetDoubleVMFlag(JNIEnv* env, jobject o, jstring name))
626 double result;
627 if (GetVMFlag <double> (thread, env, name, &result, &CommandLineFlags::doubleAt)) {
628 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
629 return doubleBox(thread, env, result);
630 }
631 return NULL;
632 WB_END
634 WB_ENTRY(jstring, WB_GetStringVMFlag(JNIEnv* env, jobject o, jstring name))
635 ccstr ccstrResult;
636 if (GetVMFlag <ccstr> (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAt)) {
637 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
638 jstring result = env->NewStringUTF(ccstrResult);
639 CHECK_JNI_EXCEPTION_(env, NULL);
640 return result;
641 }
642 return NULL;
643 WB_END
645 WB_ENTRY(void, WB_SetBooleanVMFlag(JNIEnv* env, jobject o, jstring name, jboolean value))
646 bool result = value == JNI_TRUE ? true : false;
647 SetVMFlag <bool> (thread, env, name, &result, &CommandLineFlags::boolAtPut);
648 WB_END
650 WB_ENTRY(void, WB_SetIntxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value))
651 intx result = value;
652 SetVMFlag <intx> (thread, env, name, &result, &CommandLineFlags::intxAtPut);
653 WB_END
655 WB_ENTRY(void, WB_SetUintxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value))
656 uintx result = value;
657 SetVMFlag <uintx> (thread, env, name, &result, &CommandLineFlags::uintxAtPut);
658 WB_END
660 WB_ENTRY(void, WB_SetUint64VMFlag(JNIEnv* env, jobject o, jstring name, jlong value))
661 uint64_t result = value;
662 SetVMFlag <uint64_t> (thread, env, name, &result, &CommandLineFlags::uint64_tAtPut);
663 WB_END
665 WB_ENTRY(void, WB_SetDoubleVMFlag(JNIEnv* env, jobject o, jstring name, jdouble value))
666 double result = value;
667 SetVMFlag <double> (thread, env, name, &result, &CommandLineFlags::doubleAtPut);
668 WB_END
670 WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring value))
671 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
672 const char* ccstrValue = (value == NULL) ? NULL : env->GetStringUTFChars(value, NULL);
673 ccstr ccstrResult = ccstrValue;
674 bool needFree;
675 {
676 ThreadInVMfromNative ttvfn(thread); // back to VM
677 needFree = SetVMFlag <ccstr> (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAtPut);
678 }
679 if (value != NULL) {
680 env->ReleaseStringUTFChars(value, ccstrValue);
681 }
682 if (needFree) {
683 FREE_C_HEAP_ARRAY(char, ccstrResult, mtInternal);
684 }
685 WB_END
688 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
689 ResourceMark rm(THREAD);
690 int len;
691 jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len, CHECK_false);
692 return (StringTable::lookup(name, len) != NULL);
693 WB_END
695 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
696 Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true);
697 Universe::heap()->collect(GCCause::_last_ditch_collection);
698 WB_END
700 WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o))
701 Universe::heap()->collect(GCCause::_wb_young_gc);
702 WB_END
704 WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o))
705 // static+volatile in order to force the read to happen
706 // (not be eliminated by the compiler)
707 static char c;
708 static volatile char* p;
710 p = os::reserve_memory(os::vm_allocation_granularity(), NULL, 0);
711 if (p == NULL) {
712 THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Failed to reserve memory");
713 }
715 c = *p;
716 WB_END
718 WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o))
719 const char* cpu_features = VM_Version::cpu_features();
720 ThreadToNativeFromVM ttn(thread);
721 jstring features_string = env->NewStringUTF(cpu_features);
723 CHECK_JNI_EXCEPTION_(env, NULL);
725 return features_string;
726 WB_END
729 WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
730 ResourceMark rm(THREAD);
731 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
732 CHECK_JNI_EXCEPTION_(env, NULL);
733 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
734 nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
735 jobjectArray result = NULL;
736 if (code == NULL) {
737 return result;
738 }
739 int insts_size = code->insts_size();
741 ThreadToNativeFromVM ttn(thread);
742 jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
743 CHECK_JNI_EXCEPTION_(env, NULL);
744 result = env->NewObjectArray(2, clazz, NULL);
745 if (result == NULL) {
746 return result;
747 }
749 jobject obj = integerBox(thread, env, code->comp_level());
750 CHECK_JNI_EXCEPTION_(env, NULL);
751 env->SetObjectArrayElement(result, 0, obj);
753 jbyteArray insts = env->NewByteArray(insts_size);
754 CHECK_JNI_EXCEPTION_(env, NULL);
755 env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin());
756 env->SetObjectArrayElement(result, 1, insts);
758 return result;
759 WB_END
762 int WhiteBox::array_bytes_to_length(size_t bytes) {
763 return Array<u1>::bytes_to_length(bytes);
764 }
766 WB_ENTRY(jlong, WB_AllocateMetaspace(JNIEnv* env, jobject wb, jobject class_loader, jlong size))
767 if (size < 0) {
768 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
769 err_msg("WB_AllocateMetaspace: size is negative: " JLONG_FORMAT, size));
770 }
772 oop class_loader_oop = JNIHandles::resolve(class_loader);
773 ClassLoaderData* cld = class_loader_oop != NULL
774 ? java_lang_ClassLoader::loader_data(class_loader_oop)
775 : ClassLoaderData::the_null_class_loader_data();
777 void* metadata = MetadataFactory::new_writeable_array<u1>(cld, WhiteBox::array_bytes_to_length((size_t)size), thread);
779 return (jlong)(uintptr_t)metadata;
780 WB_END
782 WB_ENTRY(void, WB_FreeMetaspace(JNIEnv* env, jobject wb, jobject class_loader, jlong addr, jlong size))
783 oop class_loader_oop = JNIHandles::resolve(class_loader);
784 ClassLoaderData* cld = class_loader_oop != NULL
785 ? java_lang_ClassLoader::loader_data(class_loader_oop)
786 : ClassLoaderData::the_null_class_loader_data();
788 MetadataFactory::free_array(cld, (Array<u1>*)(uintptr_t)addr);
789 WB_END
791 //Some convenience methods to deal with objects from java
792 int WhiteBox::offset_for_field(const char* field_name, oop object,
793 Symbol* signature_symbol) {
794 assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
795 Thread* THREAD = Thread::current();
797 //Get the class of our object
798 Klass* arg_klass = object->klass();
799 //Turn it into an instance-klass
800 InstanceKlass* ik = InstanceKlass::cast(arg_klass);
802 //Create symbols to look for in the class
803 TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
804 THREAD);
806 //To be filled in with an offset of the field we're looking for
807 fieldDescriptor fd;
809 Klass* res = ik->find_field(name_symbol, signature_symbol, &fd);
810 if (res == NULL) {
811 tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
812 name_symbol->as_C_string());
813 fatal("Invalid layout of preloaded class");
814 }
816 //fetch the field at the offset we've found
817 int dest_offset = fd.offset();
819 return dest_offset;
820 }
823 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) {
824 int offset = offset_for_field(field_name, object,
825 vmSymbols::string_signature());
826 oop string = object->obj_field(offset);
827 if (string == NULL) {
828 return NULL;
829 }
830 const char* ret = java_lang_String::as_utf8_string(string);
831 return ret;
832 }
834 bool WhiteBox::lookup_bool(const char* field_name, oop object) {
835 int offset =
836 offset_for_field(field_name, object, vmSymbols::bool_signature());
837 bool ret = (object->bool_field(offset) == JNI_TRUE);
838 return ret;
839 }
842 #define CC (char*)
844 static JNINativeMethod methods[] = {
845 {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress },
846 {CC"getObjectSize", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize },
847 {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen },
848 {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize },
849 {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
850 {CC"parseCommandLine",
851 CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
852 (void*) &WB_ParseCommandLine
853 },
854 {CC"getCompressedOopsMaxHeapSize", CC"()J",
855 (void*)&WB_GetCompressedOopsMaxHeapSize},
856 {CC"printHeapSizes", CC"()V", (void*)&WB_PrintHeapSizes },
857 {CC"runMemoryUnitTests", CC"()V", (void*)&WB_RunMemoryUnitTests},
858 {CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea},
859 {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize},
860 #if INCLUDE_ALL_GCS
861 {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark},
862 {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous },
863 {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions },
864 {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize },
865 #endif // INCLUDE_ALL_GCS
866 #if INCLUDE_NMT
867 {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
868 {CC"NMTMallocWithPseudoStack", CC"(JI)J", (void*)&WB_NMTMallocWithPseudoStack},
869 {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree },
870 {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory },
871 {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory },
872 {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory },
873 {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory },
874 {CC"NMTOverflowHashBucket", CC"(J)V", (void*)&WB_NMTOverflowHashBucket},
875 {CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported},
876 #endif // INCLUDE_NMT
877 {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll },
878 {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I",
879 (void*)&WB_DeoptimizeMethod },
880 {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;Z)Z",
881 (void*)&WB_IsMethodCompiled },
882 {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;IZ)Z",
883 (void*)&WB_IsMethodCompilable},
884 {CC"isMethodQueuedForCompilation",
885 CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation},
886 {CC"makeMethodNotCompilable",
887 CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable},
888 {CC"testSetDontInlineMethod",
889 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod},
890 {CC"getMethodCompilationLevel",
891 CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_GetMethodCompilationLevel},
892 {CC"getMethodEntryBci",
893 CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodEntryBci},
894 {CC"getCompileQueueSize",
895 CC"(I)I", (void*)&WB_GetCompileQueueSize},
896 {CC"testSetForceInlineMethod",
897 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod},
898 {CC"enqueueMethodForCompilation",
899 CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation},
900 {CC"clearMethodState",
901 CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
902 {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag},
903 {CC"setIntxVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetIntxVMFlag},
904 {CC"setUintxVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetUintxVMFlag},
905 {CC"setUint64VMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetUint64VMFlag},
906 {CC"setDoubleVMFlag", CC"(Ljava/lang/String;D)V",(void*)&WB_SetDoubleVMFlag},
907 {CC"setStringVMFlag", CC"(Ljava/lang/String;Ljava/lang/String;)V",
908 (void*)&WB_SetStringVMFlag},
909 {CC"getBooleanVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Boolean;",
910 (void*)&WB_GetBooleanVMFlag},
911 {CC"getIntxVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;",
912 (void*)&WB_GetIntxVMFlag},
913 {CC"getUintxVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;",
914 (void*)&WB_GetUintxVMFlag},
915 {CC"getUint64VMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;",
916 (void*)&WB_GetUint64VMFlag},
917 {CC"getDoubleVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Double;",
918 (void*)&WB_GetDoubleVMFlag},
919 {CC"getStringVMFlag", CC"(Ljava/lang/String;)Ljava/lang/String;",
920 (void*)&WB_GetStringVMFlag},
921 {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable },
922 {CC"fullGC", CC"()V", (void*)&WB_FullGC },
923 {CC"youngGC", CC"()V", (void*)&WB_YoungGC },
924 {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory },
925 {CC"allocateMetaspace",
926 CC"(Ljava/lang/ClassLoader;J)J", (void*)&WB_AllocateMetaspace },
927 {CC"freeMetaspace",
928 CC"(Ljava/lang/ClassLoader;JJ)V", (void*)&WB_FreeMetaspace },
929 {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures },
930 {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;",
931 (void*)&WB_GetNMethod },
932 };
934 #undef CC
936 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
937 {
938 if (WhiteBoxAPI) {
939 // Make sure that wbclass is loaded by the null classloader
940 instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
941 Handle loader(ikh->class_loader());
942 if (loader.is_null()) {
943 ResourceMark rm;
944 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
945 bool result = true;
946 // one by one registration natives for exception catching
947 jclass exceptionKlass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string());
948 CHECK_JNI_EXCEPTION(env);
949 for (int i = 0, n = sizeof(methods) / sizeof(methods[0]); i < n; ++i) {
950 if (env->RegisterNatives(wbclass, methods + i, 1) != 0) {
951 result = false;
952 jthrowable throwable_obj = env->ExceptionOccurred();
953 if (throwable_obj != NULL) {
954 env->ExceptionClear();
955 if (env->IsInstanceOf(throwable_obj, exceptionKlass)) {
956 // j.l.NoSuchMethodError is thrown when a method can't be found or a method is not native
957 // ignoring the exception
958 tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s", methods[i].name, methods[i].signature);
959 }
960 } else {
961 // register is failed w/o exception or w/ unexpected exception
962 tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered", methods[i].name, methods[i].signature);
963 env->UnregisterNatives(wbclass);
964 break;
965 }
966 }
967 }
969 if (result) {
970 WhiteBox::set_used();
971 }
972 }
973 }
974 }
975 JVM_END