# HG changeset patch # User iignatyev # Date 1415635478 -10800 # Node ID 8c9eff69314546f9638ebc37bb4aa2c387167a31 # Parent fca9ac607ebce2d12cb1956d85102154c369b742 8059624: Test task: WhiteBox API for testing segmented codecache feature Reviewed-by: kvn, thartmann diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/code/codeBlob.cpp --- a/hotspot/src/share/vm/code/codeBlob.cpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/code/codeBlob.cpp Mon Nov 10 19:04:38 2014 +0300 @@ -43,7 +43,7 @@ #include "c1/c1_Runtime1.hpp" #endif -unsigned int align_code_offset(int offset) { +unsigned int CodeBlob::align_code_offset(int offset) { // align the size to CodeEntryAlignment return ((offset + (int)CodeHeap::header_size() + (CodeEntryAlignment-1)) & ~(CodeEntryAlignment-1)) diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/code/codeBlob.hpp --- a/hotspot/src/share/vm/code/codeBlob.hpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/code/codeBlob.hpp Mon Nov 10 19:04:38 2014 +0300 @@ -83,6 +83,7 @@ public: // Returns the space needed for CodeBlob static unsigned int allocation_size(CodeBuffer* cb, int header_size); + static unsigned int align_code_offset(int offset); // Creation // a) simple CodeBlob @@ -207,7 +208,7 @@ } }; - +class WhiteBox; //---------------------------------------------------------------------------------------------------- // BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc. @@ -215,6 +216,7 @@ friend class VMStructs; friend class AdapterBlob; friend class MethodHandlesAdapterBlob; + friend class WhiteBox; private: // Creation support diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/code/codeCache.cpp --- a/hotspot/src/share/vm/code/codeCache.cpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/code/codeCache.cpp Mon Nov 10 19:04:38 2014 +0300 @@ -305,7 +305,7 @@ MemoryService::add_code_heap_memory_pool(heap, name); } -CodeHeap* CodeCache::get_code_heap(CodeBlob* cb) { +CodeHeap* CodeCache::get_code_heap(const CodeBlob* cb) { assert(cb != NULL, "CodeBlob is null"); FOR_ALL_HEAPS(heap) { if ((*heap)->contains(cb)) { diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/code/codeCache.hpp --- a/hotspot/src/share/vm/code/codeCache.hpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/code/codeCache.hpp Mon Nov 10 19:04:38 2014 +0300 @@ -77,6 +77,7 @@ class CodeCache : AllStatic { friend class VMStructs; friend class NMethodIterator; + friend class WhiteBox; private: // CodeHeaps of the cache static GrowableArray* _heaps; @@ -98,7 +99,7 @@ static void initialize_heaps(); // Initializes the CodeHeaps // Creates a new heap with the given name and size, containing CodeBlobs of the given type static void add_heap(ReservedSpace rs, const char* name, size_t size_initial, int code_blob_type); - static CodeHeap* get_code_heap(CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob + static CodeHeap* get_code_heap(const CodeBlob* cb); // Returns the CodeHeap for the given CodeBlob static CodeHeap* get_code_heap(int code_blob_type); // Returns the CodeHeap for the given CodeBlobType // Returns the name of the VM option to set the size of the corresponding CodeHeap static const char* get_code_heap_flag_name(int code_blob_type); diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/compiler/compileBroker.cpp --- a/hotspot/src/share/vm/compiler/compileBroker.cpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/compiler/compileBroker.cpp Mon Nov 10 19:04:38 2014 +0300 @@ -35,6 +35,7 @@ #include "oops/method.hpp" #include "oops/oop.inline.hpp" #include "prims/nativeLookup.hpp" +#include "prims/whitebox.hpp" #include "runtime/arguments.hpp" #include "runtime/atomic.inline.hpp" #include "runtime/compilationPolicy.hpp" @@ -1963,6 +1964,12 @@ if (comp == NULL) { ci_env.record_method_not_compilable("no compiler", !TieredCompilation); } else { + if (WhiteBoxAPI && WhiteBox::compilation_locked) { + MonitorLockerEx locker(Compilation_lock, Mutex::_no_safepoint_check_flag); + while (WhiteBox::compilation_locked) { + locker.wait(Mutex::_no_safepoint_check_flag); + } + } comp->compile_method(&ci_env, target, osr_bci); } diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/prims/whitebox.cpp --- a/hotspot/src/share/vm/prims/whitebox.cpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/prims/whitebox.cpp Mon Nov 10 19:04:38 2014 +0300 @@ -24,6 +24,8 @@ #include "precompiled.hpp" +#include + #include "code/codeCache.hpp" #include "memory/metadataFactory.hpp" #include "memory/universe.hpp" @@ -37,9 +39,11 @@ #include "runtime/thread.hpp" #include "runtime/arguments.hpp" +#include "runtime/deoptimization.hpp" #include "runtime/interfaceSupport.hpp" #include "runtime/os.hpp" #include "runtime/vm_version.hpp" +#include "runtime/sweeper.hpp" #include "utilities/array.hpp" #include "utilities/debug.hpp" @@ -67,6 +71,7 @@ #define SIZE_T_MAX_VALUE ((size_t) -1) bool WhiteBox::_used = false; +volatile bool WhiteBox::compilation_locked = false; WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) return (jlong)(void*)JNIHandles::resolve(obj); @@ -302,13 +307,12 @@ WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) jlong addr = 0; - addr = (jlong)(uintptr_t)os::reserve_memory(size); - MemTracker::record_virtual_memory_type((address)addr, mtTest); + addr = (jlong)(uintptr_t)os::reserve_memory(size); + MemTracker::record_virtual_memory_type((address)addr, mtTest); return addr; WB_END - WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem); MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest); @@ -728,6 +732,29 @@ WB_END +WB_ENTRY(void, WB_LockCompilation(JNIEnv* env, jobject o, jlong timeout)) + WhiteBox::compilation_locked = true; +WB_END + +WB_ENTRY(void, WB_UnlockCompilation(JNIEnv* env, jobject o)) + MonitorLockerEx mo(Compilation_lock, Mutex::_no_safepoint_check_flag); + WhiteBox::compilation_locked = false; + mo.notify_all(); +WB_END + +void WhiteBox::force_sweep() { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + NMethodSweeper::_should_sweep = true; + } + NMethodSweeper::possibly_sweep(); +} + +WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o)) + WhiteBox::force_sweep(); +WB_END + WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString)) ResourceMark rm(THREAD); int len; @@ -774,6 +801,46 @@ return features_string; WB_END +int WhiteBox::get_blob_type(const CodeBlob* code) { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + return CodeCache::get_code_heap(code)->code_blob_type(); +} + +CodeHeap* WhiteBox::get_code_heap(int blob_type) { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + return CodeCache::get_code_heap(blob_type); +} + +struct CodeBlobStub { + CodeBlobStub(const CodeBlob* blob) : + name(os::strdup(blob->name())), + size(blob->size()), + blob_type(WhiteBox::get_blob_type(blob)) { } + ~CodeBlobStub() { os::free((void*) name); } + const char* const name; + const int size; + const int blob_type; +}; + +static jobjectArray codeBlob2objectArray(JavaThread* thread, JNIEnv* env, CodeBlobStub* cb) { + jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + jobjectArray result = env->NewObjectArray(3, clazz, NULL); + + jstring name = env->NewStringUTF(cb->name); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 0, name); + + jobject obj = integerBox(thread, env, cb->size); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 1, obj); + + obj = integerBox(thread, env, cb->blob_type); + CHECK_JNI_EXCEPTION_(env, NULL); + env->SetObjectArrayElement(result, 2, obj); + + return result; +} WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr)) ResourceMark rm(THREAD); @@ -790,24 +857,90 @@ ThreadToNativeFromVM ttn(thread); jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); CHECK_JNI_EXCEPTION_(env, NULL); - result = env->NewObjectArray(3, clazz, NULL); + result = env->NewObjectArray(4, clazz, NULL); if (result == NULL) { return result; } + CodeBlobStub stub(code); + jobjectArray codeBlob = codeBlob2objectArray(thread, env, &stub); + env->SetObjectArrayElement(result, 0, codeBlob); + jobject level = integerBox(thread, env, code->comp_level()); CHECK_JNI_EXCEPTION_(env, NULL); - env->SetObjectArrayElement(result, 0, level); + env->SetObjectArrayElement(result, 1, level); jbyteArray insts = env->NewByteArray(insts_size); CHECK_JNI_EXCEPTION_(env, NULL); env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin()); - env->SetObjectArrayElement(result, 1, insts); + env->SetObjectArrayElement(result, 2, insts); jobject id = integerBox(thread, env, code->compile_id()); CHECK_JNI_EXCEPTION_(env, NULL); - env->SetObjectArrayElement(result, 2, id); + env->SetObjectArrayElement(result, 3, id); + + return result; +WB_END + +CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) { + guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled"); + BufferBlob* blob; + int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob)); + if (full_size < size) { + full_size += round_to(size - full_size, oopSize); + } + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type); + } + // Track memory usage statistic after releasing CodeCache_lock + MemoryService::track_code_cache_memory_usage(); + ::new (blob) BufferBlob("WB::DummyBlob", full_size); + return blob; +} + +WB_ENTRY(jlong, WB_AllocateCodeBlob(JNIEnv* env, jobject o, jint size, jint blob_type)) + return (jlong) WhiteBox::allocate_code_blob(size, blob_type); +WB_END + +WB_ENTRY(void, WB_FreeCodeBlob(JNIEnv* env, jobject o, jlong addr)) + BufferBlob::free((BufferBlob*) addr); +WB_END +WB_ENTRY(jobjectArray, WB_GetCodeHeapEntries(JNIEnv* env, jobject o, jint blob_type)) + ResourceMark rm; + GrowableArray blobs; + { + MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag); + CodeHeap* heap = WhiteBox::get_code_heap(blob_type); + if (heap == NULL) { + return NULL; + } + for (CodeBlob* cb = (CodeBlob*) heap->first(); + cb != NULL; cb = (CodeBlob*) heap->next(cb)) { + CodeBlobStub* stub = NEW_RESOURCE_OBJ(CodeBlobStub); + new (stub) CodeBlobStub(cb); + blobs.append(stub); + } + } + if (blobs.length() == 0) { + return NULL; + } + ThreadToNativeFromVM ttn(thread); + jobjectArray result = NULL; + jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); + CHECK_JNI_EXCEPTION_(env, NULL); + result = env->NewObjectArray(blobs.length(), clazz, NULL); + if (result == NULL) { + return result; + } + int i = 0; + for (GrowableArrayIterator it = blobs.begin(); + it != blobs.end(); ++it) { + jobjectArray obj = codeBlob2objectArray(thread, env, *it); + env->SetObjectArrayElement(result, i, obj); + ++i; + } return result; WB_END @@ -1018,6 +1151,8 @@ CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, {CC"clearMethodState", CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_ClearMethodState}, + {CC"lockCompilation", CC"()V", (void*)&WB_LockCompilation}, + {CC"unlockCompilation", CC"()V", (void*)&WB_UnlockCompilation}, {CC"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, @@ -1055,6 +1190,10 @@ {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", (void*)&WB_GetNMethod }, + {CC"forceNMethodSweep", CC"()V", (void*)&WB_ForceNMethodSweep }, + {CC"allocateCodeBlob", CC"(II)J", (void*)&WB_AllocateCodeBlob }, + {CC"freeCodeBlob", CC"(J)V", (void*)&WB_FreeCodeBlob }, + {CC"getCodeHeapEntries", CC"(I)[Ljava/lang/Object;",(void*)&WB_GetCodeHeapEntries }, {CC"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, }; diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/prims/whitebox.hpp --- a/hotspot/src/share/vm/prims/whitebox.hpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/prims/whitebox.hpp Mon Nov 10 19:04:38 2014 +0300 @@ -54,17 +54,24 @@ } \ } while (0) +class CodeBlob; +class CodeHeap; + class WhiteBox : public AllStatic { private: static bool _used; public: + static volatile bool compilation_locked; static bool used() { return _used; } static void set_used() { _used = true; } static int offset_for_field(const char* field_name, oop object, Symbol* signature_symbol); static const char* lookup_jstring(const char* field_name, oop object); static bool lookup_bool(const char* field_name, oop object); - + static void force_sweep(); + static int get_blob_type(const CodeBlob* code); + static CodeHeap* get_code_heap(int blob_type); + static CodeBlob* allocate_code_blob(int blob_type, int size); static int array_bytes_to_length(size_t bytes); static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread, JNINativeMethod* method_array, int method_count); diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/runtime/mutexLocker.cpp --- a/hotspot/src/share/vm/runtime/mutexLocker.cpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/runtime/mutexLocker.cpp Mon Nov 10 19:04:38 2014 +0300 @@ -88,6 +88,7 @@ Mutex* Compile_lock = NULL; Monitor* MethodCompileQueue_lock = NULL; Monitor* CompileThread_lock = NULL; +Monitor* Compilation_lock = NULL; Mutex* CompileTaskAlloc_lock = NULL; Mutex* CompileStatistics_lock = NULL; Mutex* MultiArray_lock = NULL; @@ -278,7 +279,9 @@ def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(CompileThread_lock , Monitor, nonleaf+5, false ); def(PeriodicTask_lock , Monitor, nonleaf+5, true); - + if (WhiteBoxAPI) { + def(Compilation_lock , Monitor, leaf, false ); + } #ifdef INCLUDE_TRACE def(JfrMsg_lock , Monitor, leaf, true); def(JfrBuffer_lock , Mutex, leaf, true); diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/runtime/mutexLocker.hpp --- a/hotspot/src/share/vm/runtime/mutexLocker.hpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/runtime/mutexLocker.hpp Mon Nov 10 19:04:38 2014 +0300 @@ -91,6 +91,7 @@ extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc) extern Monitor* MethodCompileQueue_lock; // a lock held when method compilations are enqueued, dequeued extern Monitor* CompileThread_lock; // a lock held by compile threads during compilation system initialization +extern Monitor* Compilation_lock; // a lock used to pause compilation extern Mutex* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays diff -r fca9ac607ebc -r 8c9eff693145 hotspot/src/share/vm/runtime/sweeper.hpp --- a/hotspot/src/share/vm/runtime/sweeper.hpp Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/src/share/vm/runtime/sweeper.hpp Mon Nov 10 19:04:38 2014 +0300 @@ -25,6 +25,8 @@ #ifndef SHARE_VM_RUNTIME_SWEEPER_HPP #define SHARE_VM_RUNTIME_SWEEPER_HPP +class WhiteBox; + #include "utilities/ticks.hpp" // An NmethodSweeper is an incremental cleaner for: // - cleanup inline caches @@ -52,6 +54,8 @@ // nmethod's space is freed. class NMethodSweeper : public AllStatic { + friend class WhiteBox; + private: static long _traversals; // Stack scan count, also sweep ID. static long _total_nof_code_cache_sweeps; // Total number of full sweeps of the code cache static long _time_counter; // Virtual time used to periodically invoke sweeper @@ -88,7 +92,6 @@ static void handle_safepoint_request(); static void do_stack_scanning(); static void possibly_sweep(); - public: static long traversal_count() { return _traversals; } static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java Mon Nov 10 19:04:38 2014 +0300 @@ -0,0 +1,128 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.lang.management.MemoryPoolMXBean; +import java.util.EnumSet; +import java.util.ArrayList; + +import sun.hotspot.WhiteBox; +import sun.hotspot.code.BlobType; +import com.oracle.java.testlibrary.Asserts; + +/* + * @test AllocationCodeBlobTest + * @bug 8059624 + * @library /testlibrary /testlibrary/whitebox + * @build AllocationCodeBlobTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:-SegmentedCodeCache AllocationCodeBlobTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,null::* + * -XX:+SegmentedCodeCache AllocationCodeBlobTest + * @summary testing of WB::allocate/freeCodeBlob() + */ +public class AllocationCodeBlobTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final long CODE_CACHE_SIZE + = WHITE_BOX.getUintxVMFlag("ReservedCodeCacheSize"); + private static final int SIZE = 1; + + public static void main(String[] args) { + // check that Sweeper handels dummy blobs correctly + new ForcedSweeper(500).start(); + EnumSet blobTypes = BlobType.getAvailable(); + for (BlobType type : blobTypes) { + new AllocationCodeBlobTest(type).test(); + } + } + + private final BlobType type; + private final MemoryPoolMXBean bean; + private AllocationCodeBlobTest(BlobType type) { + this.type = type; + bean = type.getMemoryPool(); + } + + private void test() { + System.out.printf("type %s%n", type); + long start = getUsage(); + long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id); + Asserts.assertNE(0, addr, "allocation failed"); + + long firstAllocation = getUsage(); + Asserts.assertLTE(start + SIZE, firstAllocation, + "allocation should increase memory usage: " + + start + " + " + SIZE + " <= " + firstAllocation); + + WHITE_BOX.freeCodeBlob(addr); + long firstFree = getUsage(); + Asserts.assertLTE(firstFree, firstAllocation, + "free shouldn't increase memory usage: " + + firstFree + " <= " + firstAllocation); + + addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id); + Asserts.assertNE(0, addr, "allocation failed"); + + long secondAllocation = getUsage(); + Asserts.assertEQ(firstAllocation, secondAllocation); + + WHITE_BOX.freeCodeBlob(addr); + System.out.println("allocating till possible..."); + ArrayList blobs = new ArrayList<>(); + int size = (int) (CODE_CACHE_SIZE >> 7); + while ((addr = WHITE_BOX.allocateCodeBlob(size, type.id)) != 0) { + blobs.add(addr); + } + for (Long blob : blobs) { + WHITE_BOX.freeCodeBlob(blob); + } + } + + private long getUsage() { + return bean.getUsage().getUsed(); + } + + private static class ForcedSweeper extends Thread { + private final int millis; + public ForcedSweeper(int millis) { + super("ForcedSweeper"); + setDaemon(true); + this.millis = millis; + } + public void run() { + try { + while (true) { + WHITE_BOX.forceNMethodSweep(); + Thread.sleep(millis); + } + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new Error(e); + } + } + } +} diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/whitebox/GetCodeHeapEntriesTest.java Mon Nov 10 19:04:38 2014 +0300 @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +import java.util.Arrays; +import java.util.EnumSet; + +import sun.hotspot.WhiteBox; +import sun.hotspot.code.CodeBlob; +import sun.hotspot.code.BlobType; +import com.oracle.java.testlibrary.Asserts; + +/* + * @test GetCodeHeapEntriesTest + * @bug 8059624 + * @library /testlibrary /testlibrary/whitebox + * @build GetCodeHeapEntriesTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:-SegmentedCodeCache + * GetCodeHeapEntriesTest + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions + * -XX:+WhiteBoxAPI -XX:+SegmentedCodeCache + * GetCodeHeapEntriesTest + * @summary testing of WB::getCodeHeapEntries() + */ +public class GetCodeHeapEntriesTest { + private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); + private static final int SIZE = 1024; + private static final String DUMMY_NAME = "WB::DummyBlob"; + private static EnumSet SEGMENTED_TYPES + = EnumSet.complementOf(EnumSet.of(BlobType.All)); + + public static void main(String[] args) { + EnumSet blobTypes = BlobType.getAvailable(); + for (BlobType type : blobTypes) { + new GetCodeHeapEntriesTest(type).test(); + } + } + + private final BlobType type; + private GetCodeHeapEntriesTest(BlobType type) { + this.type = type; + } + + private void test() { + System.out.printf("type %s%n", type); + long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id); + Asserts.assertNE(0, addr, "allocation failed"); + CodeBlob[] blobs = CodeBlob.getCodeBlobs(type); + Asserts.assertNotNull(blobs); + CodeBlob blob = Arrays.stream(blobs) + .filter(GetCodeHeapEntriesTest::filter) + .findAny() + .get(); + Asserts.assertNotNull(blob); + Asserts.assertEQ(blob.code_blob_type, type); + Asserts.assertGTE(blob.size, SIZE); + + WHITE_BOX.freeCodeBlob(addr); + blobs = CodeBlob.getCodeBlobs(type); + long count = Arrays.stream(blobs) + .filter(GetCodeHeapEntriesTest::filter) + .count(); + Asserts.assertEQ(0L, count); + } + + private static boolean filter(CodeBlob blob) { + if (blob == null) { + return false; + } + return DUMMY_NAME.equals(blob.name); + } +} diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/compiler/whitebox/GetNMethodTest.java --- a/hotspot/test/compiler/whitebox/GetNMethodTest.java Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/test/compiler/whitebox/GetNMethodTest.java Mon Nov 10 19:04:38 2014 +0300 @@ -22,7 +22,9 @@ * */ +import sun.hotspot.code.BlobType; import sun.hotspot.code.NMethod; +import com.oracle.java.testlibrary.Asserts; /* * @test GetNMethodTest @@ -52,21 +54,46 @@ compile(); checkCompiled(); + NMethod nmethod = NMethod.get(method, testCase.isOsr()); if (IS_VERBOSE) { System.out.println("nmethod = " + nmethod); } - if (nmethod == null) { - throw new RuntimeException("nmethod of compiled method is null"); + Asserts.assertNotNull(nmethod, + "nmethod of compiled method is null"); + Asserts.assertNotNull(nmethod.insts, + "nmethod.insts of compiled method is null"); + Asserts.assertGT(nmethod.insts.length, 0, + "compiled method's instructions is empty"); + Asserts.assertNotNull(nmethod.code_blob_type, "blob type is null"); + if (WHITE_BOX.getBooleanVMFlag("SegmentedCodeCache")) { + Asserts.assertNE(nmethod.code_blob_type, BlobType.All); + switch (nmethod.comp_level) { + case 1: + case 4: + checkBlockType(nmethod, BlobType.MethodNonProfiled); + break; + case 2: + case 3: + checkBlockType(nmethod, BlobType.MethodNonProfiled); + break; + default: + throw new Error("unexpected comp level " + nmethod); + } + } else { + Asserts.assertEQ(nmethod.code_blob_type, BlobType.All); } - if (nmethod.insts.length == 0) { - throw new RuntimeException("compiled method's instructions is empty"); - } + deoptimize(); checkNotCompiled(); nmethod = NMethod.get(method, testCase.isOsr()); - if (nmethod != null) { - throw new RuntimeException("nmethod of non-compiled method isn't null"); - } + Asserts.assertNull(nmethod, + "nmethod of non-compiled method isn't null"); + } + + private void checkBlockType(NMethod nmethod, BlobType expectedType) { + Asserts.assertEQ(nmethod.code_blob_type, expectedType, + String.format("blob_type[%s] for %d level isn't %s", + nmethod.code_blob_type, nmethod.comp_level, expectedType)); } } diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/compiler/whitebox/LockCompilationTest.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/compiler/whitebox/LockCompilationTest.java Mon Nov 10 19:04:38 2014 +0300 @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * @test LockCompilationTest + * @bug 8059624 + * @library /testlibrary /testlibrary/whitebox + * @build LockCompilationTest + * @run main ClassFileInstaller sun.hotspot.WhiteBox + * sun.hotspot.WhiteBox$WhiteBoxPermission + * @run main/othervm/timeout=600 -Xbootclasspath/a:. -Xmixed -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -XX:CompileCommand=compileonly,SimpleTestCase$Helper::* LockCompilationTest + * @summary testing of WB::lock/unlockCompilation() + */ + +import java.io.OutputStream; +import java.io.PrintWriter; +import java.util.concurrent.BrokenBarrierException; +import java.util.concurrent.CyclicBarrier; + +import com.oracle.java.testlibrary.Asserts; + +public class LockCompilationTest extends CompilerWhiteBoxTest { + public static void main(String[] args) throws Exception { + CompilerWhiteBoxTest.main(LockCompilationTest::new, args); + } + + private LockCompilationTest(TestCase testCase) { + super(testCase); + // to prevent inlining of #method + WHITE_BOX.testSetDontInlineMethod(method, true); + } + + protected void test() throws Exception { + checkNotCompiled(); + + System.out.println("locking compilation"); + WHITE_BOX.lockCompilation(); + + try { + System.out.println("trying to compile"); + compile(); + // to check if it works correctly w/ safepoints + System.out.println("going to safepoint"); + WHITE_BOX.fullGC(); + waitBackgroundCompilation(); + Asserts.assertTrue( + WHITE_BOX.isMethodQueuedForCompilation(method), + method + " must be in queue"); + Asserts.assertFalse( + WHITE_BOX.isMethodCompiled(method, false), + method + " must be not compiled"); + Asserts.assertEQ( + WHITE_BOX.getMethodCompilationLevel(method, false), 0, + method + " comp_level must be == 0"); + Asserts.assertFalse( + WHITE_BOX.isMethodCompiled(method, true), + method + " must be not osr_compiled"); + Asserts.assertEQ( + WHITE_BOX.getMethodCompilationLevel(method, true), 0, + method + " osr_comp_level must be == 0"); + } finally { + System.out.println("unlocking compilation"); + WHITE_BOX.unlockCompilation(); + } + waitBackgroundCompilation(); + Asserts.assertFalse( + WHITE_BOX.isMethodQueuedForCompilation(method), + method + " must not be in queue"); + } +} + diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Mon Nov 10 19:04:38 2014 +0300 @@ -143,8 +143,14 @@ } public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); public native void clearMethodState(Executable method); + public native void lockCompilation(); + public native void unlockCompilation(); public native int getMethodEntryBci(Executable method); public native Object[] getNMethod(Executable method, boolean isOsr); + public native long allocateCodeBlob(int size, int type); + public native void freeCodeBlob(long addr); + public native void forceNMethodSweep(); + public native Object[] getCodeHeapEntries(int type); // Intered strings public native boolean isInStringTable(String str); diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/testlibrary/whitebox/sun/hotspot/code/BlobType.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/BlobType.java Mon Nov 10 19:04:38 2014 +0300 @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.hotspot.code; + +import java.lang.management.ManagementFactory; +import java.lang.management.MemoryPoolMXBean; +import java.util.EnumSet; + +import sun.hotspot.WhiteBox; + +public enum BlobType { + // Execution level 1 and 4 (non-profiled) nmethods (including native nmethods) + MethodNonProfiled(0, "CodeHeap 'non-profiled nmethods'"), + // Execution level 2 and 3 (profiled) nmethods + MethodProfiled(1, "CodeHeap 'profiled nmethods'"), + // Non-nmethods like Buffers, Adapters and Runtime Stubs + NonNMethod(2, "CodeHeap 'non-nmethods'"), + // All types (No code cache segmentation) + All(3, "CodeCache"); + + public final int id; + private final String beanName; + + private BlobType(int id, String beanName) { + this.id = id; + this.beanName = beanName; + } + + public MemoryPoolMXBean getMemoryPool() { + for (MemoryPoolMXBean bean : ManagementFactory.getMemoryPoolMXBeans()) { + String name = bean.getName(); + if (beanName.equals(name)) { + return bean; + } + } + return null; + } + public static EnumSet getAvailable() { + WhiteBox whiteBox = WhiteBox.getWhiteBox(); + if (!whiteBox.getBooleanVMFlag("SegmentedCodeCache")) { + // only All for non segmented world + return EnumSet.of(All); + } + if (System.getProperty("java.vm.info").startsWith("interpreted ")) { + // only NonNMethod for -Xint + return EnumSet.of(NonNMethod); + } + + EnumSet result = EnumSet.complementOf(EnumSet.of(All)); + if (!whiteBox.getBooleanVMFlag("TieredCompilation") + || whiteBox.getIntxVMFlag("TieredStopAtLevel") <= 1) { + // there is no MethodProfiled in non tiered world or pure C1 + result.remove(MethodProfiled); + } + return result; + } +} diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/testlibrary/whitebox/sun/hotspot/code/CodeBlob.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/CodeBlob.java Mon Nov 10 19:04:38 2014 +0300 @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2014, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + * + */ + +package sun.hotspot.code; + +import sun.hotspot.WhiteBox; + +public class CodeBlob { + private static final WhiteBox WB = WhiteBox.getWhiteBox(); + public static CodeBlob[] getCodeBlobs(BlobType type) { + Object[] obj = WB.getCodeHeapEntries(type.id); + if (obj == null) { + return null; + } + CodeBlob[] result = new CodeBlob[obj.length]; + for (int i = 0, n = result.length; i < n; ++i) { + result[i] = new CodeBlob((Object[]) obj[i]); + } + return result; + } + protected CodeBlob(Object[] obj) { + assert obj.length == 3; + name = (String) obj[0]; + size = (Integer) obj[1]; + code_blob_type = BlobType.values()[(Integer) obj[2]]; + assert code_blob_type.id == (Integer) obj[2]; + } + public final String name; + public final int size; + public final BlobType code_blob_type; + + @Override + public String toString() { + return "CodeBlob{" + + "name=" + name + + ", size=" + size + + ", code_blob_type=" + code_blob_type + + '}'; + } +} diff -r fca9ac607ebc -r 8c9eff693145 hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java --- a/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java Sat Nov 08 16:00:28 2014 +0300 +++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/code/NMethod.java Mon Nov 10 19:04:38 2014 +0300 @@ -27,28 +27,30 @@ import java.lang.reflect.Executable; import sun.hotspot.WhiteBox; -public class NMethod { +public class NMethod extends CodeBlob { private static final WhiteBox wb = WhiteBox.getWhiteBox(); public static NMethod get(Executable method, boolean isOsr) { Object[] obj = wb.getNMethod(method, isOsr); return obj == null ? null : new NMethod(obj); } private NMethod(Object[] obj) { - assert obj.length == 3; - comp_level = (Integer) obj[0]; - insts = (byte[]) obj[1]; - compile_id = (Integer) obj[2]; + super((Object[])obj[0]); + assert obj.length == 4; + comp_level = (Integer) obj[1]; + insts = (byte[]) obj[2]; + compile_id = (Integer) obj[3]; } - public byte[] insts; - public int comp_level; - public int compile_id; + public final byte[] insts; + public final int comp_level; + public final int compile_id; @Override public String toString() { - return "NMethod{" + - "insts=" + insts + - ", comp_level=" + comp_level + - ", compile_id=" + compile_id + - '}'; + return "NMethod{" + + super.toString() + + ", insts=" + insts + + ", comp_level=" + comp_level + + ", compile_id=" + compile_id + + '}'; } }