8059624: Test task: WhiteBox API for testing segmented codecache feature
Reviewed-by: kvn, thartmann
--- 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))
--- 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
--- 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)) {
--- 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<CodeHeap*>* _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);
--- 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);
}
--- 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 <new>
+
#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<CodeBlobStub*> 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<CodeBlobStub*> 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 },
};
--- 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);
--- 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);
--- 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
--- 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; }
--- /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<BlobType> 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<Long> 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);
+ }
+ }
+ }
+}
--- /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<BlobType> SEGMENTED_TYPES
+ = EnumSet.complementOf(EnumSet.of(BlobType.All));
+
+ public static void main(String[] args) {
+ EnumSet<BlobType> 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);
+ }
+}
--- 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));
}
}
--- /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");
+ }
+}
+
--- 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);
--- /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<BlobType> 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<BlobType> 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;
+ }
+}
--- /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
+ + '}';
+ }
+}
--- 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
+ + '}';
}
}