8059624: Test task: WhiteBox API for testing segmented codecache feature

Reviewed-by: kvn, thartmann
This commit is contained in:
Igor Ignatyev 2014-11-10 19:04:38 +03:00
parent 80830d4932
commit bdac822811
18 changed files with 687 additions and 35 deletions

View file

@ -43,7 +43,7 @@
#include "c1/c1_Runtime1.hpp" #include "c1/c1_Runtime1.hpp"
#endif #endif
unsigned int align_code_offset(int offset) { unsigned int CodeBlob::align_code_offset(int offset) {
// align the size to CodeEntryAlignment // align the size to CodeEntryAlignment
return return
((offset + (int)CodeHeap::header_size() + (CodeEntryAlignment-1)) & ~(CodeEntryAlignment-1)) ((offset + (int)CodeHeap::header_size() + (CodeEntryAlignment-1)) & ~(CodeEntryAlignment-1))

View file

@ -83,6 +83,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
public: public:
// Returns the space needed for CodeBlob // Returns the space needed for CodeBlob
static unsigned int allocation_size(CodeBuffer* cb, int header_size); static unsigned int allocation_size(CodeBuffer* cb, int header_size);
static unsigned int align_code_offset(int offset);
// Creation // Creation
// a) simple CodeBlob // a) simple CodeBlob
@ -207,7 +208,7 @@ class CodeBlob VALUE_OBJ_CLASS_SPEC {
} }
}; };
class WhiteBox;
//---------------------------------------------------------------------------------------------------- //----------------------------------------------------------------------------------------------------
// BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc. // BufferBlob: used to hold non-relocatable machine code such as the interpreter, stubroutines, etc.
@ -215,6 +216,7 @@ class BufferBlob: public CodeBlob {
friend class VMStructs; friend class VMStructs;
friend class AdapterBlob; friend class AdapterBlob;
friend class MethodHandlesAdapterBlob; friend class MethodHandlesAdapterBlob;
friend class WhiteBox;
private: private:
// Creation support // Creation support

View file

@ -305,7 +305,7 @@ void CodeCache::add_heap(ReservedSpace rs, const char* name, size_t size_initial
MemoryService::add_code_heap_memory_pool(heap, name); 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"); assert(cb != NULL, "CodeBlob is null");
FOR_ALL_HEAPS(heap) { FOR_ALL_HEAPS(heap) {
if ((*heap)->contains(cb)) { if ((*heap)->contains(cb)) {

View file

@ -77,6 +77,7 @@ class DepChange;
class CodeCache : AllStatic { class CodeCache : AllStatic {
friend class VMStructs; friend class VMStructs;
friend class NMethodIterator; friend class NMethodIterator;
friend class WhiteBox;
private: private:
// CodeHeaps of the cache // CodeHeaps of the cache
static GrowableArray<CodeHeap*>* _heaps; static GrowableArray<CodeHeap*>* _heaps;
@ -98,7 +99,7 @@ class CodeCache : AllStatic {
static void initialize_heaps(); // Initializes the CodeHeaps static void initialize_heaps(); // Initializes the CodeHeaps
// Creates a new heap with the given name and size, containing CodeBlobs of the given type // 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 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 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 // 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); static const char* get_code_heap_flag_name(int code_blob_type);

View file

@ -35,6 +35,7 @@
#include "oops/method.hpp" #include "oops/method.hpp"
#include "oops/oop.inline.hpp" #include "oops/oop.inline.hpp"
#include "prims/nativeLookup.hpp" #include "prims/nativeLookup.hpp"
#include "prims/whitebox.hpp"
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/atomic.inline.hpp" #include "runtime/atomic.inline.hpp"
#include "runtime/compilationPolicy.hpp" #include "runtime/compilationPolicy.hpp"
@ -1963,6 +1964,12 @@ void CompileBroker::invoke_compiler_on_method(CompileTask* task) {
if (comp == NULL) { if (comp == NULL) {
ci_env.record_method_not_compilable("no compiler", !TieredCompilation); ci_env.record_method_not_compilable("no compiler", !TieredCompilation);
} else { } 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); comp->compile_method(&ci_env, target, osr_bci);
} }

View file

@ -24,6 +24,8 @@
#include "precompiled.hpp" #include "precompiled.hpp"
#include <new>
#include "code/codeCache.hpp" #include "code/codeCache.hpp"
#include "memory/metadataFactory.hpp" #include "memory/metadataFactory.hpp"
#include "memory/universe.hpp" #include "memory/universe.hpp"
@ -37,9 +39,11 @@
#include "runtime/thread.hpp" #include "runtime/thread.hpp"
#include "runtime/arguments.hpp" #include "runtime/arguments.hpp"
#include "runtime/deoptimization.hpp"
#include "runtime/interfaceSupport.hpp" #include "runtime/interfaceSupport.hpp"
#include "runtime/os.hpp" #include "runtime/os.hpp"
#include "runtime/vm_version.hpp" #include "runtime/vm_version.hpp"
#include "runtime/sweeper.hpp"
#include "utilities/array.hpp" #include "utilities/array.hpp"
#include "utilities/debug.hpp" #include "utilities/debug.hpp"
@ -67,6 +71,7 @@ PRAGMA_FORMAT_MUTE_WARNINGS_FOR_GCC
#define SIZE_T_MAX_VALUE ((size_t) -1) #define SIZE_T_MAX_VALUE ((size_t) -1)
bool WhiteBox::_used = false; bool WhiteBox::_used = false;
volatile bool WhiteBox::compilation_locked = false;
WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj)) WB_ENTRY(jlong, WB_GetObjectAddress(JNIEnv* env, jobject o, jobject obj))
return (jlong)(void*)JNIHandles::resolve(obj); return (jlong)(void*)JNIHandles::resolve(obj);
@ -302,13 +307,12 @@ WB_END
WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size)) WB_ENTRY(jlong, WB_NMTReserveMemory(JNIEnv* env, jobject o, jlong size))
jlong addr = 0; jlong addr = 0;
addr = (jlong)(uintptr_t)os::reserve_memory(size); addr = (jlong)(uintptr_t)os::reserve_memory(size);
MemTracker::record_virtual_memory_type((address)addr, mtTest); MemTracker::record_virtual_memory_type((address)addr, mtTest);
return addr; return addr;
WB_END WB_END
WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size)) WB_ENTRY(void, WB_NMTCommitMemory(JNIEnv* env, jobject o, jlong addr, jlong size))
os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem); os::commit_memory((char *)(uintptr_t)addr, size, !ExecMem);
MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest); MemTracker::record_virtual_memory_type((address)(uintptr_t)addr, mtTest);
@ -728,6 +732,29 @@ WB_ENTRY(void, WB_SetStringVMFlag(JNIEnv* env, jobject o, jstring name, jstring
WB_END 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)) WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
int len; int len;
@ -774,6 +801,46 @@ WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o))
return features_string; return features_string;
WB_END 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)) WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jboolean is_osr))
ResourceMark rm(THREAD); ResourceMark rm(THREAD);
@ -790,27 +857,93 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo
ThreadToNativeFromVM ttn(thread); ThreadToNativeFromVM ttn(thread);
jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string()); jclass clazz = env->FindClass(vmSymbols::java_lang_Object()->as_C_string());
CHECK_JNI_EXCEPTION_(env, NULL); CHECK_JNI_EXCEPTION_(env, NULL);
result = env->NewObjectArray(3, clazz, NULL); result = env->NewObjectArray(4, clazz, NULL);
if (result == NULL) { if (result == NULL) {
return result; return result;
} }
CodeBlobStub stub(code);
jobjectArray codeBlob = codeBlob2objectArray(thread, env, &stub);
env->SetObjectArrayElement(result, 0, codeBlob);
jobject level = integerBox(thread, env, code->comp_level()); jobject level = integerBox(thread, env, code->comp_level());
CHECK_JNI_EXCEPTION_(env, NULL); CHECK_JNI_EXCEPTION_(env, NULL);
env->SetObjectArrayElement(result, 0, level); env->SetObjectArrayElement(result, 1, level);
jbyteArray insts = env->NewByteArray(insts_size); jbyteArray insts = env->NewByteArray(insts_size);
CHECK_JNI_EXCEPTION_(env, NULL); CHECK_JNI_EXCEPTION_(env, NULL);
env->SetByteArrayRegion(insts, 0, insts_size, (jbyte*) code->insts_begin()); 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()); jobject id = integerBox(thread, env, code->compile_id());
CHECK_JNI_EXCEPTION_(env, NULL); CHECK_JNI_EXCEPTION_(env, NULL);
env->SetObjectArrayElement(result, 2, id); env->SetObjectArrayElement(result, 3, id);
return result; return result;
WB_END 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
WB_ENTRY(jlong, WB_GetThreadStackSize(JNIEnv* env, jobject o)) WB_ENTRY(jlong, WB_GetThreadStackSize(JNIEnv* env, jobject o))
return (jlong) Thread::current()->stack_size(); return (jlong) Thread::current()->stack_size();
WB_END WB_END
@ -1018,6 +1151,8 @@ static JNINativeMethod methods[] = {
CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation}, CC"(Ljava/lang/reflect/Executable;II)Z", (void*)&WB_EnqueueMethodForCompilation},
{CC"clearMethodState", {CC"clearMethodState",
CC"(Ljava/lang/reflect/Executable;)V", (void*)&WB_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"isConstantVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsConstantVMFlag},
{CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag}, {CC"isLockedVMFlag", CC"(Ljava/lang/String;)Z", (void*)&WB_IsLockedVMFlag},
{CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag}, {CC"setBooleanVMFlag", CC"(Ljava/lang/String;Z)V",(void*)&WB_SetBooleanVMFlag},
@ -1055,6 +1190,10 @@ static JNINativeMethod methods[] = {
{CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures }, {CC"getCPUFeatures", CC"()Ljava/lang/String;", (void*)&WB_GetCPUFeatures },
{CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;", {CC"getNMethod", CC"(Ljava/lang/reflect/Executable;Z)[Ljava/lang/Object;",
(void*)&WB_GetNMethod }, (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"getThreadStackSize", CC"()J", (void*)&WB_GetThreadStackSize },
{CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize }, {CC"getThreadRemainingStackSize", CC"()J", (void*)&WB_GetThreadRemainingStackSize },
}; };

View file

@ -54,17 +54,24 @@
} \ } \
} while (0) } while (0)
class CodeBlob;
class CodeHeap;
class WhiteBox : public AllStatic { class WhiteBox : public AllStatic {
private: private:
static bool _used; static bool _used;
public: public:
static volatile bool compilation_locked;
static bool used() { return _used; } static bool used() { return _used; }
static void set_used() { _used = true; } static void set_used() { _used = true; }
static int offset_for_field(const char* field_name, oop object, static int offset_for_field(const char* field_name, oop object,
Symbol* signature_symbol); Symbol* signature_symbol);
static const char* lookup_jstring(const char* field_name, oop object); static const char* lookup_jstring(const char* field_name, oop object);
static bool lookup_bool(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 int array_bytes_to_length(size_t bytes);
static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread, static void register_methods(JNIEnv* env, jclass wbclass, JavaThread* thread,
JNINativeMethod* method_array, int method_count); JNINativeMethod* method_array, int method_count);

View file

@ -88,6 +88,7 @@ Mutex* DerivedPointerTableGC_lock = NULL;
Mutex* Compile_lock = NULL; Mutex* Compile_lock = NULL;
Monitor* MethodCompileQueue_lock = NULL; Monitor* MethodCompileQueue_lock = NULL;
Monitor* CompileThread_lock = NULL; Monitor* CompileThread_lock = NULL;
Monitor* Compilation_lock = NULL;
Mutex* CompileTaskAlloc_lock = NULL; Mutex* CompileTaskAlloc_lock = NULL;
Mutex* CompileStatistics_lock = NULL; Mutex* CompileStatistics_lock = NULL;
Mutex* MultiArray_lock = NULL; Mutex* MultiArray_lock = NULL;
@ -278,7 +279,9 @@ void mutex_init() {
def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread def(ProfileVM_lock , Monitor, special, false); // used for profiling of the VMThread
def(CompileThread_lock , Monitor, nonleaf+5, false ); def(CompileThread_lock , Monitor, nonleaf+5, false );
def(PeriodicTask_lock , Monitor, nonleaf+5, true); def(PeriodicTask_lock , Monitor, nonleaf+5, true);
if (WhiteBoxAPI) {
def(Compilation_lock , Monitor, leaf, false );
}
#ifdef INCLUDE_TRACE #ifdef INCLUDE_TRACE
def(JfrMsg_lock , Monitor, leaf, true); def(JfrMsg_lock , Monitor, leaf, true);
def(JfrBuffer_lock , Mutex, leaf, true); def(JfrBuffer_lock , Mutex, leaf, true);

View file

@ -91,6 +91,7 @@ extern Mutex* EvacFailureStack_lock; // guards the evac failure scan
extern Mutex* Compile_lock; // a lock held when Compilation is updating code (used to block CodeCache traversal, CHA updates, etc) 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* 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* 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* CompileTaskAlloc_lock; // a lock held when CompileTasks are allocated
extern Mutex* CompileStatistics_lock; // a lock held when updating compilation statistics 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 extern Mutex* MultiArray_lock; // a lock used to guard allocation of multi-dim arrays

View file

@ -25,6 +25,8 @@
#ifndef SHARE_VM_RUNTIME_SWEEPER_HPP #ifndef SHARE_VM_RUNTIME_SWEEPER_HPP
#define SHARE_VM_RUNTIME_SWEEPER_HPP #define SHARE_VM_RUNTIME_SWEEPER_HPP
class WhiteBox;
#include "utilities/ticks.hpp" #include "utilities/ticks.hpp"
// An NmethodSweeper is an incremental cleaner for: // An NmethodSweeper is an incremental cleaner for:
// - cleanup inline caches // - cleanup inline caches
@ -52,6 +54,8 @@
// nmethod's space is freed. // nmethod's space is freed.
class NMethodSweeper : public AllStatic { class NMethodSweeper : public AllStatic {
friend class WhiteBox;
private:
static long _traversals; // Stack scan count, also sweep ID. 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 _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 static long _time_counter; // Virtual time used to periodically invoke sweeper
@ -88,7 +92,6 @@ class NMethodSweeper : public AllStatic {
static void handle_safepoint_request(); static void handle_safepoint_request();
static void do_stack_scanning(); static void do_stack_scanning();
static void possibly_sweep(); static void possibly_sweep();
public: public:
static long traversal_count() { return _traversals; } static long traversal_count() { return _traversals; }
static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; } static int total_nof_methods_reclaimed() { return _total_nof_methods_reclaimed; }

View file

@ -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);
}
}
}
}

View file

@ -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);
}
}

View file

@ -22,7 +22,9 @@
* *
*/ */
import sun.hotspot.code.BlobType;
import sun.hotspot.code.NMethod; import sun.hotspot.code.NMethod;
import com.oracle.java.testlibrary.Asserts;
/* /*
* @test GetNMethodTest * @test GetNMethodTest
@ -52,21 +54,46 @@ public class GetNMethodTest extends CompilerWhiteBoxTest {
compile(); compile();
checkCompiled(); checkCompiled();
NMethod nmethod = NMethod.get(method, testCase.isOsr()); NMethod nmethod = NMethod.get(method, testCase.isOsr());
if (IS_VERBOSE) { if (IS_VERBOSE) {
System.out.println("nmethod = " + nmethod); System.out.println("nmethod = " + nmethod);
} }
if (nmethod == null) { Asserts.assertNotNull(nmethod,
throw new RuntimeException("nmethod of compiled method is null"); "nmethod of compiled method is null");
} Asserts.assertNotNull(nmethod.insts,
if (nmethod.insts.length == 0) { "nmethod.insts of compiled method is null");
throw new RuntimeException("compiled method's instructions is empty"); 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);
} }
deoptimize(); deoptimize();
checkNotCompiled(); checkNotCompiled();
nmethod = NMethod.get(method, testCase.isOsr()); nmethod = NMethod.get(method, testCase.isOsr());
if (nmethod != null) { Asserts.assertNull(nmethod,
throw new RuntimeException("nmethod of non-compiled method isn't null"); "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));
} }
} }

View file

@ -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");
}
}

View file

@ -143,8 +143,14 @@ public class WhiteBox {
} }
public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci); public native boolean enqueueMethodForCompilation(Executable method, int compLevel, int entry_bci);
public native void clearMethodState(Executable method); public native void clearMethodState(Executable method);
public native void lockCompilation();
public native void unlockCompilation();
public native int getMethodEntryBci(Executable method); public native int getMethodEntryBci(Executable method);
public native Object[] getNMethod(Executable method, boolean isOsr); 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 // Intered strings
public native boolean isInStringTable(String str); public native boolean isInStringTable(String str);

View file

@ -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;
}
}

View file

@ -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
+ '}';
}
}

View file

@ -27,28 +27,30 @@ package sun.hotspot.code;
import java.lang.reflect.Executable; import java.lang.reflect.Executable;
import sun.hotspot.WhiteBox; import sun.hotspot.WhiteBox;
public class NMethod { public class NMethod extends CodeBlob {
private static final WhiteBox wb = WhiteBox.getWhiteBox(); private static final WhiteBox wb = WhiteBox.getWhiteBox();
public static NMethod get(Executable method, boolean isOsr) { public static NMethod get(Executable method, boolean isOsr) {
Object[] obj = wb.getNMethod(method, isOsr); Object[] obj = wb.getNMethod(method, isOsr);
return obj == null ? null : new NMethod(obj); return obj == null ? null : new NMethod(obj);
} }
private NMethod(Object[] obj) { private NMethod(Object[] obj) {
assert obj.length == 3; super((Object[])obj[0]);
comp_level = (Integer) obj[0]; assert obj.length == 4;
insts = (byte[]) obj[1]; comp_level = (Integer) obj[1];
compile_id = (Integer) obj[2]; insts = (byte[]) obj[2];
compile_id = (Integer) obj[3];
} }
public byte[] insts; public final byte[] insts;
public int comp_level; public final int comp_level;
public int compile_id; public final int compile_id;
@Override @Override
public String toString() { public String toString() {
return "NMethod{" + return "NMethod{"
"insts=" + insts + + super.toString()
", comp_level=" + comp_level + + ", insts=" + insts
", compile_id=" + compile_id + + ", comp_level=" + comp_level
'}'; + ", compile_id=" + compile_id
+ '}';
} }
} }