1 /*
2 * Copyright (c) 2012, 2019, 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 "precompiled.hpp"
26
27 #include "memory/metadataFactory.hpp"
28 #include "memory/metaspaceShared.hpp"
29 #include "memory/iterator.hpp"
30 #include "memory/universe.hpp"
31 #include "oops/oop.inline.hpp"
32
33 #include "classfile/symbolTable.hpp"
34 #include "classfile/classLoaderData.hpp"
35
36 #include "prims/whitebox.hpp"
37 #include "prims/wbtestmethods/parserTests.hpp"
38
39 #include "runtime/arguments.hpp"
40 #include "runtime/interfaceSupport.hpp"
41 #include "runtime/os.hpp"
42 #include "utilities/array.hpp"
43 #include "utilities/align.hpp"
44 #include "utilities/debug.hpp"
45 #include "utilities/macros.hpp"
46 #include "utilities/exceptions.hpp"
47
48 #if INCLUDE_ALL_GCS
49 #include "gc_implementation/parallelScavenge/parallelScavengeHeap.inline.hpp"
50 #include "gc_implementation/g1/concurrentMark.hpp"
51 #include "gc_implementation/g1/concurrentMarkThread.hpp"
52 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp"
53 #include "gc_implementation/g1/heapRegionRemSet.hpp"
54 #endif // INCLUDE_ALL_GCS
55
56 #if INCLUDE_NMT
57 #include "services/mallocSiteTable.hpp"
58 #include "services/memTracker.hpp"
59 #include "utilities/nativeCallStack.hpp"
60 #endif // INCLUDE_NMT
61
62 #include "compiler/compileBroker.hpp"
63 #include "jvmtifiles/jvmtiEnv.hpp"
64 #include "runtime/compilationPolicy.hpp"
65
66 PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
67
68 #define SIZE_T_MAX_VALUE ((size_t) -1)
69
70 bool WhiteBox::_used = false;
71
72 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
73 return (jlong)(void*)JNIHandles::resolve(obj);
74 WB_END
75
76 WB_ENTRY(jint, WB_GetHeapOopSize(JNIEnv* env, jobject o))
77 return heapOopSize;
78 WB_END
79
80 WB_ENTRY(jint, WB_GetVMPageSize(JNIEnv* env, jobject o))
81 return os::vm_page_size();
82 WB_END
83
84 WB_ENTRY(jlong, WB_GetVMLargePageSize(JNIEnv* env, jobject o))
85 return os::large_page_size();
86 WB_END
87
88 class WBIsKlassAliveClosure : public KlassClosure {
89 Symbol* _name;
90 bool _found;
91 public:
WBIsKlassAliveClosure(Symbol * name)92 WBIsKlassAliveClosure(Symbol* name) : _name(name), _found(false) {}
93
do_klass(Klass * k)94 void do_klass(Klass* k) {
95 if (_found) return;
96 Symbol* ksym = k->name();
97 if (ksym->fast_compare(_name) == 0) {
98 _found = true;
99 }
100 }
101
found() const102 bool found() const {
103 return _found;
104 }
105 };
106
107 WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name))
108 Handle h_name = JNIHandles::resolve(name);
109 if (h_name.is_null()) return false;
110 Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_false);
111 TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return
112
113 WBIsKlassAliveClosure closure(sym);
114 ClassLoaderDataGraph::classes_do(&closure);
115
116 return closure.found();
117 WB_END
118
119 WB_ENTRY(jboolean, WB_ClassKnownToNotExist(JNIEnv* env, jobject o, jobject loader, jstring name))
120 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
121 const char* class_name = env->GetStringUTFChars(name, NULL);
122 jboolean result = JVM_KnownToNotExist(env, loader, class_name);
123 env->ReleaseStringUTFChars(name, class_name);
124 return result;
125 WB_END
126
127 WB_ENTRY(jobjectArray, WB_GetLookupCacheURLs(JNIEnv* env, jobject o, jobject loader))
128 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
129 return JVM_GetResourceLookupCacheURLs(env, loader);
130 WB_END
131
132 WB_ENTRY(jintArray, WB_GetLookupCacheMatches(JNIEnv* env, jobject o, jobject loader, jstring name))
133 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
134 const char* resource_name = env->GetStringUTFChars(name, NULL);
135 jintArray result = JVM_GetResourceLookupCache(env, loader, resource_name);
136
137 env->ReleaseStringUTFChars(name, resource_name);
138 return result;
139 WB_END
140
WB_ENTRY(void,WB_AddToBootstrapClassLoaderSearch (JNIEnv * env,jobject o,jstring segment))141 WB_ENTRY(void, WB_AddToBootstrapClassLoaderSearch(JNIEnv* env, jobject o, jstring segment)) {
142 #if INCLUDE_JVMTI
143 ResourceMark rm;
144 const char* seg = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(segment));
145 JvmtiEnv* jvmti_env = JvmtiEnv::create_a_jvmti(JVMTI_VERSION);
146 jvmtiError err = jvmti_env->AddToBootstrapClassLoaderSearch(seg);
147 assert(err == JVMTI_ERROR_NONE, "must not fail");
148 #endif
149 }
150 WB_END
151
WB_ENTRY(void,WB_AddToSystemClassLoaderSearch (JNIEnv * env,jobject o,jstring segment))152 WB_ENTRY(void, WB_AddToSystemClassLoaderSearch(JNIEnv* env, jobject o, jstring segment)) {
153 #if INCLUDE_JVMTI
154 ResourceMark rm;
155 const char* seg = java_lang_String::as_utf8_string(JNIHandles::resolve_non_null(segment));
156 JvmtiEnv* jvmti_env = JvmtiEnv::create_a_jvmti(JVMTI_VERSION);
157 jvmtiError err = jvmti_env->AddToSystemClassLoaderSearch(seg);
158 assert(err == JVMTI_ERROR_NONE, "must not fail");
159 #endif
160 }
161 WB_END
162
163 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
164 #include "utilities/elfFile.hpp"
165 #endif
166 #if defined(LINUX)
167 #include "osContainer_linux.hpp"
168 #endif
169
WB_ENTRY(jlong,WB_GetCompressedOopsMaxHeapSize (JNIEnv * env,jobject o))170 WB_ENTRY(jlong, WB_GetCompressedOopsMaxHeapSize(JNIEnv* env, jobject o)) {
171 return (jlong)Arguments::max_heap_for_compressed_oops();
172 }
173 WB_END
174
WB_ENTRY(void,WB_PrintHeapSizes (JNIEnv * env,jobject o))175 WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) {
176 CollectorPolicy * p = Universe::heap()->collector_policy();
177 gclog_or_tty->print_cr("Minimum heap " SIZE_FORMAT " Initial heap "
178 SIZE_FORMAT " Maximum heap " SIZE_FORMAT " Space alignment " SIZE_FORMAT " Heap alignment " SIZE_FORMAT,
179 p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(),
180 p->space_alignment(), p->heap_alignment());
181 }
182 WB_END
183
184 #ifndef PRODUCT
185 // Forward declaration
186 void TestReservedSpace_test();
187 void TestReserveMemorySpecial_test();
188 void TestVirtualSpace_test();
189 void TestMetaspaceAux_test();
190 #endif
191
192 WB_ENTRY(void, WB_RunMemoryUnitTests(JNIEnv* env, jobject o))
193 #ifndef PRODUCT
194 TestReservedSpace_test();
195 TestReserveMemorySpecial_test();
196 TestVirtualSpace_test();
197 TestMetaspaceAux_test();
198 #endif
199 WB_END
200
201 WB_ENTRY(void, WB_ReadFromNoaccessArea(JNIEnv* env, jobject o))
202 size_t granularity = os::vm_allocation_granularity();
203 ReservedHeapSpace rhs(100 * granularity, granularity, false, NULL);
204 VirtualSpace vs;
205 vs.initialize(rhs, 50 * granularity);
206
207 //Check if constraints are complied
208 if (!( UseCompressedOops && rhs.base() != NULL &&
209 Universe::narrow_oop_base() != NULL &&
210 Universe::narrow_oop_use_implicit_null_checks() )) {
211 tty->print_cr("WB_ReadFromNoaccessArea method is useless:\n "
212 "\tUseCompressedOops is %d\n"
213 "\trhs.base() is " PTR_FORMAT "\n"
214 "\tUniverse::narrow_oop_base() is " PTR_FORMAT "\n"
215 "\tUniverse::narrow_oop_use_implicit_null_checks() is %d",
216 UseCompressedOops,
217 rhs.base(),
218 Universe::narrow_oop_base(),
219 Universe::narrow_oop_use_implicit_null_checks());
220 return;
221 }
222 tty->print_cr("Reading from no access area... ");
223 tty->print_cr("*(vs.low_boundary() - rhs.noaccess_prefix() / 2 ) = %c",
224 *(vs.low_boundary() - rhs.noaccess_prefix() / 2 ));
225 WB_END
226
wb_stress_virtual_space_resize(size_t reserved_space_size,size_t magnitude,size_t iterations)227 static jint wb_stress_virtual_space_resize(size_t reserved_space_size,
228 size_t magnitude, size_t iterations) {
229 size_t granularity = os::vm_allocation_granularity();
230 ReservedHeapSpace rhs(reserved_space_size * granularity, granularity, false, NULL);
231 VirtualSpace vs;
232 if (!vs.initialize(rhs, 0)) {
233 tty->print_cr("Failed to initialize VirtualSpace. Can't proceed.");
234 return 3;
235 }
236
237 long seed = os::random();
238 tty->print_cr("Random seed is %ld", seed);
239 os::init_random(seed);
240
241 for (size_t i = 0; i < iterations; i++) {
242
243 // Whether we will shrink or grow
244 bool shrink = os::random() % 2L == 0;
245
246 // Get random delta to resize virtual space
247 size_t delta = (size_t)os::random() % magnitude;
248
249 // If we are about to shrink virtual space below zero, then expand instead
250 if (shrink && vs.committed_size() < delta) {
251 shrink = false;
252 }
253
254 // Resizing by delta
255 if (shrink) {
256 vs.shrink_by(delta);
257 } else {
258 // If expanding fails expand_by will silently return false
259 vs.expand_by(delta, true);
260 }
261 }
262 return 0;
263 }
264
265 WB_ENTRY(jint, WB_StressVirtualSpaceResize(JNIEnv* env, jobject o,
266 jlong reserved_space_size, jlong magnitude, jlong iterations))
267 tty->print_cr("reservedSpaceSize=" JLONG_FORMAT ", magnitude=" JLONG_FORMAT ", "
268 "iterations=" JLONG_FORMAT "\n", reserved_space_size, magnitude,
269 iterations);
270 if (reserved_space_size < 0 || magnitude < 0 || iterations < 0) {
271 tty->print_cr("One of variables printed above is negative. Can't proceed.\n");
272 return 1;
273 }
274
275 // sizeof(size_t) depends on whether OS is 32bit or 64bit. sizeof(jlong) is
276 // always 8 byte. That's why we should avoid overflow in case of 32bit platform.
277 if (sizeof(size_t) < sizeof(jlong)) {
278 jlong size_t_max_value = (jlong) SIZE_T_MAX_VALUE;
279 if (reserved_space_size > size_t_max_value || magnitude > size_t_max_value
280 || iterations > size_t_max_value) {
281 tty->print_cr("One of variables printed above overflows size_t. Can't proceed.\n");
282 return 2;
283 }
284 }
285
286 return wb_stress_virtual_space_resize((size_t) reserved_space_size,
287 (size_t) magnitude, (size_t) iterations);
288 WB_END
289
290 WB_ENTRY(jboolean, WB_isObjectInOldGen(JNIEnv* env, jobject o, jobject obj))
291 oop p = JNIHandles::resolve(obj);
292 #if INCLUDE_ALL_GCS
293 if (UseG1GC) {
294 G1CollectedHeap* g1 = G1CollectedHeap::heap();
295 const HeapRegion* hr = g1->heap_region_containing(p);
296 if (hr == NULL) {
297 return false;
298 }
299 return !(hr->is_young());
300 } else if (UseParallelGC) {
301 ParallelScavengeHeap* psh = ParallelScavengeHeap::heap();
302 return !psh->is_in_young(p);
303 }
304 #endif // INCLUDE_ALL_GCS
305 GenCollectedHeap* gch = GenCollectedHeap::heap();
306 return !gch->is_in_young(p);
307 WB_END
308
309 WB_ENTRY(jlong, WB_GetObjectSize(JNIEnv* env, jobject o, jobject obj))
310 oop p = JNIHandles::resolve(obj);
311 return p->size() * HeapWordSize;
312 WB_END
313
314 #if INCLUDE_ALL_GCS
315 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj))
316 G1CollectedHeap* g1 = G1CollectedHeap::heap();
317 oop result = JNIHandles::resolve(obj);
318 const HeapRegion* hr = g1->heap_region_containing(result);
319 return hr->isHumongous();
320 WB_END
321
322 WB_ENTRY(jlong, WB_G1NumMaxRegions(JNIEnv* env, jobject o))
323 G1CollectedHeap* g1 = G1CollectedHeap::heap();
324 size_t nr = g1->max_regions();
325 return (jlong)nr;
326 WB_END
327
328 WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o))
329 G1CollectedHeap* g1 = G1CollectedHeap::heap();
330 size_t nr = g1->num_free_regions();
331 return (jlong)nr;
332 WB_END
333
334 WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o))
335 G1CollectedHeap* g1 = G1CollectedHeap::heap();
336 return g1->concurrent_mark()->cmThread()->during_cycle();
337 WB_END
338
339 WB_ENTRY(jboolean, WB_G1StartMarkCycle(JNIEnv* env, jobject o))
340 G1CollectedHeap* g1h = G1CollectedHeap::heap();
341 if (!g1h->concurrent_mark()->cmThread()->during_cycle()) {
342 g1h->collect(GCCause::_wb_conc_mark);
343 return true;
344 }
345 return false;
346 WB_END
347
348 WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o))
349 return (jint)HeapRegion::GrainBytes;
350 WB_END
351
352 WB_ENTRY(jobject, WB_G1AuxiliaryMemoryUsage(JNIEnv* env))
353 ResourceMark rm(THREAD);
354 G1CollectedHeap* g1h = G1CollectedHeap::heap();
355 MemoryUsage usage = g1h->get_auxiliary_data_memory_usage();
356 Handle h = MemoryService::create_MemoryUsage_obj(usage, CHECK_NULL);
357 return JNIHandles::make_local(env, h());
358 WB_END
359 #endif // INCLUDE_ALL_GCS
360
361 #if INCLUDE_NMT
362 // Alloc memory using the test memory type so that we can use that to see if
363 // NMT picks it up correctly
364 WB_ENTRY(jlong, WB_NMTMalloc(JNIEnv* env, jobject o, jlong size))
365 jlong addr = 0;
366 addr = (jlong)(uintptr_t)os::malloc(size, mtTest);
367 return addr;
368 WB_END
369
370 // Alloc memory with pseudo call stack. The test can create psudo malloc
371 // allocation site to stress the malloc tracking.
372 WB_ENTRY(jlong, WB_NMTMallocWithPseudoStack(JNIEnv* env, jobject o, jlong size, jint pseudo_stack))
373 address pc = (address)(size_t)pseudo_stack;
374 NativeCallStack stack(&pc, 1);
375 return (jlong)(uintptr_t)os::malloc(size, mtTest, stack);
376 WB_END
377
378 // Alloc memory with pseudo call stack and specific memory type.
379 WB_ENTRY(jlong, WB_NMTMallocWithPseudoStackAndType(JNIEnv* env, jobject o, jlong size, jint pseudo_stack, jint type))
380 address pc = (address)(size_t)pseudo_stack;
381 NativeCallStack stack(&pc, 1);
382 return (jlong)(uintptr_t)os::malloc(size, (MEMFLAGS)type, stack);
383 WB_END
384
385 // Free the memory allocated by NMTAllocTest
386 WB_ENTRY(void, WB_NMTFree(JNIEnv* env, jobject o, jlong mem))
387 os::free((void*)(uintptr_t)mem, mtTest);
388 WB_END
389
390 WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
391 jlong addr = 0;
392
393 addr = (jlong)(uintptr_t)os::reserve_memory(size);
394 MemTracker::record_virtual_memory_type((address)addr, mtTest);
395
396 return addr;
397 WB_END
398
399
400 WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
401 os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem);
402 MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
403 WB_END
404
405 WB_ENTRY(void, WB_NMTUncommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
406 os::uncommit_memory((char *)(uintptr_t)addr, size);
407 WB_END
408
409 WB_ENTRY(void, WB_NMTReleaseMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
410 os::release_memory((char *)(uintptr_t)addr, size);
411 WB_END
412
413 WB_ENTRY(jboolean, WB_NMTIsDetailSupported(JNIEnv* env))
414 return MemTracker::tracking_level() == NMT_detail;
415 WB_END
416
417 WB_ENTRY(jboolean, WB_NMTChangeTrackingLevel(JNIEnv* env))
418 // Test that we can downgrade NMT levels but not upgrade them.
419 if (MemTracker::tracking_level() == NMT_off) {
420 MemTracker::transition_to(NMT_off);
421 return MemTracker::tracking_level() == NMT_off;
422 } else {
423 assert(MemTracker::tracking_level() == NMT_detail, "Should start out as detail tracking");
424 MemTracker::transition_to(NMT_summary);
425 assert(MemTracker::tracking_level() == NMT_summary, "Should be summary now");
426
427 // Can't go to detail once NMT is set to summary.
428 MemTracker::transition_to(NMT_detail);
429 assert(MemTracker::tracking_level() == NMT_summary, "Should still be summary now");
430
431 // Shutdown sets tracking level to minimal.
432 MemTracker::shutdown();
433 assert(MemTracker::tracking_level() == NMT_minimal, "Should be minimal now");
434
435 // Once the tracking level is minimal, we cannot increase to summary.
436 // The code ignores this request instead of asserting because if the malloc site
437 // table overflows in another thread, it tries to change the code to summary.
438 MemTracker::transition_to(NMT_summary);
439 assert(MemTracker::tracking_level() == NMT_minimal, "Should still be minimal now");
440
441 // Really can never go up to detail, verify that the code would never do this.
442 MemTracker::transition_to(NMT_detail);
443 assert(MemTracker::tracking_level() == NMT_minimal, "Should still be minimal now");
444 return MemTracker::tracking_level() == NMT_minimal;
445 }
446 WB_END
447
448 WB_ENTRY(jint, WB_NMTGetHashSize(JNIEnv* env, jobject o))
449 int hash_size = MallocSiteTable::hash_buckets();
450 assert(hash_size > 0, "NMT hash_size should be > 0");
451 return (jint)hash_size;
452 WB_END
453
454 WB_ENTRY(jlong, WB_NMTNewArena(JNIEnv* env, jobject o, jlong init_size))
455 Arena* arena = new (mtTest) Arena(mtTest, size_t(init_size));
456 return (jlong)arena;
457 WB_END
458
459 WB_ENTRY(void, WB_NMTFreeArena(JNIEnv* env, jobject o, jlong arena))
460 Arena* a = (Arena*)arena;
461 delete a;
462 WB_END
463
464 WB_ENTRY(void, WB_NMTArenaMalloc(JNIEnv* env, jobject o, jlong arena, jlong size))
465 Arena* a = (Arena*)arena;
466 a->Amalloc(size_t(size));
467 WB_END
468 #endif // INCLUDE_NMT
469
reflected_method_to_jmid(JavaThread * thread,JNIEnv * env,jobject method)470 static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) {
471 assert(method != NULL, "method should not be null");
472 ThreadToNativeFromVM ttn(thread);
473 return env->FromReflectedMethod(method);
474 }
475
476 WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o))
477 MutexLockerEx mu(Compile_lock);
478 CodeCache::mark_all_nmethods_for_deoptimization();
479 VM_Deoptimize op;
480 VMThread::execute(&op);
481 WB_END
482
483 WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
484 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
485 int result = 0;
486 CHECK_JNI_EXCEPTION_(env, result);
487 MutexLockerEx mu(Compile_lock);
488 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
489 if (is_osr) {
490 result += mh->mark_osr_nmethods();
491 } else if (mh->code() != NULL) {
492 mh->code()->mark_for_deoptimization();
493 ++result;
494 }
495 result += CodeCache::mark_for_deoptimization(mh());
496 if (result > 0) {
497 VM_Deoptimize op;
498 VMThread::execute(&op);
499 }
500 return result;
501 WB_END
502
503 WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
504 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
505 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
506 MutexLockerEx mu(Compile_lock);
507 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
508 nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
509 if (code == NULL) {
510 return JNI_FALSE;
511 }
512 return (code->is_alive() && !code->is_marked_for_deoptimization());
513 WB_END
514
515 WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr))
516 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
517 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
518 MutexLockerEx mu(Compile_lock);
519 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
520 if (is_osr) {
521 return CompilationPolicy::can_be_osr_compiled(mh, comp_level);
522 } else {
523 return CompilationPolicy::can_be_compiled(mh, comp_level);
524 }
525 WB_END
526
527 WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method))
528 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
529 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
530 MutexLockerEx mu(Compile_lock);
531 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
532 return mh->queued_for_compilation();
533 WB_END
534
535 WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
536 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
537 CHECK_JNI_EXCEPTION_(env, CompLevel_none);
538 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
539 nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
540 return (code != NULL ? code->comp_level() : CompLevel_none);
541 WB_END
542
543 WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method, jint comp_level, jboolean is_osr))
544 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
545 CHECK_JNI_EXCEPTION(env);
546 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
547 if (is_osr) {
548 mh->set_not_osr_compilable(comp_level, true /* report */, "WhiteBox");
549 } else {
550 mh->set_not_compilable(comp_level, true /* report */, "WhiteBox");
551 }
552 WB_END
553
554 WB_ENTRY(jint, WB_GetMethodEntryBci(JNIEnv* env, jobject o, jobject method))
555 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
556 CHECK_JNI_EXCEPTION_(env, InvocationEntryBci);
557 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
558 nmethod* code = mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false);
559 return (code != NULL && code->is_osr_method() ? code->osr_entry_bci() : InvocationEntryBci);
560 WB_END
561
562 WB_ENTRY(jboolean, WB_TestSetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
563 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
564 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
565 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
566 bool result = mh->dont_inline();
567 mh->set_dont_inline(value == JNI_TRUE);
568 return result;
569 WB_END
570
571 WB_ENTRY(jint, WB_GetCompileQueueSize(JNIEnv* env, jobject o, jint comp_level))
572 if (comp_level == CompLevel_any) {
573 return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ +
574 CompileBroker::queue_size(CompLevel_full_profile) /* C1 */;
575 } else {
576 return CompileBroker::queue_size(comp_level);
577 }
578 WB_END
579
580 WB_ENTRY(jboolean, WB_TestSetForceInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value))
581 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
582 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
583 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
584 bool result = mh->force_inline();
585 mh->set_force_inline(value == JNI_TRUE);
586 return result;
587 WB_END
588
compile_method(Method * method,int comp_level,int bci,Thread * THREAD)589 bool WhiteBox::compile_method(Method* method, int comp_level, int bci, Thread* THREAD) {
590 // Screen for unavailable/bad comp level or null method
591 AbstractCompiler* comp = CompileBroker::compiler(comp_level);
592 if (method == NULL) {
593 tty->print_cr("WB error: request to compile NULL method");
594 return false;
595 }
596 if (comp_level > MIN2((CompLevel) TieredStopAtLevel, CompLevel_highest_tier)) {
597 tty->print_cr("WB error: invalid compilation level %d", comp_level);
598 return false;
599 }
600 if (comp == NULL) {
601 tty->print_cr("WB error: no compiler for requested compilation level %d", comp_level);
602 return false;
603 }
604
605 methodHandle mh(THREAD, method);
606
607 // Compile method and check result
608 nmethod* nm = CompileBroker::compile_method(mh, bci, comp_level, mh, mh->invocation_count(), "Whitebox", THREAD);
609 MutexLocker mu(Compile_lock);
610 bool is_queued = mh->queued_for_compilation();
611 if (is_queued || nm != NULL) {
612 return true;
613 }
614 tty->print("WB error: failed to compile at level %d method ", comp_level);
615 mh->print_short_name(tty);
616 tty->cr();
617 if (is_queued) {
618 tty->print_cr("WB error: blocking compilation is still in queue!");
619 }
620 return false;
621 }
622
623 WB_ENTRY(jboolean, WB_EnqueueMethodForCompilation(JNIEnv* env, jobject o, jobject method, jint comp_level, jint bci))
624 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
625 CHECK_JNI_EXCEPTION_(env, JNI_FALSE);
626 return WhiteBox::compile_method(Method::checked_resolve_jmethod_id(jmid), comp_level, bci, THREAD);
627 WB_END
628
629 WB_ENTRY(jboolean, WB_EnqueueInitializerForCompilation(JNIEnv* env, jobject o, jclass klass, jint comp_level))
630 InstanceKlass* ik = InstanceKlass::cast(java_lang_Class::as_Klass(JNIHandles::resolve(klass)));
631 Method* clinit = ik->class_initializer();
632 if (clinit == NULL) {
633 return false;
634 }
635 return WhiteBox::compile_method(clinit, comp_level, InvocationEntryBci, THREAD);
636 WB_END
637
638 class VM_WhiteBoxOperation : public VM_Operation {
639 public:
VM_WhiteBoxOperation()640 VM_WhiteBoxOperation() { }
type() const641 VMOp_Type type() const { return VMOp_WhiteBoxOperation; }
allow_nested_vm_operations() const642 bool allow_nested_vm_operations() const { return true; }
643 };
644
645 static AlwaysFalseClosure always_false;
646
647 class VM_WhiteBoxCleanMethodData : public VM_WhiteBoxOperation {
648 public:
VM_WhiteBoxCleanMethodData(MethodData * mdo)649 VM_WhiteBoxCleanMethodData(MethodData* mdo) : _mdo(mdo) { }
doit()650 void doit() {
651 _mdo->clean_method_data(&always_false);
652 }
653 private:
654 MethodData* _mdo;
655 };
656
657 WB_ENTRY(void, WB_ClearMethodState(JNIEnv* env, jobject o, jobject method))
658 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
659 CHECK_JNI_EXCEPTION(env);
660 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
661 MutexLockerEx mu(Compile_lock);
662 MethodData* mdo = mh->method_data();
663 MethodCounters* mcs = mh->method_counters();
664
665 if (mdo != NULL) {
666 mdo->init();
667 ResourceMark rm;
668 int arg_count = mdo->method()->size_of_parameters();
669 for (int i = 0; i < arg_count; i++) {
670 mdo->set_arg_modified(i, 0);
671 }
672 VM_WhiteBoxCleanMethodData op(mdo);
673 VMThread::execute(&op);
674 }
675
676 mh->clear_not_c1_compilable();
677 mh->clear_not_c2_compilable();
678 mh->clear_not_c2_osr_compilable();
679 NOT_PRODUCT(mh->set_compiled_invocation_count(0));
680 if (mcs != NULL) {
681 mcs->backedge_counter()->init();
682 mcs->invocation_counter()->init();
683 mcs->set_interpreter_invocation_count(0);
684 mcs->set_interpreter_throwout_count(0);
685
686 #ifdef TIERED
687 mcs->set_rate(0.0F);
688 mh->set_prev_event_count(0);
689 mh->set_prev_time(0);
690 #endif
691 }
692 WB_END
693
694 WB_ENTRY(void, WB_MarkMethodProfiled(JNIEnv* env, jobject o, jobject method))
695 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
696 CHECK_JNI_EXCEPTION(env);
697 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
698
699 MethodData* mdo = mh->method_data();
700 if (mdo == NULL) {
701 Method::build_interpreter_method_data(mh, CHECK_AND_CLEAR);
702 mdo = mh->method_data();
703 }
704 mdo->init();
705 InvocationCounter* icnt = mdo->invocation_counter();
706 InvocationCounter* bcnt = mdo->backedge_counter();
707 // set i-counter according to AdvancedThresholdPolicy::is_method_profiled
708 // because SimpleThresholdPolicy::call_predicate_helper uses > in jdk8u, that's why we need to plus one.
709 icnt->set(InvocationCounter::wait_for_compile, Tier4MinInvocationThreshold + 1);
710 bcnt->set(InvocationCounter::wait_for_compile, Tier4CompileThreshold + 1);
711 WB_END
712
713 template <typename T>
GetVMFlag(JavaThread * thread,JNIEnv * env,jstring name,T * value,bool (* TAt)(const char *,T *,bool,bool))714 static bool GetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, bool (*TAt)(const char*, T*, bool, bool)) {
715 if (name == NULL) {
716 return false;
717 }
718 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
719 const char* flag_name = env->GetStringUTFChars(name, NULL);
720 bool result = (*TAt)(flag_name, value, true, true);
721 env->ReleaseStringUTFChars(name, flag_name);
722 return result;
723 }
724
725 template <typename T>
SetVMFlag(JavaThread * thread,JNIEnv * env,jstring name,T * value,bool (* TAtPut)(const char *,T *,Flag::Flags))726 static bool SetVMFlag(JavaThread* thread, JNIEnv* env, jstring name, T* value, bool (*TAtPut)(const char*, T*, Flag::Flags)) {
727 if (name == NULL) {
728 return false;
729 }
730 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
731 const char* flag_name = env->GetStringUTFChars(name, NULL);
732 bool result = (*TAtPut)(flag_name, value, Flag::INTERNAL);
733 env->ReleaseStringUTFChars(name, flag_name);
734 return result;
735 }
736
737 template <typename T>
box(JavaThread * thread,JNIEnv * env,Symbol * name,Symbol * sig,T value)738 static jobject box(JavaThread* thread, JNIEnv* env, Symbol* name, Symbol* sig, T value) {
739 ResourceMark rm(thread);
740 jclass clazz = env->FindClass(name->as_C_string());
741 CHECK_JNI_EXCEPTION_(env, NULL);
742 jmethodID methodID = env->GetStaticMethodID(clazz,
743 vmSymbols::valueOf_name()->as_C_string(),
744 sig->as_C_string());
745 CHECK_JNI_EXCEPTION_(env, NULL);
746 jobject result = env->CallStaticObjectMethod(clazz, methodID, value);
747 CHECK_JNI_EXCEPTION_(env, NULL);
748 return result;
749 }
750
booleanBox(JavaThread * thread,JNIEnv * env,jboolean value)751 static jobject booleanBox(JavaThread* thread, JNIEnv* env, jboolean value) {
752 return box(thread, env, vmSymbols::java_lang_Boolean(), vmSymbols::Boolean_valueOf_signature(), value);
753 }
integerBox(JavaThread * thread,JNIEnv * env,jint value)754 static jobject integerBox(JavaThread* thread, JNIEnv* env, jint value) {
755 return box(thread, env, vmSymbols::java_lang_Integer(), vmSymbols::Integer_valueOf_signature(), value);
756 }
longBox(JavaThread * thread,JNIEnv * env,jlong value)757 static jobject longBox(JavaThread* thread, JNIEnv* env, jlong value) {
758 return box(thread, env, vmSymbols::java_lang_Long(), vmSymbols::Long_valueOf_signature(), value);
759 }
760 /* static jobject floatBox(JavaThread* thread, JNIEnv* env, jfloat value) {
761 return box(thread, env, vmSymbols::java_lang_Float(), vmSymbols::Float_valueOf_signature(), value);
762 }*/
doubleBox(JavaThread * thread,JNIEnv * env,jdouble value)763 static jobject doubleBox(JavaThread* thread, JNIEnv* env, jdouble value) {
764 return box(thread, env, vmSymbols::java_lang_Double(), vmSymbols::Double_valueOf_signature(), value);
765 }
766
767 WB_ENTRY(jobject, WB_GetBooleanVMFlag(JNIEnv* env, jobject o, jstring name))
768 bool result;
769 if (GetVMFlag <bool> (thread, env, name, &result, &CommandLineFlags::boolAt)) {
770 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
771 return booleanBox(thread, env, result);
772 }
773 return NULL;
774 WB_END
775
776 WB_ENTRY(jobject, WB_GetIntxVMFlag(JNIEnv* env, jobject o, jstring name))
777 intx result;
778 if (GetVMFlag <intx> (thread, env, name, &result, &CommandLineFlags::intxAt)) {
779 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
780 return longBox(thread, env, result);
781 }
782 return NULL;
783 WB_END
784
785 WB_ENTRY(jobject, WB_GetUintxVMFlag(JNIEnv* env, jobject o, jstring name))
786 uintx result;
787 if (GetVMFlag <uintx> (thread, env, name, &result, &CommandLineFlags::uintxAt)) {
788 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
789 return longBox(thread, env, result);
790 }
791 return NULL;
792 WB_END
793
794 WB_ENTRY(jobject, WB_GetUint64VMFlag(JNIEnv* env, jobject o, jstring name))
795 uint64_t result;
796 if (GetVMFlag <uint64_t> (thread, env, name, &result, &CommandLineFlags::uint64_tAt)) {
797 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
798 return longBox(thread, env, result);
799 }
800 return NULL;
801 WB_END
802
803 WB_ENTRY(jobject, WB_GetDoubleVMFlag(JNIEnv* env, jobject o, jstring name))
804 double result;
805 if (GetVMFlag <double> (thread, env, name, &result, &CommandLineFlags::doubleAt)) {
806 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
807 return doubleBox(thread, env, result);
808 }
809 return NULL;
810 WB_END
811
812 WB_ENTRY(jstring, WB_GetStringVMFlag(JNIEnv* env, jobject o, jstring name))
813 ccstr ccstrResult;
814 if (GetVMFlag <ccstr> (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAt)) {
815 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
816 jstring result = env->NewStringUTF(ccstrResult);
817 CHECK_JNI_EXCEPTION_(env, NULL);
818 return result;
819 }
820 return NULL;
821 WB_END
822
823 WB_ENTRY(void, WB_SetBooleanVMFlag(JNIEnv* env, jobject o, jstring name, jboolean value))
824 bool result = value == JNI_TRUE ? true : false;
825 SetVMFlag <bool> (thread, env, name, &result, &CommandLineFlags::boolAtPut);
826 WB_END
827
828 WB_ENTRY(void, WB_SetIntxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value))
829 intx result = value;
830 SetVMFlag <intx> (thread, env, name, &result, &CommandLineFlags::intxAtPut);
831 WB_END
832
833 WB_ENTRY(void, WB_SetUintxVMFlag(JNIEnv* env, jobject o, jstring name, jlong value))
834 uintx result = value;
835 SetVMFlag <uintx> (thread, env, name, &result, &CommandLineFlags::uintxAtPut);
836 WB_END
837
838 WB_ENTRY(void, WB_SetUint64VMFlag(JNIEnv* env, jobject o, jstring name, jlong value))
839 uint64_t result = value;
840 SetVMFlag <uint64_t> (thread, env, name, &result, &CommandLineFlags::uint64_tAtPut);
841 WB_END
842
843 WB_ENTRY(void, WB_SetDoubleVMFlag(JNIEnv* env, jobject o, jstring name, jdouble value))
844 double result = value;
845 SetVMFlag <double> (thread, env, name, &result, &CommandLineFlags::doubleAtPut);
846 WB_END
847
848 WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring value))
849 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
850 const char* ccstrValue = (value == NULL) ? NULL : env->GetStringUTFChars(value, NULL);
851 ccstr ccstrResult = ccstrValue;
852 bool needFree;
853 {
854 ThreadInVMfromNative ttvfn(thread); // back to VM
855 needFree = SetVMFlag <ccstr> (thread, env, name, &ccstrResult, &CommandLineFlags::ccstrAtPut);
856 }
857 if (value != NULL) {
858 env->ReleaseStringUTFChars(value, ccstrValue);
859 }
860 if (needFree) {
861 FREE_C_HEAP_ARRAY(char, ccstrResult, mtInternal);
862 }
863 WB_END
864
865 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
866 ResourceMark rm(THREAD);
867 int len;
868 jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len, CHECK_false);
869 return (StringTable::lookup(name, len) != NULL);
870 WB_END
871
872 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o))
873 Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true);
874 Universe::heap()->collect(GCCause::_last_ditch_collection);
875 #if INCLUDE_ALL_GCS
876 if (UseG1GC) {
877 // Needs to be cleared explicitly for G1
878 Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(false);
879 }
880 #endif // INCLUDE_ALL_GCS
881 WB_END
882
883 WB_ENTRY(void, WB_YoungGC(JNIEnv* env, jobject o))
884 Universe::heap()->collect(GCCause::_wb_young_gc);
885 WB_END
886
887 WB_ENTRY(void, WB_ReadReservedMemory(JNIEnv* env, jobject o))
888 // static+volatile in order to force the read to happen
889 // (not be eliminated by the compiler)
890 static char c;
891 static volatile char* p;
892
893 p = os::reserve_memory(os::vm_allocation_granularity(), NULL, 0);
894 if (p == NULL) {
895 THROW_MSG(vmSymbols::java_lang_OutOfMemoryError(), "Failed to reserve memory");
896 }
897
898 c = *p;
899 WB_END
900
901 WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o))
902 const char* cpu_features = VM_Version::cpu_features();
903 ThreadToNativeFromVM ttn(thread);
904 jstring features_string = env->NewStringUTF(cpu_features);
905
906 CHECK_JNI_EXCEPTION_(env, NULL);
907
908 return features_string;
909 WB_END
910
get_blob_type(const CodeBlob * code)911 int WhiteBox::get_blob_type(const CodeBlob* code) {
912 guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
913 return CodeBlobType::All;;
914 }
915
916 struct CodeBlobStub {
CodeBlobStubCodeBlobStub917 CodeBlobStub(const CodeBlob* blob) :
918 name(os::strdup(blob->name())),
919 size(blob->size()),
920 blob_type(WhiteBox::get_blob_type(blob)),
921 address((jlong) blob) { }
~CodeBlobStubCodeBlobStub922 ~CodeBlobStub() { os::free((void*) name); }
923 const char* const name;
924 const jint size;
925 const jint blob_type;
926 const jlong address;
927 };
928
codeBlob2objectArray(JavaThread * thread,JNIEnv * env,CodeBlobStub * cb)929 static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) {
930 jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
931 CHECK_JNI_EXCEPTION_(env, NULL);
932 jobjectArray result = env->NewObjectArray(4, clazz, NULL);
933
934 jstring name = env->NewStringUTF(cb->name);
935 CHECK_JNI_EXCEPTION_(env, NULL);
936 env->SetObjectArrayElement(result, 0, name);
937
938 jobject obj = integerBox(thread, env, cb->size);
939 CHECK_JNI_EXCEPTION_(env, NULL);
940 env->SetObjectArrayElement(result, 1, obj);
941
942 obj = integerBox(thread, env, cb->blob_type);
943 CHECK_JNI_EXCEPTION_(env, NULL);
944 env->SetObjectArrayElement(result, 2, obj);
945
946 obj = longBox(thread, env, cb->address);
947 CHECK_JNI_EXCEPTION_(env, NULL);
948 env->SetObjectArrayElement(result, 3, obj);
949
950 return result;
951 }
952
953 WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
954 ResourceMark rm(THREAD);
955 jmethodID jmid = reflected_method_to_jmid(thread, env, method);
956 CHECK_JNI_EXCEPTION_(env, NULL);
957 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid));
958 nmethod* code = is_osr ? mh->lookup_osr_nmethod_for(InvocationEntryBci, CompLevel_none, false) : mh->code();
959 jobjectArray result = NULL;
960 if (code == NULL) {
961 return result;
962 }
963 int insts_size = code->insts_size();
964
965 ThreadToNativeFromVM ttn(thread);
966 jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
967 CHECK_JNI_EXCEPTION_(env, NULL);
968 result = env->NewObjectArray(3, clazz, NULL);
969 if (result == NULL) {
970 return result;
971 }
972
973 jobject level = integerBox(thread, env, code->comp_level());
974 CHECK_JNI_EXCEPTION_(env, NULL);
975 env->SetObjectArrayElement(result, 0, level);
976
977 jobject id = integerBox(thread, env, code->compile_id());
978 CHECK_JNI_EXCEPTION_(env, NULL);
979 env->SetObjectArrayElement(result, 1, id);
980
981 jbyteArray insts = env->NewByteArray(insts_size);
982 CHECK_JNI_EXCEPTION_(env, NULL);
983 env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin());
984 env->SetObjectArrayElement(result, 2, insts);
985
986 return result;
987 WB_END
988
allocate_code_blob(int size,int blob_type)989 CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) {
990 guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
991 BufferBlob* blob;
992 int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob));
993 if (full_size < size) {
994 full_size += align_up(size - full_size, oopSize);
995 }
996 {
997 MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
998 blob = (BufferBlob*) CodeCache::allocate(full_size);
999 ::new (blob) BufferBlob("WB::DummyBlob", full_size);
1000 }
1001 // Track memory usage statistic after releasing CodeCache_lock
1002 MemoryService::track_code_cache_memory_usage();
1003 return blob;
1004 }
1005
1006 WB_ENTRY(jlong, WB_AllocateCodeBlob(JNIEnv* env, jobject o, jint size, jint blob_type))
1007 if (size < 0) {
1008 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
1009 err_msg("WB_AllocateCodeBlob: size is negative: " INT32_FORMAT, size));
1010 }
1011 return (jlong) WhiteBox::allocate_code_blob(size, blob_type);
1012 WB_END
1013
1014 WB_ENTRY(void, WB_FreeCodeBlob(JNIEnv* env, jobject o, jlong addr))
1015 if (addr == 0) {
1016 return;
1017 }
1018 BufferBlob::free((BufferBlob*) addr);
1019 WB_END
1020
1021 WB_ENTRY(jobjectArray, WB_GetCodeBlob(JNIEnv* env, jobject o, jlong addr))
1022 if (addr == 0) {
1023 THROW_MSG_NULL(vmSymbols::java_lang_NullPointerException(),
1024 "WB_GetCodeBlob: addr is null");
1025 }
1026 ThreadToNativeFromVM ttn(thread);
1027 CodeBlobStub stub((CodeBlob*) addr);
1028 return codeBlob2objectArray(thread, env, &stub);
1029 WB_END
1030
array_bytes_to_length(size_t bytes)1031 int WhiteBox::array_bytes_to_length(size_t bytes) {
1032 return Array<u1>::bytes_to_length(bytes);
1033 }
1034
1035 WB_ENTRY(jlong, WB_AllocateMetaspace(JNIEnv* env, jobject wb, jobject class_loader, jlong size))
1036 if (size < 0) {
1037 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
1038 err_msg("WB_AllocateMetaspace: size is negative: " JLONG_FORMAT, size));
1039 }
1040
1041 oop class_loader_oop = JNIHandles::resolve(class_loader);
1042 ClassLoaderData* cld = class_loader_oop != NULL
1043 ? java_lang_ClassLoader::loader_data(class_loader_oop)
1044 : ClassLoaderData::the_null_class_loader_data();
1045
1046 void* metadata = MetadataFactory::new_writeable_array<u1>(cld, WhiteBox::array_bytes_to_length((size_t)size), thread);
1047
1048 return (jlong)(uintptr_t)metadata;
1049 WB_END
1050
1051 WB_ENTRY(void, WB_FreeMetaspace(JNIEnv* env, jobject wb, jobject class_loader, jlong addr, jlong size))
1052 oop class_loader_oop = JNIHandles::resolve(class_loader);
1053 ClassLoaderData* cld = class_loader_oop != NULL
1054 ? java_lang_ClassLoader::loader_data(class_loader_oop)
1055 : ClassLoaderData::the_null_class_loader_data();
1056
1057 MetadataFactory::free_array(cld, (Array<u1>*)(uintptr_t)addr);
1058 WB_END
1059
1060 WB_ENTRY(jlong, WB_IncMetaspaceCapacityUntilGC(JNIEnv* env, jobject wb, jlong inc))
1061 if (inc < 0) {
1062 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
1063 err_msg("WB_IncMetaspaceCapacityUntilGC: inc is negative: " JLONG_FORMAT, inc));
1064 }
1065
1066 jlong max_size_t = (jlong) ((size_t) -1);
1067 if (inc > max_size_t) {
1068 THROW_MSG_0(vmSymbols::java_lang_IllegalArgumentException(),
1069 err_msg("WB_IncMetaspaceCapacityUntilGC: inc does not fit in size_t: " JLONG_FORMAT, inc));
1070 }
1071
1072 size_t new_cap_until_GC = 0;
1073 size_t aligned_inc = align_size_down((size_t) inc, Metaspace::commit_alignment());
1074 bool success = MetaspaceGC::inc_capacity_until_GC(aligned_inc, &new_cap_until_GC);
1075 if (!success) {
1076 THROW_MSG_0(vmSymbols::java_lang_IllegalStateException(),
1077 "WB_IncMetaspaceCapacityUntilGC: could not increase capacity until GC "
1078 "due to contention with another thread");
1079 }
1080 return (jlong) new_cap_until_GC;
1081 WB_END
1082
1083 WB_ENTRY(jlong, WB_MetaspaceCapacityUntilGC(JNIEnv* env, jobject wb))
1084 return (jlong) MetaspaceGC::capacity_until_GC();
1085 WB_END
1086
1087 WB_ENTRY(jboolean, WB_IsSharedClass(JNIEnv* env, jobject wb, jclass clazz))
1088 return (jboolean)MetaspaceShared::is_in_shared_space(java_lang_Class::as_Klass(JNIHandles::resolve_non_null(clazz)));
1089 WB_END
1090
1091 WB_ENTRY(jboolean, WB_IsMonitorInflated(JNIEnv* env, jobject wb, jobject obj))
1092 oop obj_oop = JNIHandles::resolve(obj);
1093 return (jboolean) obj_oop->mark()->has_monitor();
1094 WB_END
1095
1096 WB_ENTRY(void, WB_ForceSafepoint(JNIEnv* env, jobject wb))
1097 VM_ForceSafepoint force_safepoint_op;
1098 VMThread::execute(&force_safepoint_op);
1099 WB_END
1100
1101 WB_ENTRY(jlong, WB_GetHeapAlignment(JNIEnv* env, jobject o))
1102 size_t alignment = Universe::heap()->collector_policy()->heap_alignment();
1103 return (jlong)alignment;
1104 WB_END
1105
1106 //Some convenience methods to deal with objects from java
offset_for_field(const char * field_name,oop object,Symbol * signature_symbol)1107 int WhiteBox::offset_for_field(const char* field_name, oop object,
1108 Symbol* signature_symbol) {
1109 assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid");
1110 Thread* THREAD = Thread::current();
1111
1112 //Get the class of our object
1113 Klass* arg_klass = object->klass();
1114 //Turn it into an instance-klass
1115 InstanceKlass* ik = InstanceKlass::cast(arg_klass);
1116
1117 //Create symbols to look for in the class
1118 TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name),
1119 THREAD);
1120
1121 //To be filled in with an offset of the field we're looking for
1122 fieldDescriptor fd;
1123
1124 Klass* res = ik->find_field(name_symbol, signature_symbol, &fd);
1125 if (res == NULL) {
1126 tty->print_cr("Invalid layout of %s at %s", ik->external_name(),
1127 name_symbol->as_C_string());
1128 vm_exit_during_initialization("Invalid layout of preloaded class: use -XX:+TraceClassLoading to see the origin of the problem class");
1129 }
1130
1131 //fetch the field at the offset we've found
1132 int dest_offset = fd.offset();
1133
1134 return dest_offset;
1135 }
1136
1137
lookup_jstring(const char * field_name,oop object)1138 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) {
1139 int offset = offset_for_field(field_name, object,
1140 vmSymbols::string_signature());
1141 oop string = object->obj_field(offset);
1142 if (string == NULL) {
1143 return NULL;
1144 }
1145 const char* ret = java_lang_String::as_utf8_string(string);
1146 return ret;
1147 }
1148
lookup_bool(const char * field_name,oop object)1149 bool WhiteBox::lookup_bool(const char* field_name, oop object) {
1150 int offset =
1151 offset_for_field(field_name, object, vmSymbols::bool_signature());
1152 bool ret = (object->bool_field(offset) == JNI_TRUE);
1153 return ret;
1154 }
1155
register_methods(JNIEnv * env,jclass wbclass,JavaThread * thread,JNINativeMethod * method_array,int method_count)1156 void WhiteBox::register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread, JNINativeMethod* method_array, int method_count) {
1157 ResourceMark rm;
1158 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI
1159
1160 // one by one registration natives for exception catching
1161 jclass no_such_method_error_klass = env->FindClass(vmSymbols::java_lang_NoSuchMethodError()->as_C_string());
1162 CHECK_JNI_EXCEPTION(env);
1163 for (int i = 0, n = method_count; i < n; ++i) {
1164 // Skip dummy entries
1165 if (method_array[i].fnPtr == NULL) continue;
1166 if (env->RegisterNatives(wbclass, &method_array[i], 1) != 0) {
1167 jthrowable throwable_obj = env->ExceptionOccurred();
1168 if (throwable_obj != NULL) {
1169 env->ExceptionClear();
1170 if (env->IsInstanceOf(throwable_obj, no_such_method_error_klass)) {
1171 // NoSuchMethodError is thrown when a method can't be found or a method is not native.
1172 // Ignoring the exception since it is not preventing use of other WhiteBox methods.
1173 tty->print_cr("Warning: 'NoSuchMethodError' on register of sun.hotspot.WhiteBox::%s%s",
1174 method_array[i].name, method_array[i].signature);
1175 }
1176 } else {
1177 // Registration failed unexpectedly.
1178 tty->print_cr("Warning: unexpected error on register of sun.hotspot.WhiteBox::%s%s. All methods will be unregistered",
1179 method_array[i].name, method_array[i].signature);
1180 env->UnregisterNatives(wbclass);
1181 break;
1182 }
1183 }
1184 }
1185 }
1186
1187 // Checks that the library libfile has the noexecstack bit set.
1188 WB_ENTRY(jboolean, WB_CheckLibSpecifiesNoexecstack(JNIEnv* env, jobject o, jstring libfile))
1189 jboolean ret = false;
1190 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
1191 // Can't be in VM when we call JNI.
1192 ThreadToNativeFromVM ttnfv(thread);
1193 const char* lf = env->GetStringUTFChars(libfile, NULL);
1194 CHECK_JNI_EXCEPTION_(env, 0);
1195 ElfFile ef(lf);
1196 ret = (jboolean) ef.specifies_noexecstack();
1197 env->ReleaseStringUTFChars(libfile, lf);
1198 #endif
1199 return ret;
1200 WB_END
1201
1202 WB_ENTRY(jboolean, WB_IsContainerized(JNIEnv* env, jobject o))
1203 LINUX_ONLY(return OSContainer::is_containerized();)
1204 return false;
1205 WB_END
1206
1207 WB_ENTRY(void, WB_PrintOsInfo(JNIEnv* env, jobject o))
1208 os::print_os_info(tty);
1209 WB_END
1210
1211 #define CC (char*)
1212
1213 static JNINativeMethod methods[] = {
1214 {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress },
1215 {CC"getObjectSize", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectSize },
1216 {CC"isObjectInOldGen", CC"(Ljava/lang/Object;)Z", (void*)&WB_isObjectInOldGen },
1217 {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize },
1218 {CC"getVMPageSize", CC"()I", (void*)&WB_GetVMPageSize },
1219 {CC"getVMLargePageSize", CC"()J", (void*)&WB_GetVMLargePageSize},
1220 {CC"getHeapAlignment", CC"()J", (void*)&WB_GetHeapAlignment },
1221 {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive },
1222 {CC"classKnownToNotExist",
1223 CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)Z",(void*)&WB_ClassKnownToNotExist},
1224 {CC"getLookupCacheURLs", CC"(Ljava/lang/ClassLoader;)[Ljava/net/URL;", (void*)&WB_GetLookupCacheURLs},
1225 {CC"getLookupCacheMatches", CC"(Ljava/lang/ClassLoader;Ljava/lang/String;)[I",
1226 (void*)&WB_GetLookupCacheMatches},
1227 {CC"parseCommandLine",
1228 CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;",
1229 (void*) &WB_ParseCommandLine
1230 },
1231 {CC"addToBootstrapClassLoaderSearch", CC"(Ljava/lang/String;)V",
1232 (void*)&WB_AddToBootstrapClassLoaderSearch},
1233 {CC"addToSystemClassLoaderSearch", CC"(Ljava/lang/String;)V",
1234 (void*)&WB_AddToSystemClassLoaderSearch},
1235 {CC"getCompressedOopsMaxHeapSize", CC"()J",
1236 (void*)&WB_GetCompressedOopsMaxHeapSize},
1237 {CC"printHeapSizes", CC"()V", (void*)&WB_PrintHeapSizes },
1238 {CC"runMemoryUnitTests", CC"()V", (void*)&WB_RunMemoryUnitTests},
1239 {CC"readFromNoaccessArea",CC"()V", (void*)&WB_ReadFromNoaccessArea},
1240 {CC"stressVirtualSpaceResize",CC"(JJJ)I", (void*)&WB_StressVirtualSpaceResize},
1241 {CC"isSharedClass", CC"(Ljava/lang/Class;)Z", (void*)&WB_IsSharedClass },
1242 #if INCLUDE_ALL_GCS
1243 {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark},
1244 {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous },
1245 {CC"g1NumMaxRegions", CC"()J", (void*)&WB_G1NumMaxRegions },
1246 {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions },
1247 {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize },
1248 {CC"g1StartConcMarkCycle", CC"()Z", (void*)&WB_G1StartMarkCycle },
1249 {CC"g1AuxiliaryMemoryUsage", CC"()Ljava/lang/management/MemoryUsage;",
1250 (void*)&WB_G1AuxiliaryMemoryUsage },
1251 #endif // INCLUDE_ALL_GCS
1252 #if INCLUDE_NMT
1253 {CC"NMTMalloc", CC"(J)J", (void*)&WB_NMTMalloc },
1254 {CC"NMTMallocWithPseudoStack", CC"(JI)J", (void*)&WB_NMTMallocWithPseudoStack},
1255 {CC"NMTMallocWithPseudoStackAndType", CC"(JII)J", (void*)&WB_NMTMallocWithPseudoStackAndType},
1256 {CC"NMTFree", CC"(J)V", (void*)&WB_NMTFree },
1257 {CC"NMTReserveMemory", CC"(J)J", (void*)&WB_NMTReserveMemory },
1258 {CC"NMTCommitMemory", CC"(JJ)V", (void*)&WB_NMTCommitMemory },
1259 {CC"NMTUncommitMemory", CC"(JJ)V", (void*)&WB_NMTUncommitMemory },
1260 {CC"NMTReleaseMemory", CC"(JJ)V", (void*)&WB_NMTReleaseMemory },
1261 {CC"NMTIsDetailSupported",CC"()Z", (void*)&WB_NMTIsDetailSupported},
1262 {CC"NMTChangeTrackingLevel", CC"()Z", (void*)&WB_NMTChangeTrackingLevel},
1263 {CC"NMTGetHashSize", CC"()I", (void*)&WB_NMTGetHashSize },
1264 {CC"NMTNewArena", CC"(J)J", (void*)&WB_NMTNewArena },
1265 {CC"NMTFreeArena", CC"(J)V", (void*)&WB_NMTFreeArena },
1266 {CC"NMTArenaMalloc", CC"(JJ)V", (void*)&WB_NMTArenaMalloc },
1267 #endif // INCLUDE_NMT
1268 {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll },
1269 {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Executable;Z)I",
1270 (void*)&WB_DeoptimizeMethod },
1271 {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Executable;Z)Z",
1272 (void*)&WB_IsMethodCompiled },
1273 {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Executable;IZ)Z",
1274 (void*)&WB_IsMethodCompilable},
1275 {CC"isMethodQueuedForCompilation",
1276 CC"(Ljava/lang/reflect/Executable;)Z", (void*)&WB_IsMethodQueuedForCompilation},
1277 {CC"makeMethodNotCompilable",
1278 CC"(Ljava/lang/reflect/Executable;IZ)V", (void*)&WB_MakeMethodNotCompilable},
1279 {CC"testSetDontInlineMethod",
1280 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetDontInlineMethod},
1281 {CC"getMethodCompilationLevel",
1282 CC"(Ljava/lang/reflect/Executable;Z)I", (void*)&WB_GetMethodCompilationLevel},
1283 {CC"getMethodEntryBci",
1284 CC"(Ljava/lang/reflect/Executable;)I", (void*)&WB_GetMethodEntryBci},
1285 {CC"getCompileQueueSize",
1286 CC"(I)I", (void*)&WB_GetCompileQueueSize},
1287 {CC"testSetForceInlineMethod",
1288 CC"(Ljava/lang/reflect/Executable;Z)Z", (void*)&WB_TestSetForceInlineMethod},
1289 {CC"enqueueMethodForCompilation0",
1290 CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation},
1291 {CC"enqueueInitializerForCompilation0",
1292 CC"(Ljava/lang/Class;I)Z", (void*)&WB_EnqueueInitializerForCompilation},
1293 {CC"clearMethodState",
1294 CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState},
1295 {CC"markMethodProfiled",
1296 CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_MarkMethodProfiled},
1297 {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag},
1298 {CC"setIntxVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetIntxVMFlag},
1299 {CC"setUintxVMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetUintxVMFlag},
1300 {CC"setUint64VMFlag", CC"(Ljava/lang/String;J)V",(void*)&WB_SetUint64VMFlag},
1301 {CC"setDoubleVMFlag", CC"(Ljava/lang/String;D)V",(void*)&WB_SetDoubleVMFlag},
1302 {CC"setStringVMFlag", CC"(Ljava/lang/String;Ljava/lang/String;)V",
1303 (void*)&WB_SetStringVMFlag},
1304 {CC"getBooleanVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Boolean;",
1305 (void*)&WB_GetBooleanVMFlag},
1306 {CC"getIntxVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;",
1307 (void*)&WB_GetIntxVMFlag},
1308 {CC"getUintxVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;",
1309 (void*)&WB_GetUintxVMFlag},
1310 {CC"getUint64VMFlag", CC"(Ljava/lang/String;)Ljava/lang/Long;",
1311 (void*)&WB_GetUint64VMFlag},
1312 {CC"getDoubleVMFlag", CC"(Ljava/lang/String;)Ljava/lang/Double;",
1313 (void*)&WB_GetDoubleVMFlag},
1314 {CC"getStringVMFlag", CC"(Ljava/lang/String;)Ljava/lang/String;",
1315 (void*)&WB_GetStringVMFlag},
1316 {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable },
1317 {CC"fullGC", CC"()V", (void*)&WB_FullGC },
1318 {CC"youngGC", CC"()V", (void*)&WB_YoungGC },
1319 {CC"readReservedMemory", CC"()V", (void*)&WB_ReadReservedMemory },
1320 {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob },
1321 {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob },
1322 {CC"getCodeBlob", CC"(J)[Ljava/lang/Object;",(void*)&WB_GetCodeBlob },
1323 {CC"allocateMetaspace",
1324 CC"(Ljava/lang/ClassLoader;J)J", (void*)&WB_AllocateMetaspace },
1325 {CC"freeMetaspace",
1326 CC"(Ljava/lang/ClassLoader;JJ)V", (void*)&WB_FreeMetaspace },
1327 {CC"incMetaspaceCapacityUntilGC", CC"(J)J", (void*)&WB_IncMetaspaceCapacityUntilGC },
1328 {CC"metaspaceCapacityUntilGC", CC"()J", (void*)&WB_MetaspaceCapacityUntilGC },
1329 {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures },
1330 {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;",
1331 (void*)&WB_GetNMethod },
1332 {CC"isMonitorInflated", CC"(Ljava/lang/Object;)Z", (void*)&WB_IsMonitorInflated },
1333 {CC"forceSafepoint", CC"()V", (void*)&WB_ForceSafepoint },
1334 {CC"checkLibSpecifiesNoexecstack", CC"(Ljava/lang/String;)Z",
1335 (void*)&WB_CheckLibSpecifiesNoexecstack},
1336 {CC"isContainerized", CC"()Z", (void*)&WB_IsContainerized },
1337 {CC"printOsInfo", CC"()V", (void*)&WB_PrintOsInfo },
1338 };
1339
1340 #undef CC
1341
JVM_ENTRY(void,JVM_RegisterWhiteBoxMethods (JNIEnv * env,jclass wbclass))1342 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass))
1343 {
1344 if (WhiteBoxAPI) {
1345 // Make sure that wbclass is loaded by the null classloader
1346 instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass());
1347 Handle loader(ikh->class_loader());
1348 if (loader.is_null()) {
1349 WhiteBox::register_methods(env, wbclass, thread, methods, sizeof(methods) / sizeof(methods[0]));
1350 WhiteBox::register_extended(env, wbclass, thread);
1351 WhiteBox::set_used();
1352 }
1353 }
1354 }
1355 JVM_END
1356