This commit is contained in:
David Chase 2014-12-04 11:35:09 -05:00
commit 0b7c6dc57c
24 changed files with 889 additions and 136 deletions

View file

@ -36,6 +36,7 @@
#include "interpreter/bytecodes.hpp"
#include "memory/allocation.inline.hpp"
#include "opto/compile.hpp"
#include "opto/node.hpp"
#include "runtime/deoptimization.hpp"
#include "utilities/growableArray.hpp"

View file

@ -936,7 +936,7 @@ address Method::make_adapters(methodHandle mh, TRAPS) {
// so making them eagerly shouldn't be too expensive.
AdapterHandlerEntry* adapter = AdapterHandlerLibrary::get_adapter(mh);
if (adapter == NULL ) {
THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "out of space in CodeCache for adapters");
THROW_MSG_NULL(vmSymbols::java_lang_VirtualMachineError(), "Out of space in CodeCache for adapters");
}
mh->set_adapter_entry(adapter);

View file

@ -1115,6 +1115,9 @@ bool ConnectionGraph::complete_connection_graph(
// Each 4 iterations calculate how much time it will take
// to complete graph construction.
time.stop();
// Poll for requests from shutdown mechanism to quiesce compiler
// because Connection graph construction may take long time.
CompileBroker::maybe_block();
double stop_time = time.seconds();
double time_per_iter = (stop_time - start_time) / (double)SAMPLE_SIZE;
double time_until_end = time_per_iter * (double)(java_objects_length - next);

View file

@ -2809,7 +2809,8 @@ Node* GraphKit::maybe_cast_profiled_receiver(Node* not_null_obj,
*/
Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
ciKlass* type,
bool not_null) {
bool not_null,
SafePointNode* sfpt) {
// type == NULL if profiling tells us this object is always null
if (type != NULL) {
Deoptimization::DeoptReason class_reason = Deoptimization::Reason_speculate_class_check;
@ -2831,7 +2832,13 @@ Node* GraphKit::maybe_cast_profiled_obj(Node* obj,
ciKlass* exact_kls = type;
Node* slow_ctl = type_check_receiver(exact_obj, exact_kls, 1.0,
&exact_obj);
{
if (sfpt != NULL) {
GraphKit kit(sfpt->jvms());
PreserveJVMState pjvms(&kit);
kit.set_control(slow_ctl);
kit.uncommon_trap(class_reason,
Deoptimization::Action_maybe_recompile);
} else {
PreserveJVMState pjvms(this);
set_control(slow_ctl);
uncommon_trap(class_reason,

View file

@ -418,7 +418,8 @@ class GraphKit : public Phase {
// Cast obj to type and emit guard unless we had too many traps here already
Node* maybe_cast_profiled_obj(Node* obj,
ciKlass* type,
bool not_null = false);
bool not_null = false,
SafePointNode* sfpt = NULL);
// Cast obj to not-null on this path
Node* cast_not_null(Node* obj, bool do_replace_in_map = true);

View file

@ -4697,10 +4697,6 @@ bool LibraryCallKit::inline_arraycopy() {
Node* dest_offset = argument(3); // type: int
Node* length = argument(4); // type: int
// Check for allocation before we add nodes that would confuse
// tightly_coupled_allocation()
AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL);
// The following tests must be performed
// (1) src and dest are arrays.
// (2) src and dest arrays must have elements of the same BasicType
@ -4717,6 +4713,36 @@ bool LibraryCallKit::inline_arraycopy() {
src = null_check(src, T_ARRAY);
dest = null_check(dest, T_ARRAY);
// Check for allocation before we add nodes that would confuse
// tightly_coupled_allocation()
AllocateArrayNode* alloc = tightly_coupled_allocation(dest, NULL);
SafePointNode* sfpt = NULL;
if (alloc != NULL) {
// The JVM state for uncommon traps between the allocation and
// arraycopy is set to the state before the allocation: if the
// initialization is performed by the array copy, we don't want to
// go back to the interpreter with an unitialized array.
JVMState* old_jvms = alloc->jvms();
JVMState* jvms = old_jvms->clone_shallow(C);
uint size = alloc->req();
sfpt = new SafePointNode(size, jvms);
jvms->set_map(sfpt);
for (uint i = 0; i < size; i++) {
sfpt->init_req(i, alloc->in(i));
}
// re-push array length for deoptimization
sfpt->ins_req(jvms->stkoff() + jvms->sp(), alloc->in(AllocateNode::ALength));
jvms->set_sp(jvms->sp()+1);
jvms->set_monoff(jvms->monoff()+1);
jvms->set_scloff(jvms->scloff()+1);
jvms->set_endoff(jvms->endoff()+1);
jvms->set_should_reexecute(true);
sfpt->set_i_o(map()->i_o());
sfpt->set_memory(map()->memory());
}
bool notest = false;
const Type* src_type = _gvn.type(src);
@ -4762,14 +4788,14 @@ bool LibraryCallKit::inline_arraycopy() {
if (could_have_src && could_have_dest) {
// This is going to pay off so emit the required guards
if (!has_src) {
src = maybe_cast_profiled_obj(src, src_k);
src = maybe_cast_profiled_obj(src, src_k, true, sfpt);
src_type = _gvn.type(src);
top_src = src_type->isa_aryptr();
has_src = (top_src != NULL && top_src->klass() != NULL);
src_spec = true;
}
if (!has_dest) {
dest = maybe_cast_profiled_obj(dest, dest_k);
dest = maybe_cast_profiled_obj(dest, dest_k, true);
dest_type = _gvn.type(dest);
top_dest = dest_type->isa_aryptr();
has_dest = (top_dest != NULL && top_dest->klass() != NULL);
@ -4810,10 +4836,10 @@ bool LibraryCallKit::inline_arraycopy() {
if (could_have_src && could_have_dest) {
// If we can have both exact types, emit the missing guards
if (could_have_src && !src_spec) {
src = maybe_cast_profiled_obj(src, src_k);
src = maybe_cast_profiled_obj(src, src_k, true, sfpt);
}
if (could_have_dest && !dest_spec) {
dest = maybe_cast_profiled_obj(dest, dest_k);
dest = maybe_cast_profiled_obj(dest, dest_k, true);
}
}
}
@ -4855,13 +4881,28 @@ bool LibraryCallKit::inline_arraycopy() {
Node* not_subtype_ctrl = gen_subtype_check(src_klass, dest_klass);
if (not_subtype_ctrl != top()) {
PreserveJVMState pjvms(this);
set_control(not_subtype_ctrl);
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
assert(stopped(), "Should be stopped");
if (sfpt != NULL) {
GraphKit kit(sfpt->jvms());
PreserveJVMState pjvms(&kit);
kit.set_control(not_subtype_ctrl);
kit.uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
assert(kit.stopped(), "Should be stopped");
} else {
PreserveJVMState pjvms(this);
set_control(not_subtype_ctrl);
uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
assert(stopped(), "Should be stopped");
}
}
{
if (sfpt != NULL) {
GraphKit kit(sfpt->jvms());
kit.set_control(_gvn.transform(slow_region));
kit.uncommon_trap(Deoptimization::Reason_intrinsic,
Deoptimization::Action_make_not_entrant);
assert(kit.stopped(), "Should be stopped");
} else {
PreserveJVMState pjvms(this);
set_control(_gvn.transform(slow_region));
uncommon_trap(Deoptimization::Reason_intrinsic,

View file

@ -1431,7 +1431,7 @@ void PhaseIterGVN::add_users_to_worklist( Node *n ) {
Node* castii = in1->raw_out(i);
if (castii->in(0) != NULL && castii->in(0)->in(0) != NULL && castii->in(0)->in(0)->is_If()) {
Node* ifnode = castii->in(0)->in(0);
if (ifnode->in(1) != NULL && ifnode->in(1)->in(1) == use) {
if (ifnode->in(1) != NULL && ifnode->in(1)->is_Bool() && ifnode->in(1)->in(1) == use) {
// Reprocess a CastII node that may depend on an
// opaque node value when the opaque node is
// removed. In case it carries a dependency we can do

View file

@ -41,6 +41,7 @@
#include "runtime/interfaceSupport.hpp"
#include "runtime/os.hpp"
#include "runtime/sweeper.hpp"
#include "runtime/javaCalls.hpp"
#include "runtime/thread.hpp"
#include "runtime/vm_version.hpp"
#include "utilities/array.hpp"
@ -771,8 +772,8 @@ WB_ENTRY(void, WB_UnlockCompilation(JNIEnv* env, jobject o))
mo.notify_all();
WB_END
void WhiteBox::force_sweep() {
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
void WhiteBox::sweeper_thread_entry(JavaThread* thread, TRAPS) {
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
NMethodSweeper::_should_sweep = true;
@ -780,8 +781,37 @@ void WhiteBox::force_sweep() {
NMethodSweeper::possibly_sweep();
}
WB_ENTRY(void, WB_ForceNMethodSweep(JNIEnv* env, jobject o))
WhiteBox::force_sweep();
JavaThread* WhiteBox::create_sweeper_thread(TRAPS) {
// create sweeper thread w/ custom entry -- one iteration instead of loop
CodeCacheSweeperThread* sweeper_thread = new CodeCacheSweeperThread();
sweeper_thread->set_entry_point(&WhiteBox::sweeper_thread_entry);
// create j.l.Thread object and associate it w/ sweeper thread
{
// inherit deamon property from current thread
bool is_daemon = java_lang_Thread::is_daemon(JavaThread::current()->threadObj());
HandleMark hm(THREAD);
Handle thread_group(THREAD, Universe::system_thread_group());
const char* name = "WB Sweeper thread";
sweeper_thread->allocate_threadObj(thread_group, name, is_daemon, THREAD);
}
{
MutexLocker mu(Threads_lock, THREAD);
Threads::add(sweeper_thread);
}
return sweeper_thread;
}
WB_ENTRY(jobject, WB_ForceNMethodSweep(JNIEnv* env, jobject o))
JavaThread* sweeper_thread = WhiteBox::create_sweeper_thread(Thread::current());
if (sweeper_thread == NULL) {
return NULL;
}
jobject result = JNIHandles::make_local(env, sweeper_thread->threadObj());
Thread::start(sweeper_thread);
return result;
WB_END
WB_ENTRY(jboolean, WB_IsInStringTable(JNIEnv* env, jobject o, jstring javaString))
@ -831,12 +861,12 @@ WB_ENTRY(jstring, WB_GetCPUFeatures(JNIEnv* env, jobject o))
WB_END
int WhiteBox::get_blob_type(const CodeBlob* code) {
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be 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");
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
return CodeCache::get_code_heap(blob_type);
}
@ -912,7 +942,7 @@ WB_ENTRY(jobjectArray, WB_GetNMethod(JNIEnv* env, jobject o, jobject method, jbo
WB_END
CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) {
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to enabled");
guarantee(WhiteBoxAPI, "internal testing API :: WhiteBox has to be enabled");
BufferBlob* blob;
int full_size = CodeBlob::align_code_offset(sizeof(BufferBlob));
if (full_size < size) {
@ -921,10 +951,10 @@ CodeBlob* WhiteBox::allocate_code_blob(int size, int blob_type) {
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
blob = (BufferBlob*) CodeCache::allocate(full_size, blob_type);
::new (blob) BufferBlob("WB::DummyBlob", full_size);
}
// Track memory usage statistic after releasing CodeCache_lock
MemoryService::track_code_cache_memory_usage();
::new (blob) BufferBlob("WB::DummyBlob", full_size);
return blob;
}
@ -1235,7 +1265,7 @@ static JNINativeMethod methods[] = {
{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"forceNMethodSweep0", CC"()Ljava/lang/Thread;", (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 },

View file

@ -27,6 +27,7 @@
#include "prims/jni.h"
#include "utilities/exceptions.hpp"
#include "memory/allocation.hpp"
#include "oops/oopsHierarchy.hpp"
#include "oops/symbol.hpp"
@ -56,6 +57,7 @@
class CodeBlob;
class CodeHeap;
class JavaThread;
class WhiteBox : public AllStatic {
private:
@ -68,7 +70,8 @@ class WhiteBox : public AllStatic {
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 void sweeper_thread_entry(JavaThread* thread, TRAPS);
static JavaThread* create_sweeper_thread(TRAPS);
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);

View file

@ -142,9 +142,6 @@ long NMethodSweeper::_total_nof_code_cache_sweeps = 0; // Total number o
long NMethodSweeper::_time_counter = 0; // Virtual time used to periodically invoke sweeper
long NMethodSweeper::_last_sweep = 0; // Value of _time_counter when the last sweep happened
int NMethodSweeper::_seen = 0; // Nof. nmethod we have currently processed in current pass of CodeCache
int NMethodSweeper::_flushed_count = 0; // Nof. nmethods flushed in current sweep
int NMethodSweeper::_zombified_count = 0; // Nof. nmethods made zombie in current sweep
int NMethodSweeper::_marked_for_reclamation_count = 0; // Nof. nmethods marked for reclaim in current sweep
volatile bool NMethodSweeper::_should_sweep = true; // Indicates if we should invoke the sweeper
volatile int NMethodSweeper::_bytes_changed = 0; // Counts the total nmethod size if the nmethod changed from:
@ -161,6 +158,7 @@ Tickspan NMethodSweeper::_total_time_this_sweep; // Total time thi
Tickspan NMethodSweeper::_peak_sweep_time; // Peak time for a full sweep
Tickspan NMethodSweeper::_peak_sweep_fraction_time; // Peak time sweeping one fraction
Monitor* NMethodSweeper::_stat_lock = new Monitor(Mutex::special, "Sweeper::Statistics", true);
class MarkActivationClosure: public CodeBlobClosure {
public:
@ -370,9 +368,10 @@ void NMethodSweeper::sweep_code_cache() {
ResourceMark rm;
Ticks sweep_start_counter = Ticks::now();
_flushed_count = 0;
_zombified_count = 0;
_marked_for_reclamation_count = 0;
int flushed_count = 0;
int zombified_count = 0;
int marked_for_reclamation_count = 0;
int flushed_c2_count = 0;
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Sweep at %d out of %d", _seen, CodeCache::nof_nmethods());
@ -386,10 +385,8 @@ void NMethodSweeper::sweep_code_cache() {
{
MutexLockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
// The last invocation iterates until there are no more nmethods
while (!_current.end()) {
swept_count++;
handle_safepoint_request();
// Since we will give up the CodeCache_lock, always skip ahead
// to the next nmethod. Other blobs can be deleted by other
// threads but nmethods are only reclaimed by the sweeper.
@ -399,9 +396,32 @@ void NMethodSweeper::sweep_code_cache() {
// Now ready to process nmethod and give up CodeCache_lock
{
MutexUnlockerEx mu(CodeCache_lock, Mutex::_no_safepoint_check_flag);
freed_memory += process_nmethod(nm);
int size = nm->total_size();
bool is_c2_method = nm->is_compiled_by_c2();
MethodStateChange type = process_nmethod(nm);
switch (type) {
case Flushed:
freed_memory += size;
++flushed_count;
if (is_c2_method) {
++flushed_c2_count;
}
break;
case MarkedForReclamation:
++marked_for_reclamation_count;
break;
case MadeZombie:
++zombified_count;
break;
case None:
break;
default:
ShouldNotReachHere();
}
}
_seen++;
handle_safepoint_request();
}
}
@ -409,21 +429,25 @@ void NMethodSweeper::sweep_code_cache() {
const Ticks sweep_end_counter = Ticks::now();
const Tickspan sweep_time = sweep_end_counter - sweep_start_counter;
_total_time_sweeping += sweep_time;
_total_time_this_sweep += sweep_time;
_peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time);
_total_flushed_size += freed_memory;
_total_nof_methods_reclaimed += _flushed_count;
{
MutexLockerEx mu(_stat_lock, Mutex::_no_safepoint_check_flag);
_total_time_sweeping += sweep_time;
_total_time_this_sweep += sweep_time;
_peak_sweep_fraction_time = MAX2(sweep_time, _peak_sweep_fraction_time);
_total_flushed_size += freed_memory;
_total_nof_methods_reclaimed += flushed_count;
_total_nof_c2_methods_reclaimed += flushed_c2_count;
_peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep);
}
EventSweepCodeCache event(UNTIMED);
if (event.should_commit()) {
event.set_starttime(sweep_start_counter);
event.set_endtime(sweep_end_counter);
event.set_sweepIndex(_traversals);
event.set_sweptCount(swept_count);
event.set_flushedCount(_flushed_count);
event.set_markedCount(_marked_for_reclamation_count);
event.set_zombifiedCount(_zombified_count);
event.set_flushedCount(flushed_count);
event.set_markedCount(marked_for_reclamation_count);
event.set_zombifiedCount(zombified_count);
event.commit();
}
@ -433,7 +457,6 @@ void NMethodSweeper::sweep_code_cache() {
}
#endif
_peak_sweep_time = MAX2(_peak_sweep_time, _total_time_this_sweep);
log_sweep("finished");
// Sweeper is the only case where memory is released, check here if it
@ -511,10 +534,11 @@ void NMethodSweeper::release_nmethod(nmethod* nm) {
nm->flush();
}
int NMethodSweeper::process_nmethod(nmethod* nm) {
NMethodSweeper::MethodStateChange NMethodSweeper::process_nmethod(nmethod* nm) {
assert(nm != NULL, "sanity");
assert(!CodeCache_lock->owned_by_self(), "just checking");
int freed_memory = 0;
MethodStateChange result = None;
// Make sure this nmethod doesn't get unloaded during the scan,
// since safepoints may happen during acquired below locks.
NMethodMarker nmm(nm);
@ -529,7 +553,7 @@ int NMethodSweeper::process_nmethod(nmethod* nm) {
nm->cleanup_inline_caches();
SWEEP(nm);
}
return freed_memory;
return result;
}
if (nm->is_zombie()) {
@ -541,12 +565,9 @@ int NMethodSweeper::process_nmethod(nmethod* nm) {
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (marked for reclamation) being flushed", nm->compile_id(), nm);
}
freed_memory = nm->total_size();
if (nm->is_compiled_by_c2()) {
_total_nof_c2_methods_reclaimed++;
}
release_nmethod(nm);
_flushed_count++;
assert(result == None, "sanity");
result = Flushed;
} else {
if (PrintMethodFlushing && Verbose) {
tty->print_cr("### Nmethod %3d/" PTR_FORMAT " (zombie) being marked for reclamation", nm->compile_id(), nm);
@ -554,8 +575,9 @@ int NMethodSweeper::process_nmethod(nmethod* nm) {
nm->mark_for_reclamation();
// Keep track of code cache state change
_bytes_changed += nm->total_size();
_marked_for_reclamation_count++;
SWEEP(nm);
assert(result == None, "sanity");
result = MarkedForReclamation;
}
} else if (nm->is_not_entrant()) {
// If there are no current activations of this method on the
@ -576,8 +598,9 @@ int NMethodSweeper::process_nmethod(nmethod* nm) {
}
// Code cache state change is tracked in make_zombie()
nm->make_zombie();
_zombified_count++;
SWEEP(nm);
assert(result == None, "sanity");
result = MadeZombie;
}
assert(nm->is_zombie(), "nmethod must be zombie");
} else {
@ -594,17 +617,15 @@ int NMethodSweeper::process_nmethod(nmethod* nm) {
if (nm->is_osr_method()) {
SWEEP(nm);
// No inline caches will ever point to osr methods, so we can just remove it
freed_memory = nm->total_size();
if (nm->is_compiled_by_c2()) {
_total_nof_c2_methods_reclaimed++;
}
release_nmethod(nm);
_flushed_count++;
assert(result == None, "sanity");
result = Flushed;
} else {
// Code cache state change is tracked in make_zombie()
nm->make_zombie();
_zombified_count++;
SWEEP(nm);
assert(result == None, "sanity");
result = MadeZombie;
}
} else {
possibly_flush(nm);
@ -613,7 +634,7 @@ int NMethodSweeper::process_nmethod(nmethod* nm) {
nm->cleanup_inline_caches();
SWEEP(nm);
}
return freed_memory;
return result;
}

View file

@ -56,15 +56,18 @@ class WhiteBox;
class NMethodSweeper : public AllStatic {
friend class WhiteBox;
private:
enum MethodStateChange {
None,
MadeZombie,
MarkedForReclamation,
Flushed
};
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
static long _last_sweep; // Value of _time_counter when the last sweep happened
static NMethodIterator _current; // Current nmethod
static int _seen; // Nof. nmethod we have currently processed in current pass of CodeCache
static int _flushed_count; // Nof. nmethods flushed in current sweep
static int _zombified_count; // Nof. nmethods made zombie in current sweep
static int _marked_for_reclamation_count; // Nof. nmethods marked for reclaim in current sweep
static volatile int _sweep_started; // Flag to control conc sweeper
static volatile bool _should_sweep; // Indicates if we should invoke the sweeper
@ -83,8 +86,10 @@ class NMethodSweeper : public AllStatic {
static Tickspan _peak_sweep_time; // Peak time for a full sweep
static Tickspan _peak_sweep_fraction_time; // Peak time sweeping one fraction
static int process_nmethod(nmethod *nm);
static void release_nmethod(nmethod* nm);
static Monitor* _stat_lock;
static MethodStateChange process_nmethod(nmethod *nm);
static void release_nmethod(nmethod* nm);
static void init_sweeper_log() NOT_DEBUG_RETURN;
static bool wait_for_stack_scanning();

View file

@ -1076,7 +1076,7 @@ static void reset_vm_info_property(TRAPS) {
}
void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name,
void JavaThread::allocate_threadObj(Handle thread_group, const char* thread_name,
bool daemon, TRAPS) {
assert(thread_group.not_null(), "thread group should be specified");
assert(threadObj() == NULL, "should only create Java thread object once");
@ -1123,8 +1123,8 @@ void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name,
return;
}
KlassHandle group(this, SystemDictionary::ThreadGroup_klass());
Handle threadObj(this, this->threadObj());
KlassHandle group(THREAD, SystemDictionary::ThreadGroup_klass());
Handle threadObj(THREAD, this->threadObj());
JavaCalls::call_special(&result,
thread_group,
@ -1133,8 +1133,6 @@ void JavaThread::allocate_threadObj(Handle thread_group, char* thread_name,
vmSymbols::thread_void_signature(),
threadObj, // Arg 1
THREAD);
}
// NamedThread -- non-JavaThread subclasses with multiple

View file

@ -749,6 +749,7 @@ typedef void (*ThreadFunction)(JavaThread*, TRAPS);
class JavaThread: public Thread {
friend class VMStructs;
friend class WhiteBox;
private:
JavaThread* _next; // The next thread in the Threads list
oop _threadObj; // The Java level thread object
@ -1000,7 +1001,7 @@ class JavaThread: public Thread {
ThreadFunction entry_point() const { return _entry_point; }
// Allocates a new Java level thread object for this thread. thread_name may be NULL.
void allocate_threadObj(Handle thread_group, char* thread_name, bool daemon, TRAPS);
void allocate_threadObj(Handle thread_group, const char* thread_name, bool daemon, TRAPS);
// Last frame anchor routines

View file

@ -0,0 +1,244 @@
/*
* 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
* @bug 8064703
* @summary Deoptimization between array allocation and arraycopy may result in non initialized array
* @run main/othervm -XX:-BackgroundCompilation -XX:-UseOnStackReplacement -XX:TypeProfileLevel=020 TestArrayCopyNoInit
*
*/
import java.lang.invoke.*;
public class TestArrayCopyNoInit {
static int[] m1(int[] src) {
int[] dest = new int[10];
try {
System.arraycopy(src, 0, dest, 0, 10);
} catch (NullPointerException npe) {
}
return dest;
}
static int[] m2(Object src, boolean flag) {
Class tmp = src.getClass();
if (flag) {
return null;
}
int[] dest = new int[10];
try {
System.arraycopy(src, 0, dest, 0, 10);
} catch (ArrayStoreException npe) {
}
return dest;
}
static int[] m3(int[] src, int src_offset) {
int tmp = src[0];
int[] dest = new int[10];
try {
System.arraycopy(src, src_offset, dest, 0, 10);
} catch (IndexOutOfBoundsException npe) {
}
return dest;
}
static int[] m4(int[] src, int length) {
int tmp = src[0];
int[] dest = new int[10];
try {
System.arraycopy(src, 0, dest, 0, length);
} catch (IndexOutOfBoundsException npe) {
}
return dest;
}
static TestArrayCopyNoInit[] m5(Object[] src) {
Object tmp = src[0];
TestArrayCopyNoInit[] dest = new TestArrayCopyNoInit[10];
System.arraycopy(src, 0, dest, 0, 0);
return dest;
}
static class A {
}
static class B extends A {
}
static class C extends B {
}
static class D extends C {
}
static class E extends D {
}
static class F extends E {
}
static class G extends F {
}
static class H extends G {
}
static class I extends H {
}
static H[] m6(Object[] src) {
Object tmp = src[0];
H[] dest = new H[10];
System.arraycopy(src, 0, dest, 0, 0);
return dest;
}
static Object m7_src(Object src) {
return src;
}
static int[] m7(Object src, boolean flag) {
Class tmp = src.getClass();
if (flag) {
return null;
}
src = m7_src(src);
int[] dest = new int[10];
try {
System.arraycopy(src, 0, dest, 0, 10);
} catch (ArrayStoreException npe) {
}
return dest;
}
static public void main(String[] args) throws Throwable {
boolean success = true;
int[] src = new int[10];
TestArrayCopyNoInit[] src2 = new TestArrayCopyNoInit[10];
int[] res = null;
TestArrayCopyNoInit[] res2 = null;
Object src_obj = new Object();
for (int i = 0; i < 20000; i++) {
m1(src);
}
res = m1(null);
for (int i = 0; i < res.length; i++) {
if (res[i] != 0) {
success = false;
System.out.println("Uninitialized array following NPE");
break;
}
}
for (int i = 0; i < 20000; i++) {
if ((i%2) == 0) {
m2(src, false);
} else {
m2(src_obj, true);
}
}
res = m2(src_obj, false);
for (int i = 0; i < res.length; i++) {
if (res[i] != 0) {
success = false;
System.out.println("Uninitialized array following failed array check");
break;
}
}
for (int i = 0; i < 20000; i++) {
m3(src, 0);
}
res = m3(src, -1);
for (int i = 0; i < res.length; i++) {
if (res[i] != 0) {
success = false;
System.out.println("Uninitialized array following failed src offset check");
break;
}
}
for (int i = 0; i < 20000; i++) {
m4(src, 0);
}
res = m4(src, -1);
for (int i = 0; i < res.length; i++) {
if (res[i] != 0) {
success = false;
System.out.println("Uninitialized array following failed length check");
break;
}
}
for (int i = 0; i < 20000; i++) {
m5(src2);
}
res2 = m5(new Object[10]);
for (int i = 0; i < res2.length; i++) {
if (res2[i] != null) {
success = false;
System.out.println("Uninitialized array following failed type check");
break;
}
}
H[] src3 = new H[10];
I b = new I();
for (int i = 0; i < 20000; i++) {
m6(src3);
}
H[] res3 = m6(new Object[10]);
for (int i = 0; i < res3.length; i++) {
if (res3[i] != null) {
success = false;
System.out.println("Uninitialized array following failed full type check");
break;
}
}
for (int i = 0; i < 20000; i++) {
if ((i%2) == 0) {
m7(src, false);
} else {
m7(src_obj, true);
}
}
res = m7(src_obj, false);
for (int i = 0; i < res.length; i++) {
if (res[i] != 0) {
success = false;
System.out.println("Uninitialized array following failed type check with return value profiling");
break;
}
}
if (!success) {
throw new RuntimeException("Some tests failed");
}
}
}

View file

@ -24,22 +24,29 @@
/*
* @test
* @bug 8023014
* @summary Test ensures that there is no crash if there is not enough ReservedCodeacacheSize
* @summary Test ensures that there is no crash if there is not enough ReservedCodeCacheSize
* to initialize all compiler threads. The option -Xcomp gives the VM more time to
* to trigger the old bug.
* trigger the old bug.
* @library /testlibrary
*/
import com.oracle.java.testlibrary.*;
import static com.oracle.java.testlibrary.Asserts.assertTrue;
public class SmallCodeCacheStartup {
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=3m",
"-XX:CICompilerCount=64",
"-Xcomp",
"-version");
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
analyzer.shouldHaveExitValue(0);
public static void main(String[] args) throws Exception {
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:ReservedCodeCacheSize=3m",
"-XX:CICompilerCount=64",
"-Xcomp",
"-version");
OutputAnalyzer analyzer = new OutputAnalyzer(pb.start());
try {
analyzer.shouldHaveExitValue(0);
} catch (RuntimeException e) {
// Error occurred during initialization, did we run out of adapter space?
assertTrue(analyzer.getOutput().contains("VirtualMachineError: Out of space in CodeCache"),
"Expected VirtualMachineError");
}
System.out.println("TEST PASSED");
System.out.println("TEST PASSED");
}
}

View file

@ -29,10 +29,11 @@ import java.util.ArrayList;
import sun.hotspot.WhiteBox;
import sun.hotspot.code.BlobType;
import com.oracle.java.testlibrary.Asserts;
import com.oracle.java.testlibrary.InfiniteLoop;
/*
* @test AllocationCodeBlobTest
* @bug 8059624
* @bug 8059624 8064669
* @library /testlibrary /testlibrary/whitebox
* @build AllocationCodeBlobTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
@ -53,11 +54,32 @@ public class AllocationCodeBlobTest {
public static void main(String[] args) {
// check that Sweeper handels dummy blobs correctly
new ForcedSweeper(500).start();
Thread t = new Thread(
new InfiniteLoop(WHITE_BOX::forceNMethodSweep, 1L),
"ForcedSweeper");
t.setDaemon(true);
System.out.println("Starting " + t.getName());
t.start();
EnumSet<BlobType> blobTypes = BlobType.getAvailable();
for (BlobType type : blobTypes) {
new AllocationCodeBlobTest(type).test();
}
// check that deoptimization works well w/ dummy blobs
t = new Thread(
new InfiniteLoop(WHITE_BOX::deoptimizeAll, 1L),
"Deoptimize Thread");
t.setDaemon(true);
System.out.println("Starting " + t.getName());
t.start();
for (int i = 0; i < 10_000; ++i) {
for (BlobType type : blobTypes) {
long addr = WHITE_BOX.allocateCodeBlob(SIZE, type.id);
}
}
}
private final BlobType type;
@ -105,24 +127,4 @@ public class AllocationCodeBlobTest {
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,97 @@
/*
* 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.reflect.Method;
import java.util.EnumSet;
import sun.hotspot.WhiteBox;
import sun.hotspot.code.BlobType;
import com.oracle.java.testlibrary.Asserts;
import com.oracle.java.testlibrary.InfiniteLoop;
/*
* @test
* @bug 8059624 8064669
* @library /testlibrary /testlibrary/whitebox
* @build ForceNMethodSweepTest
* @run main ClassFileInstaller sun.hotspot.WhiteBox
* sun.hotspot.WhiteBox$WhiteBoxPermission
* @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions
* -XX:-TieredCompilation -XX:+WhiteBoxAPI
* -XX:CompileCommand=compileonly,SimpleTestCase$Helper::*
* ForceNMethodSweepTest
* @summary testing of WB::forceNMethodSweep
*/
public class ForceNMethodSweepTest extends CompilerWhiteBoxTest {
public static void main(String[] args) throws Exception {
CompilerWhiteBoxTest.main(ForceNMethodSweepTest::new, args);
}
private final EnumSet<BlobType> blobTypes;
private ForceNMethodSweepTest(TestCase testCase) {
super(testCase);
// to prevent inlining of #method
WHITE_BOX.testSetDontInlineMethod(method, true);
blobTypes = BlobType.getAvailable();
}
@Override
protected void test() throws Exception {
checkNotCompiled();
guaranteedSweep();
int usage = getTotalUsage();
compile();
checkCompiled();
int afterCompilation = getTotalUsage();
Asserts.assertGT(afterCompilation, usage,
"compilation should increase usage");
guaranteedSweep();
int afterSweep = getTotalUsage();
Asserts.assertLTE(afterSweep, afterCompilation,
"sweep shouldn't increase usage");
deoptimize();
guaranteedSweep();
int afterDeoptAndSweep = getTotalUsage();
Asserts.assertLT(afterDeoptAndSweep, afterSweep,
"sweep after deoptimization should decrease usage");
}
private int getTotalUsage() {
int usage = 0;
for (BlobType type : blobTypes) {
usage += type.getMemoryPool().getUsage().getUsed();
}
return usage;
}
private void guaranteedSweep() {
// not entrant -> ++stack_traversal_mark -> zombie -> reclamation -> flushed
for (int i = 0; i < 5; ++i) {
WHITE_BOX.fullGC();
WHITE_BOX.forceNMethodSweep();
}
}
}

View file

@ -75,7 +75,7 @@ public class GetNMethodTest extends CompilerWhiteBoxTest {
break;
case 2:
case 3:
checkBlockType(nmethod, BlobType.MethodNonProfiled);
checkBlockType(nmethod, BlobType.MethodProfiled);
break;
default:
throw new Error("unexpected comp level " + nmethod);

View file

@ -68,8 +68,7 @@ public class Asserts {
* @see #assertLessThan(T, T, String)
*/
public static <T extends Comparable<T>> void assertLessThan(T lhs, T rhs) {
String msg = "Expected that " + format(lhs) + " < " + format(rhs);
assertLessThan(lhs, rhs, msg);
assertLessThan(lhs, rhs, null);
}
/**
@ -81,7 +80,7 @@ public class Asserts {
* @throws RuntimeException if the assertion isn't valid.
*/
public static <T extends Comparable<T>>void assertLessThan(T lhs, T rhs, String msg) {
assertTrue(compare(lhs, rhs, msg) < 0, msg);
assertTrue(compare(lhs, rhs, msg) < 0, getMessage(lhs, rhs, "<", msg));
}
/**
@ -108,8 +107,7 @@ public class Asserts {
* @see #assertLessThanOrEqual(T, T, String)
*/
public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs) {
String msg = "Expected that " + format(lhs) + " <= " + format(rhs);
assertLessThanOrEqual(lhs, rhs, msg);
assertLessThanOrEqual(lhs, rhs, null);
}
/**
@ -121,7 +119,7 @@ public class Asserts {
* @throws RuntimeException if the assertion isn't valid.
*/
public static <T extends Comparable<T>> void assertLessThanOrEqual(T lhs, T rhs, String msg) {
assertTrue(compare(lhs, rhs, msg) <= 0, msg);
assertTrue(compare(lhs, rhs, msg) <= 0, getMessage(lhs, rhs, "<=", msg));
}
/**
@ -148,8 +146,7 @@ public class Asserts {
* @see #assertEquals(T, T, String)
*/
public static void assertEquals(Object lhs, Object rhs) {
String msg = "Expected " + format(lhs) + " to equal " + format(rhs);
assertEquals(lhs, rhs, msg);
assertEquals(lhs, rhs, null);
}
/**
@ -166,7 +163,7 @@ public class Asserts {
error(msg);
}
} else {
assertTrue(lhs.equals(rhs), msg);
assertTrue(lhs.equals(rhs), getMessage(lhs, rhs, "==", msg));
}
}
@ -194,8 +191,7 @@ public class Asserts {
* @see #assertGreaterThanOrEqual(T, T, String)
*/
public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs) {
String msg = "Expected that " + format(lhs) + " >= " + format(rhs);
assertGreaterThanOrEqual(lhs, rhs, msg);
assertGreaterThanOrEqual(lhs, rhs, null);
}
/**
@ -207,7 +203,7 @@ public class Asserts {
* @throws RuntimeException if the assertion isn't valid.
*/
public static <T extends Comparable<T>> void assertGreaterThanOrEqual(T lhs, T rhs, String msg) {
assertTrue(compare(lhs, rhs, msg) >= 0, msg);
assertTrue(compare(lhs, rhs, msg) >= 0, getMessage(lhs, rhs, ">=", msg));
}
/**
@ -234,8 +230,7 @@ public class Asserts {
* @see #assertGreaterThan(T, T, String)
*/
public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs) {
String msg = "Expected that " + format(lhs) + " > " + format(rhs);
assertGreaterThan(lhs, rhs, msg);
assertGreaterThan(lhs, rhs, null);
}
/**
@ -247,7 +242,7 @@ public class Asserts {
* @throws RuntimeException if the assertion isn't valid.
*/
public static <T extends Comparable<T>> void assertGreaterThan(T lhs, T rhs, String msg) {
assertTrue(compare(lhs, rhs, msg) > 0, msg);
assertTrue(compare(lhs, rhs, msg) > 0, getMessage(lhs, rhs, ">", msg));
}
/**
@ -274,8 +269,7 @@ public class Asserts {
* @see #assertNotEquals(T, T, String)
*/
public static void assertNotEquals(Object lhs, Object rhs) {
String msg = "Expected " + format(lhs) + " to not equal " + format(rhs);
assertNotEquals(lhs, rhs, msg);
assertNotEquals(lhs, rhs, null);
}
/**
@ -292,7 +286,7 @@ public class Asserts {
error(msg);
}
} else {
assertFalse(lhs.equals(rhs), msg);
assertFalse(lhs.equals(rhs), getMessage(lhs, rhs,"!=", msg));
}
}
@ -450,4 +444,8 @@ public class Asserts {
throw new RuntimeException(msg);
}
private static String getMessage(Object lhs, Object rhs, String op, String msg) {
return (msg == null ? "" : msg + " ") + "(assert failed: " + format(lhs) + " " + op + " " + format(rhs) + ")";
}
}

View file

@ -0,0 +1,64 @@
/*
* 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 com.oracle.java.testlibrary;
import java.util.Objects;
/**
* Class which runs another Runnable in infinite loop with certain pauses
* between cycles.
*/
public class InfiniteLoop implements Runnable {
private final Runnable target;
private final long mills;
/**
* @param target a target to run in a loop
* @param mills the length of pause time in milliseconds
* @throws NullPointerException if target is null
* @throws IllegalArgumentException if the value of millis is negative
*/
public InfiniteLoop(Runnable target, long mills) {
Objects.requireNonNull(target);
if (mills < 0) {
throw new IllegalArgumentException("mills < 0");
}
this.target = target;
this.mills = mills;
}
@Override
public void run() {
try {
while (true) {
target.run();
Thread.sleep(mills);
}
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
throw new Error(e);
}
}
}

View file

@ -23,6 +23,7 @@
package com.oracle.java.testlibrary;
import java.util.regex.Pattern;
import com.oracle.java.testlibrary.Utils;
public class Platform {
@ -97,29 +98,31 @@ public class Platform {
// Returns true for sparc and sparcv9.
public static boolean isSparc() {
return isArch("sparc");
return isArch("sparc.*");
}
public static boolean isARM() {
return isArch("arm");
return isArch("arm.*");
}
public static boolean isPPC() {
return isArch("ppc");
return isArch("ppc.*");
}
public static boolean isX86() {
// On Linux it's 'i386', Windows 'x86'
return (isArch("i386") || isArch("x86"));
// On Linux it's 'i386', Windows 'x86' without '_64' suffix.
return isArch("(i386)|(x86(?!_64))");
}
public static boolean isX64() {
// On OSX it's 'x86_64' and on other (Linux, Windows and Solaris) platforms it's 'amd64'
return (isArch("amd64") || isArch("x86_64"));
return isArch("(amd64)|(x86_64)");
}
private static boolean isArch(String archname) {
return osArch.toLowerCase().startsWith(archname.toLowerCase());
private static boolean isArch(String archnameRE) {
return Pattern.compile(archnameRE, Pattern.CASE_INSENSITIVE)
.matcher(osArch)
.matches();
}
public static String getOsArch() {

View file

@ -0,0 +1,86 @@
/*
* 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 com.oracle.java.testlibrary;
import java.util.Objects;
import java.util.concurrent.Callable;
/**
* Auxiliary class to run target w/ given timeout.
*/
public class TimeLimitedRunner implements Callable<Void> {
private final long stoptime;
private final long timeout;
private final double factor;
private final Callable<Boolean> target;
/**
* @param timeout a timeout. zero means no time limitation
* @param factor a multiplier used to estimate next iteration time
* @param target a target to run
* @throws NullPointerException if target is null
* @throws IllegalArgumentException if timeout is negative or
factor isn't positive
*/
public TimeLimitedRunner(long timeout, double factor,
Callable<Boolean> target) {
Objects.requireNonNull(target, "target must not be null");
if (timeout < 0) {
throw new IllegalArgumentException("timeout[" + timeout + "] < 0");
}
if (factor <= 0d) {
throw new IllegalArgumentException("factor[" + factor + "] <= 0");
}
this.stoptime = System.currentTimeMillis() + timeout;
this.timeout = timeout;
this.factor = factor;
this.target = target;
}
/**
* Runs @{linkplan target} while it returns true and timeout isn't exceeded
*/
@Override
public Void call() throws Exception {
long maxDuration = 0L;
long iterStart = System.currentTimeMillis();
if (timeout != 0 && iterStart > stoptime) {
return null;
}
while (target.call()) {
if (timeout != 0) {
long iterDuration = System.currentTimeMillis() - iterStart;
maxDuration = Math.max(maxDuration, iterDuration);
iterStart = System.currentTimeMillis();
if (iterStart + (maxDuration * factor) > stoptime) {
System.out.println("Not enough time to continue execution. "
+ "Interrupted.");
break;
}
}
}
return null;
}
}

View file

@ -154,7 +154,14 @@ public class WhiteBox {
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 void forceNMethodSweep() {
try {
forceNMethodSweep0().join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
public native Thread forceNMethodSweep0();
public native Object[] getCodeHeapEntries(int type);
public native int getCompilationActivityMode();
public native Object[] getCodeBlob(long addr);

View file

@ -0,0 +1,134 @@
/*
* 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 com.oracle.java.testlibrary.Asserts;
import com.oracle.java.testlibrary.Platform;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Collections;
import java.util.EnumSet;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
/**
* @test
* @summary Verify that for each group of mutually exclusive predicates defined
* in com.oracle.java.testlibrary.Platform one and only one predicate
* evaluates to true.
* @library /testlibrary
* @run main TestMutuallyExclusivePlatformPredicates
*/
public class TestMutuallyExclusivePlatformPredicates {
private static enum MethodGroup {
ARCH("isARM", "isPPC", "isSparc", "isX86", "isX64"),
BITNESS("is32bit", "is64bit"),
OS("isLinux", "isSolaris", "isWindows", "isOSX"),
VM_TYPE("isClient", "isServer", "isGraal", "isMinimal"),
IGNORED("isEmbedded", "isDebugBuild");
public final List<String> methodNames;
private MethodGroup(String... methodNames) {
this.methodNames = Collections.unmodifiableList(
Arrays.asList(methodNames));
}
}
public static void main(String args[]) {
EnumSet<MethodGroup> notIgnoredMethodGroups
= EnumSet.complementOf(EnumSet.of(MethodGroup.IGNORED));
notIgnoredMethodGroups.forEach(
TestMutuallyExclusivePlatformPredicates::verifyPredicates);
TestMutuallyExclusivePlatformPredicates.verifyCoverage();
}
/**
* Verifies that one and only one predicate method defined in
* {@link com.oracle.java.testlibrary.Platform}, whose name included into
* methodGroup will return {@code true}.
* @param methodGroup The group of methods that should be tested.
*/
private static void verifyPredicates(MethodGroup methodGroup) {
System.out.println("Verifying method group: " + methodGroup.name());
long truePredicatesCount = methodGroup.methodNames.stream()
.filter(TestMutuallyExclusivePlatformPredicates
::evaluatePredicate)
.count();
Asserts.assertEQ(truePredicatesCount, 1L, String.format(
"Only one predicate from group %s should be evaluated to true "
+ "(Actually %d predicates were evaluated to true).",
methodGroup.name(), truePredicatesCount));
}
/**
* Verifies that all predicates defined in
* {@link com.oracle.java.testlibrary.Platform} were either tested or
* explicitly ignored.
*/
private static void verifyCoverage() {
Set<String> allMethods = new HashSet<>();
for (MethodGroup group : MethodGroup.values()) {
allMethods.addAll(group.methodNames);
}
for (Method m : Platform.class.getMethods()) {
if (m.getParameterCount() == 0
&& m.getReturnType() == boolean.class) {
Asserts.assertTrue(allMethods.contains(m.getName()),
"All Platform's methods with signature '():Z' should "
+ "be tested ");
}
}
}
/**
* Evaluates predicate method with name {@code name} defined in
* {@link com.oracle.java.testlibrary.Platform}.
*
* @param name The name of a predicate to be evaluated.
* @return evaluated predicate's value.
* @throws java.lang.Error if predicate is not defined or could not be
* evaluated.
*/
private static boolean evaluatePredicate(String name) {
try {
System.out.printf("Trying to evaluate predicate with name %s%n",
name);
boolean value
= (Boolean) Platform.class.getMethod(name).invoke(null);
System.out.printf("Predicate evaluated to: %s%n", value);
return value;
} catch (NoSuchMethodException e) {
throw new Error("Predicate with name " + name
+ " is not defined in " + Platform.class.getName(), e);
} catch (IllegalAccessException | InvocationTargetException e) {
throw new Error("Unable to evaluate predicate " + name, e);
}
}
}