mgerdin@3619: /* mgerdin@3619: * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved. mgerdin@3619: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. mgerdin@3619: * mgerdin@3619: * This code is free software; you can redistribute it and/or modify it mgerdin@3619: * under the terms of the GNU General Public License version 2 only, as mgerdin@3619: * published by the Free Software Foundation. mgerdin@3619: * mgerdin@3619: * This code is distributed in the hope that it will be useful, but WITHOUT mgerdin@3619: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or mgerdin@3619: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License mgerdin@3619: * version 2 for more details (a copy is included in the LICENSE file that mgerdin@3619: * accompanied this code). mgerdin@3619: * mgerdin@3619: * You should have received a copy of the GNU General Public License version mgerdin@3619: * 2 along with this work; if not, write to the Free Software Foundation, mgerdin@3619: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. mgerdin@3619: * mgerdin@3619: * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA mgerdin@3619: * or visit www.oracle.com if you need additional information or have any mgerdin@3619: * questions. mgerdin@3619: * mgerdin@3619: */ mgerdin@3619: mgerdin@3619: #include "precompiled.hpp" mgerdin@3619: mgerdin@3619: #include "memory/universe.hpp" mgerdin@3619: #include "oops/oop.inline.hpp" nloodin@3681: nloodin@3681: #include "classfile/symbolTable.hpp" coleenp@4037: #include "classfile/classLoaderData.hpp" nloodin@3681: mgerdin@3619: #include "prims/whitebox.hpp" nloodin@3681: #include "prims/wbtestmethods/parserTests.hpp" nloodin@3681: mgerdin@3619: #include "runtime/interfaceSupport.hpp" mgerdin@3619: #include "runtime/os.hpp" mgerdin@3619: #include "utilities/debug.hpp" jprovino@4542: #include "utilities/macros.hpp" mgerdin@3619: jprovino@4542: #if INCLUDE_ALL_GCS mgerdin@3619: #include "gc_implementation/g1/concurrentMark.hpp" mgerdin@3619: #include "gc_implementation/g1/g1CollectedHeap.inline.hpp" mgerdin@3619: #include "gc_implementation/g1/heapRegionRemSet.hpp" jprovino@4542: #endif // INCLUDE_ALL_GCS mgerdin@3619: ctornqvi@4512: #ifdef INCLUDE_NMT ctornqvi@4512: #include "services/memTracker.hpp" ctornqvi@4512: #endif // INCLUDE_NMT ctornqvi@4512: iignatyev@4592: #include "compiler/compileBroker.hpp" iignatyev@4592: mgerdin@3619: bool WhiteBox::_used = false; mgerdin@3619: mgerdin@3619: WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) mgerdin@3619: return (jlong)(void*)JNIHandles::resolve(obj); mgerdin@3619: WB_END mgerdin@3619: mgerdin@3619: WB_ENTRY(jint, WB_GetHeapOopSize(JNIEnv* env, jobject o)) mgerdin@3619: return heapOopSize; mgerdin@3619: WB_END mgerdin@3619: coleenp@4037: coleenp@4037: class WBIsKlassAliveClosure : public KlassClosure { coleenp@4037: Symbol* _name; coleenp@4037: bool _found; coleenp@4037: public: coleenp@4037: WBIsKlassAliveClosure(Symbol* name) : _name(name), _found(false) {} coleenp@4037: coleenp@4037: void do_klass(Klass* k) { coleenp@4037: if (_found) return; coleenp@4037: Symbol* ksym = k->name(); coleenp@4037: if (ksym->fast_compare(_name) == 0) { coleenp@4037: _found = true; coleenp@4037: } coleenp@4037: } coleenp@4037: coleenp@4037: bool found() const { coleenp@4037: return _found; coleenp@4037: } coleenp@4037: }; coleenp@4037: coleenp@4037: WB_ENTRY(jboolean, WB_IsClassAlive(JNIEnv* env, jobject target, jstring name)) coleenp@4037: Handle h_name = JNIHandles::resolve(name); coleenp@4037: if (h_name.is_null()) return false; coleenp@4037: Symbol* sym = java_lang_String::as_symbol(h_name, CHECK_false); coleenp@4037: TempNewSymbol tsym(sym); // Make sure to decrement reference count on sym on return coleenp@4037: coleenp@4037: WBIsKlassAliveClosure closure(sym); coleenp@4037: ClassLoaderDataGraph::classes_do(&closure); coleenp@4037: coleenp@4037: return closure.found(); coleenp@4037: WB_END coleenp@4037: jprovino@4542: #if INCLUDE_ALL_GCS mgerdin@3619: WB_ENTRY(jboolean, WB_G1IsHumongous(JNIEnv* env, jobject o, jobject obj)) mgerdin@3619: G1CollectedHeap* g1 = G1CollectedHeap::heap(); mgerdin@3619: oop result = JNIHandles::resolve(obj); mgerdin@3619: const HeapRegion* hr = g1->heap_region_containing(result); mgerdin@3619: return hr->isHumongous(); mgerdin@3619: WB_END mgerdin@3619: mgerdin@3619: WB_ENTRY(jlong, WB_G1NumFreeRegions(JNIEnv* env, jobject o)) mgerdin@3619: G1CollectedHeap* g1 = G1CollectedHeap::heap(); mgerdin@3619: size_t nr = g1->free_regions(); mgerdin@3619: return (jlong)nr; mgerdin@3619: WB_END mgerdin@3619: mgerdin@3619: WB_ENTRY(jboolean, WB_G1InConcurrentMark(JNIEnv* env, jobject o)) mgerdin@3619: G1CollectedHeap* g1 = G1CollectedHeap::heap(); mgerdin@3619: ConcurrentMark* cm = g1->concurrent_mark(); mgerdin@3619: return cm->concurrent_marking_in_progress(); mgerdin@3619: WB_END mgerdin@3619: mgerdin@3619: WB_ENTRY(jint, WB_G1RegionSize(JNIEnv* env, jobject o)) mgerdin@3619: return (jint)HeapRegion::GrainBytes; mgerdin@3619: WB_END jprovino@4542: #endif // INCLUDE_ALL_GCS mgerdin@3619: ctornqvi@4512: #ifdef INCLUDE_NMT ctornqvi@4512: // Keep track of the 3 allocations in NMTAllocTest so we can free them later ctornqvi@4512: // on and verify that they're not visible anymore ctornqvi@4512: static void* nmtMtTest1 = NULL, *nmtMtTest2 = NULL, *nmtMtTest3 = NULL; ctornqvi@4512: ctornqvi@4512: // Alloc memory using the test memory type so that we can use that to see if ctornqvi@4512: // NMT picks it up correctly ctornqvi@4512: WB_ENTRY(jboolean, WB_NMTAllocTest(JNIEnv* env)) ctornqvi@4512: void *mem; ctornqvi@4512: ctornqvi@4512: if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { ctornqvi@4512: return false; ctornqvi@4512: } ctornqvi@4512: ctornqvi@4512: // Allocate 2 * 128k + 256k + 1024k and free the 1024k one to make sure we track ctornqvi@4512: // everything correctly. Total should be 512k held alive. ctornqvi@4512: nmtMtTest1 = os::malloc(128 * 1024, mtTest); ctornqvi@4512: mem = os::malloc(1024 * 1024, mtTest); ctornqvi@4512: nmtMtTest2 = os::malloc(256 * 1024, mtTest); ctornqvi@4512: os::free(mem, mtTest); ctornqvi@4512: nmtMtTest3 = os::malloc(128 * 1024, mtTest); ctornqvi@4512: ctornqvi@4512: return true; ctornqvi@4512: WB_END ctornqvi@4512: ctornqvi@4512: // Free the memory allocated by NMTAllocTest ctornqvi@4512: WB_ENTRY(jboolean, WB_NMTFreeTestMemory(JNIEnv* env)) ctornqvi@4512: ctornqvi@4512: if (nmtMtTest1 == NULL || nmtMtTest2 == NULL || nmtMtTest3 == NULL) { ctornqvi@4512: return false; ctornqvi@4512: } ctornqvi@4512: ctornqvi@4512: os::free(nmtMtTest1, mtTest); ctornqvi@4512: nmtMtTest1 = NULL; ctornqvi@4512: os::free(nmtMtTest2, mtTest); ctornqvi@4512: nmtMtTest2 = NULL; ctornqvi@4512: os::free(nmtMtTest3, mtTest); ctornqvi@4512: nmtMtTest3 = NULL; ctornqvi@4512: ctornqvi@4512: return true; ctornqvi@4512: WB_END ctornqvi@4512: ctornqvi@4512: // Block until the current generation of NMT data to be merged, used to reliably test the NMT feature ctornqvi@4512: WB_ENTRY(jboolean, WB_NMTWaitForDataMerge(JNIEnv* env)) ctornqvi@4512: ctornqvi@4512: if (!MemTracker::is_on() || MemTracker::shutdown_in_progress()) { ctornqvi@4512: return false; ctornqvi@4512: } ctornqvi@4512: ctornqvi@4512: return MemTracker::wbtest_wait_for_data_merge(); ctornqvi@4512: WB_END ctornqvi@4512: ctornqvi@4512: #endif // INCLUDE_NMT ctornqvi@4512: iignatyev@4592: static jmethodID reflected_method_to_jmid(JavaThread* thread, JNIEnv* env, jobject method) { iignatyev@4592: assert(method != NULL, "method should not be null"); iignatyev@4592: ThreadToNativeFromVM ttn(thread); iignatyev@4592: return env->FromReflectedMethod(method); iignatyev@4592: } iignatyev@4592: iignatyev@4592: WB_ENTRY(void, WB_DeoptimizeAll(JNIEnv* env, jobject o)) iignatyev@4592: MutexLockerEx mu(Compile_lock); iignatyev@4592: CodeCache::mark_all_nmethods_for_deoptimization(); iignatyev@4592: VM_Deoptimize op; iignatyev@4592: VMThread::execute(&op); iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jint, WB_DeoptimizeMethod(JNIEnv* env, jobject o, jobject method)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: MutexLockerEx mu(Compile_lock); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: int result = 0; iignatyev@4592: nmethod* code = mh->code(); iignatyev@4592: if (code != NULL) { iignatyev@4592: code->mark_for_deoptimization(); iignatyev@4592: ++result; iignatyev@4592: } iignatyev@4592: result += CodeCache::mark_for_deoptimization(mh()); iignatyev@4592: if (result > 0) { iignatyev@4592: VM_Deoptimize op; iignatyev@4592: VMThread::execute(&op); iignatyev@4592: } iignatyev@4592: return result; iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jboolean, WB_IsMethodCompiled(JNIEnv* env, jobject o, jobject method)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: MutexLockerEx mu(Compile_lock); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: nmethod* code = mh->code(); iignatyev@4592: if (code == NULL) { iignatyev@4592: return JNI_FALSE; iignatyev@4592: } iignatyev@4592: return (code->is_alive() && !code->is_marked_for_deoptimization()); iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jboolean, WB_IsMethodCompilable(JNIEnv* env, jobject o, jobject method)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: MutexLockerEx mu(Compile_lock); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: return !mh->is_not_compilable(); iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jboolean, WB_IsMethodQueuedForCompilation(JNIEnv* env, jobject o, jobject method)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: MutexLockerEx mu(Compile_lock); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: return mh->queued_for_compilation(); iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jint, WB_GetMethodCompilationLevel(JNIEnv* env, jobject o, jobject method)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: nmethod* code = mh->code(); iignatyev@4592: return (code != NULL ? code->comp_level() : CompLevel_none); iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: iignatyev@4592: WB_ENTRY(void, WB_MakeMethodNotCompilable(JNIEnv* env, jobject o, jobject method)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: mh->set_not_compilable(); iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jboolean, WB_SetDontInlineMethod(JNIEnv* env, jobject o, jobject method, jboolean value)) iignatyev@4592: jmethodID jmid = reflected_method_to_jmid(thread, env, method); iignatyev@4592: methodHandle mh(THREAD, Method::checked_resolve_jmethod_id(jmid)); iignatyev@4592: bool result = mh->dont_inline(); iignatyev@4592: mh->set_dont_inline(value == JNI_TRUE); iignatyev@4592: return result; iignatyev@4592: WB_END iignatyev@4592: iignatyev@4592: WB_ENTRY(jint, WB_GetCompileQueuesSize(JNIEnv* env, jobject o)) iignatyev@4592: return CompileBroker::queue_size(CompLevel_full_optimization) /* C2 */ + iignatyev@4592: CompileBroker::queue_size(CompLevel_full_profile) /* C1 */; iignatyev@4592: WB_END iignatyev@4592: mgerdin@4850: WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) mgerdin@4850: ResourceMark rm(THREAD); mgerdin@4850: int len; mgerdin@4850: jchar* name = java_lang_String::as_unicode_string(JNIHandles::resolve(javaString), len); mgerdin@4850: oop found_string = StringTable::the_table()->lookup(name, len); mgerdin@4850: if (found_string == NULL) { mgerdin@4850: return false; mgerdin@4850: } mgerdin@4850: return true; mgerdin@4850: WB_END mgerdin@4850: mgerdin@4850: mgerdin@4850: WB_ENTRY(void, WB_FullGC(JNIEnv* env, jobject o)) mgerdin@4850: Universe::heap()->collector_policy()->set_should_clear_all_soft_refs(true); mgerdin@4850: Universe::heap()->collect(GCCause::_last_ditch_collection); mgerdin@4850: WB_END mgerdin@4850: mgerdin@4850: nloodin@3681: //Some convenience methods to deal with objects from java nloodin@3681: int WhiteBox::offset_for_field(const char* field_name, oop object, nloodin@3681: Symbol* signature_symbol) { nloodin@3681: assert(field_name != NULL && strlen(field_name) > 0, "Field name not valid"); nloodin@3681: Thread* THREAD = Thread::current(); nloodin@3681: nloodin@3681: //Get the class of our object coleenp@4037: Klass* arg_klass = object->klass(); nloodin@3681: //Turn it into an instance-klass coleenp@4037: InstanceKlass* ik = InstanceKlass::cast(arg_klass); nloodin@3681: nloodin@3681: //Create symbols to look for in the class nloodin@3681: TempNewSymbol name_symbol = SymbolTable::lookup(field_name, (int) strlen(field_name), nloodin@3681: THREAD); nloodin@3681: nloodin@3681: //To be filled in with an offset of the field we're looking for nloodin@3681: fieldDescriptor fd; nloodin@3681: coleenp@4037: Klass* res = ik->find_field(name_symbol, signature_symbol, &fd); nloodin@3681: if (res == NULL) { nloodin@3681: tty->print_cr("Invalid layout of %s at %s", ik->external_name(), nloodin@3681: name_symbol->as_C_string()); nloodin@3681: fatal("Invalid layout of preloaded class"); nloodin@3681: } nloodin@3681: nloodin@3681: //fetch the field at the offset we've found nloodin@3681: int dest_offset = fd.offset(); nloodin@3681: nloodin@3681: return dest_offset; nloodin@3681: } nloodin@3681: nloodin@3681: nloodin@3681: const char* WhiteBox::lookup_jstring(const char* field_name, oop object) { nloodin@3681: int offset = offset_for_field(field_name, object, nloodin@3681: vmSymbols::string_signature()); nloodin@3681: oop string = object->obj_field(offset); sla@3905: if (string == NULL) { sla@3905: return NULL; sla@3905: } nloodin@3681: const char* ret = java_lang_String::as_utf8_string(string); nloodin@3681: return ret; nloodin@3681: } nloodin@3681: nloodin@3681: bool WhiteBox::lookup_bool(const char* field_name, oop object) { nloodin@3681: int offset = nloodin@3681: offset_for_field(field_name, object, vmSymbols::bool_signature()); nloodin@3681: bool ret = (object->bool_field(offset) == JNI_TRUE); nloodin@3681: return ret; nloodin@3681: } nloodin@3681: nloodin@3681: mgerdin@3619: #define CC (char*) mgerdin@3619: mgerdin@3619: static JNINativeMethod methods[] = { mgerdin@3619: {CC"getObjectAddress", CC"(Ljava/lang/Object;)J", (void*)&WB_GetObjectAddress }, mgerdin@3619: {CC"getHeapOopSize", CC"()I", (void*)&WB_GetHeapOopSize }, iignatyev@4592: {CC"isClassAlive0", CC"(Ljava/lang/String;)Z", (void*)&WB_IsClassAlive }, iignatyev@4592: {CC"parseCommandLine", iignatyev@4592: CC"(Ljava/lang/String;[Lsun/hotspot/parser/DiagnosticCommand;)[Ljava/lang/Object;", nloodin@3681: (void*) &WB_ParseCommandLine nloodin@3681: }, jprovino@4542: #if INCLUDE_ALL_GCS mgerdin@3619: {CC"g1InConcurrentMark", CC"()Z", (void*)&WB_G1InConcurrentMark}, mgerdin@3619: {CC"g1IsHumongous", CC"(Ljava/lang/Object;)Z", (void*)&WB_G1IsHumongous }, mgerdin@3619: {CC"g1NumFreeRegions", CC"()J", (void*)&WB_G1NumFreeRegions }, mgerdin@3619: {CC"g1RegionSize", CC"()I", (void*)&WB_G1RegionSize }, jprovino@4542: #endif // INCLUDE_ALL_GCS ctornqvi@4512: #ifdef INCLUDE_NMT ctornqvi@4512: {CC"NMTAllocTest", CC"()Z", (void*)&WB_NMTAllocTest }, ctornqvi@4512: {CC"NMTFreeTestMemory", CC"()Z", (void*)&WB_NMTFreeTestMemory }, ctornqvi@4512: {CC"NMTWaitForDataMerge",CC"()Z", (void*)&WB_NMTWaitForDataMerge}, ctornqvi@4512: #endif // INCLUDE_NMT iignatyev@4592: {CC"deoptimizeAll", CC"()V", (void*)&WB_DeoptimizeAll }, iignatyev@4592: {CC"deoptimizeMethod", CC"(Ljava/lang/reflect/Method;)I", iignatyev@4592: (void*)&WB_DeoptimizeMethod }, iignatyev@4592: {CC"isMethodCompiled", CC"(Ljava/lang/reflect/Method;)Z", iignatyev@4592: (void*)&WB_IsMethodCompiled }, iignatyev@4592: {CC"isMethodCompilable", CC"(Ljava/lang/reflect/Method;)Z", iignatyev@4592: (void*)&WB_IsMethodCompilable}, iignatyev@4592: {CC"isMethodQueuedForCompilation", iignatyev@4592: CC"(Ljava/lang/reflect/Method;)Z", (void*)&WB_IsMethodQueuedForCompilation}, iignatyev@4592: {CC"makeMethodNotCompilable", iignatyev@4592: CC"(Ljava/lang/reflect/Method;)V", (void*)&WB_MakeMethodNotCompilable}, iignatyev@4592: {CC"setDontInlineMethod", iignatyev@4592: CC"(Ljava/lang/reflect/Method;Z)Z", (void*)&WB_SetDontInlineMethod}, iignatyev@4592: {CC"getMethodCompilationLevel", iignatyev@4592: CC"(Ljava/lang/reflect/Method;)I", (void*)&WB_GetMethodCompilationLevel}, iignatyev@4592: {CC"getCompileQueuesSize", iignatyev@4592: CC"()I", (void*)&WB_GetCompileQueuesSize}, mgerdin@4850: {CC"isInStringTable", CC"(Ljava/lang/String;)Z", (void*)&WB_IsInStringTable }, mgerdin@4850: {CC"fullGC", CC"()V", (void*)&WB_FullGC }, mgerdin@3619: }; mgerdin@3619: mgerdin@3619: #undef CC mgerdin@3619: mgerdin@3619: JVM_ENTRY(void, JVM_RegisterWhiteBoxMethods(JNIEnv* env, jclass wbclass)) mgerdin@3619: { mgerdin@3619: if (WhiteBoxAPI) { mgerdin@3619: // Make sure that wbclass is loaded by the null classloader mgerdin@3619: instanceKlassHandle ikh = instanceKlassHandle(JNIHandles::resolve(wbclass)->klass()); mgerdin@3619: Handle loader(ikh->class_loader()); mgerdin@3619: if (loader.is_null()) { mgerdin@3619: ThreadToNativeFromVM ttnfv(thread); // can't be in VM when we call JNI mgerdin@3619: jint result = env->RegisterNatives(wbclass, methods, sizeof(methods)/sizeof(methods[0])); mgerdin@3619: if (result == 0) { mgerdin@3619: WhiteBox::set_used(); mgerdin@3619: } mgerdin@3619: } mgerdin@3619: } mgerdin@3619: } mgerdin@3619: JVM_END