1 /* 2 * Copyright (c) 2012, 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/universe.hpp" 28 #include "oops/oop.inline.hpp" 29 30 #include "classfile/symbolTable.hpp" 31 #include "classfile/classLoaderData.hpp" 32 33 #include "prims/whitebox.hpp" 34 #include "prims/wbtestmethods/parserTests.hpp" 35 36 #include "runtime/interfaceSupport.hpp" 37 #include "runtime/os.hpp" 38 #include "utilities/debug.hpp" 39 #include "utilities/macros.hpp" 40 41 #if INCLUDE_ALL_GCS 42 #include "gc_implementation/g1/concurrentMark.hpp" 43 #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" 44 #include "gc_implementation/g1/heapRegionRemSet.hpp" 45 #endif // INCLUDE_ALL_GCS 46 47 #ifdef INCLUDE_NMT 48 #include "services/memTracker.hpp" 49 #endif // INCLUDE_NMT 50 51 #include "compiler/compileBroker.hpp" 52 53 bool WhiteBox::_used = false; 54 55 WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) 56 return (jlong)(void*)JNIHandles::resolve(obj); 57 WB_END 58 59 WB_ENTRY(jint, WB_GetHeapOopSize(JNIEnv* env, jobject o)) 60 return heapOopSize; 61 WB_END 62 63 64 class WBIsKlassAliveClosure : public KlassClosure { 65 Symbol* _name; 66 bool _found; 67 public: 68 WBIsKlassAliveClosure(Symbol* name) : _name(name), _found(false) {} 69 70 void do_klass(Klass* k) { 71 if (_found) return; 72 Symbol* ksym = k->name(); 73 if (ksym->fast_compare(_name) == 0) { 74 _found = true; 75 } 76 } 77 78 bool found() const { 79 return _found; 80 } 81 }; 82 83 WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name)) 84 Handle h_name = JNIHandles::resolve(name); 85 if (h_name.is_null()) return false; 86 Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_false); 87 TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return 88 89 WBIsKlassAliveClosure closure(sym); 90 ClassLoaderDataGraph::classes_do(&closure); 91 92 return closure.found(); 93 WB_END 94 95 WB_ENTRY(void, WB_PrintHeapSizes(JNIEnv* env, jobject o)) { 96 CollectorPolicy * p = Universe::heap()->collector_policy(); 97 gclog_or_tty->print_cr("Minimum heap "SIZE_FORMAT" Initial heap " 98 SIZE_FORMAT" Maximum heap "SIZE_FORMAT" Min alignment "SIZE_FORMAT" Max alignment "SIZE_FORMAT, 99 p->min_heap_byte_size(), p->initial_heap_byte_size(), p->max_heap_byte_size(), 100 p->min_alignment(), p->max_alignment()); 101 } 102 WB_END 103 104 #if INCLUDE_ALL_GCS 105 WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) 106 G1CollectedHeap* g1 = G1CollectedHeap::heap(); 107 oop result = JNIHandles::resolve(obj); 108 const HeapRegion* hr = g1->heap_region_containing(result); 109 return hr->isHumongous(); 110 WB_END 111 112 WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o)) 113 G1CollectedHeap* g1 = G1CollectedHeap::heap(); 114 size_t nr = g1->free_regions(); 115 return (jlong)nr; 116 WB_END 117 118 WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) 119 G1CollectedHeap* g1 = G1CollectedHeap::heap(); 120 ConcurrentMark* cm = g1->concurrent_mark(); 121 return cm->concurrent_marking_in_progress(); 122 WB_END 123 124 WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) 125 return (jint)HeapRegion::GrainBytes; 126 WB_END 127 #endif // INCLUDE_ALL_GCS 128 129 #ifdef INCLUDE_NMT 130 // Keep track of the 3 allocations in NMTAllocTest so we can free them later 131 // on and verify that they're not visible anymore 132 static void* nmtMtTest1 = NULL, *nmtMtTest2 = NULL, *nmtMtTest3 = NULL; 133 134 // Alloc memory using the test memory type so that we can use that to see if 135 // NMT picks it up correctly 136 WB_ENTRY(jboolean, WB_NMTAllocTest(JNIEnv* env)) 137 void *mem; 138 139 if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { 140 return false; 141 } 142 143 // Allocate 2 * 128k + 256k + 1024k and free the 1024k one to make sure we track 144 // everything correctly. Total should be 512k held alive. 145 nmtMtTest1 = os::malloc(128 * 1024, mtTest); 146 mem = os::malloc(1024 * 1024, mtTest); 147 nmtMtTest2 = os::malloc(256 * 1024, mtTest); 148 os::free(mem, mtTest); 149 nmtMtTest3 = os::malloc(128 * 1024, mtTest); 150 151 return true; 152 WB_END 153 154 // Free the memory allocated by NMTAllocTest 155 WB_ENTRY(jboolean, WB_NMTFreeTestMemory(JNIEnv* env)) 156 157 if (nmtMtTest1 == NULL || nmtMtTest2 == NULL || nmtMtTest3 == NULL) { 158 return false; 159 } 160 161 os::free(nmtMtTest1, mtTest); 162 nmtMtTest1 = NULL; 163 os::free(nmtMtTest2, mtTest); 164 nmtMtTest2 = NULL; 165 os::free(nmtMtTest3, mtTest); 166 nmtMtTest3 = NULL; 167 168 return true; 169 WB_END 170 171 // Block until the current generation of NMT data to be merged, used to reliably test the NMT feature 172 WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env)) 173 174 if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { 175 return false; 176 } 177 178 return MemTracker::wbtest_wait_for_data_merge(); 179 WB_END 180 181 #endif // INCLUDE_NMT 182 183 static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { 184 assert(method != NULL, "method should not be null"); 185 ThreadToNativeFromVM ttn(thread); 186 return env->FromReflectedMethod(method); 187 } 188 189 WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o)) 190 MutexLockerEx mu(Compile_lock); 191 CodeCache::mark_all_nmethods_for_deoptimization(); 192 VM_Deoptimize op; 193 VMThread::execute(&op); 194 WB_END 195 196 WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method)) 197 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 198 MutexLockerEx mu(Compile_lock); 199 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 200 int result = 0; 201 nmethod* code = mh->code(); 202 if (code != NULL) { 203 code->mark_for_deoptimization(); 204 ++result; 205 } 206 result += CodeCache::mark_for_deoptimization(mh()); 207 if (result > 0) { 208 VM_Deoptimize op; 209 VMThread::execute(&op); 210 } 211 return result; 212 WB_END 213 214 WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method)) 215 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 216 MutexLockerEx mu(Compile_lock); 217 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 218 nmethod* code = mh->code(); 219 if (code == NULL) { 220 return JNI_FALSE; 221 } 222 return (code->is_alive() && !code->is_marked_for_deoptimization()); 223 WB_END 224 225 WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method)) 226 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 227 MutexLockerEx mu(Compile_lock); 228 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 229 return !mh->is_not_compilable(); 230 WB_END 231 232 WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method)) 233 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 234 MutexLockerEx mu(Compile_lock); 235 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 236 return mh->queued_for_compilation(); 237 WB_END 238 239 WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method)) 240 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 241 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 242 nmethod* code = mh->code(); 243 return (code != NULL ? code->comp_level() : CompLevel_none); 244 WB_END 245 246 247 WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method)) 248 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 249 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 250 mh->set_not_compilable(); 251 WB_END 252 253 WB_ENTRY(jboolean, WB_SetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) 254 jmethodID jmid = reflected_method_to_jmid(thread, env, method); 255 methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); 256 bool result = mh->dont_inline(); 257 mh->set_dont_inline(value == JNI_TRUE); 258 return result; 259 WB_END 260 261 WB_ENTRY(jint, WB_GetCompileQueuesSize(JNIEnv* env, jobject o)) 262 return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ + 263 CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; 264 WB_END 265 266 WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) 267 ResourceMark rm(THREAD); 268 int len; 269 jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len); 270 oop found_string = StringTable::the_table()->lookup(name, len); 271 if (found_string == NULL) { 272 return false; 273 } 274 return true; 275 WB_END 276 277 278 WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) 279 Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true); 280 Universe::heap()->collect(GCCause::_last_ditch_collection); 281 WB_END 282 283 284 //Some convenience methods to deal with objects from java 285 int WhiteBox::offset_for_field(const char* field_name, oop object, 286 Symbol* signature_symbol) { 287 assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid"); 288 Thread* THREAD = Thread::current(); 289 290 //Get the class of our object 291 Klass* arg_klass = object->klass(); 292 //Turn it into an instance-klass 293 InstanceKlass* ik = InstanceKlass::cast(arg_klass); 294 295 //Create symbols to look for in the class 296 TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name), 297 THREAD); 298 299 //To be filled in with an offset of the field we're looking for 300 fieldDescriptor fd; 301 302 Klass* res = ik->find_field(name_symbol, signature_symbol, &fd); 303 if (res == NULL) { 304 tty->print_cr("Invalid layout of %s at %s", ik->external_name(), 305 name_symbol->as_C_string()); 306 fatal("Invalid layout of preloaded class"); 307 } 308 309 //fetch the field at the offset we've found 310 int dest_offset = fd.offset(); 311 312 return dest_offset; 313 } 314 315 316 const char* WhiteBox::lookup_jstring(const char* field_name, oop object) { 317 int offset = offset_for_field(field_name, object, 318 vmSymbols::string_signature()); 319 oop string = object->obj_field(offset); 320 if (string == NULL) { 321 return NULL; 322 } 323 const char* ret = java_lang_String::as_utf8_string(string); 324 return ret; 325 } 326 327 bool WhiteBox::lookup_bool(const char* field_name, oop object) { 328 int offset = 329 offset_for_field(field_name, object, vmSymbols::bool_signature()); 330 bool ret = (object->bool_field(offset) == JNI_TRUE); 331 return ret; 332 } 333 334 335 #define CC (char*) 336 337 static JNINativeMethod methods[] = { 338 {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, 339 {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, 340 {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, 341 {CC"parseCommandLine", 342 CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", 343 (void*) &WB_ParseCommandLine 344 }, 345 {CC"printHeapSizes", CC"()V", (void*)&WB_PrintHeapSizes }, 346 #if INCLUDE_ALL_GCS 347 {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, 348 {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, 349 {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, 350 {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, 351 #endif // INCLUDE_ALL_GCS 352 #ifdef INCLUDE_NMT 353 {CC"NMTAllocTest", CC"()Z", (void*)&WB_NMTAllocTest }, 354 {CC"NMTFreeTestMemory", CC"()Z", (void*)&WB_NMTFreeTestMemory }, 355 {CC"NMTWaitForDataMerge",CC"()Z", (void*)&WB_NMTWaitForDataMerge}, 356 #endif // INCLUDE_NMT 357 {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, 358 {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Method;)I", 359 (void*)&WB_DeoptimizeMethod }, 360 {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Method;)Z", 361 (void*)&WB_IsMethodCompiled }, 362 {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Method;)Z", 363 (void*)&WB_IsMethodCompilable}, 364 {CC"isMethodQueuedForCompilation", 365 CC"(Ljava/lang/reflect/Method;)Z", (void*)&WB_IsMethodQueuedForCompilation}, 366 {CC"makeMethodNotCompilable", 367 CC"(Ljava/lang/reflect/Method;)V", (void*)&WB_MakeMethodNotCompilable}, 368 {CC"setDontInlineMethod", 369 CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_SetDontInlineMethod}, 370 {CC"getMethodCompilationLevel", 371 CC"(Ljava/lang/reflect/Method;)I", (void*)&WB_GetMethodCompilationLevel}, 372 {CC"getCompileQueuesSize", 373 CC"()I", (void*)&WB_GetCompileQueuesSize}, 374 {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, 375 {CC"fullGC", CC"()V", (void*)&WB_FullGC }, 376 }; 377 378 #undef CC 379 380 JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass)) 381 { 382 if (WhiteBoxAPI) { 383 // Make sure that wbclass is loaded by the null classloader 384 instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass()); 385 Handle loader(ikh->class_loader()); 386 if (loader.is_null()) { 387 ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI 388 jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0])); 389 if (result == 0) { 390 WhiteBox::set_used(); 391 } 392 } 393 } 394 } 395 JVM_END