8064669: compiler/whitebox/AllocationCodeBlobTest.java crashes / asserts
Reviewed-by: kvn, anoll
--- a/hotspot/src/share/vm/prims/whitebox.cpp Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/src/share/vm/prims/whitebox.cpp Tue Dec 02 12:36:03 2014 +0300
@@ -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"
@@ -759,8 +760,8 @@
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;
@@ -768,8 +769,37 @@
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))
@@ -819,12 +849,12 @@
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);
}
@@ -900,7 +930,7 @@
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) {
@@ -909,10 +939,10 @@
{
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;
}
@@ -1221,7 +1251,7 @@
{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 },
--- a/hotspot/src/share/vm/prims/whitebox.hpp Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/src/share/vm/prims/whitebox.hpp Tue Dec 02 12:36:03 2014 +0300
@@ -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 @@
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);
--- a/hotspot/src/share/vm/runtime/sweeper.cpp Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/src/share/vm/runtime/sweeper.cpp Tue Dec 02 12:36:03 2014 +0300
@@ -142,9 +142,6 @@
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::_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 @@
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 @@
{
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 @@
// 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 @@
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 @@
}
#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 @@
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 @@
nm->cleanup_inline_caches();
SWEEP(nm);
}
- return freed_memory;
+ return result;
}
if (nm->is_zombie()) {
@@ -541,12 +565,9 @@
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 @@
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 @@
}
// 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 @@
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 @@
nm->cleanup_inline_caches();
SWEEP(nm);
}
- return freed_memory;
+ return result;
}
--- a/hotspot/src/share/vm/runtime/sweeper.hpp Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/src/share/vm/runtime/sweeper.hpp Tue Dec 02 12:36:03 2014 +0300
@@ -56,15 +56,18 @@
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 @@
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();
--- a/hotspot/src/share/vm/runtime/thread.cpp Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/src/share/vm/runtime/thread.cpp Tue Dec 02 12:36:03 2014 +0300
@@ -1076,7 +1076,7 @@
}
-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 @@
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 @@
vmSymbols::thread_void_signature(),
threadObj, // Arg 1
THREAD);
-
-
}
// NamedThread -- non-JavaThread subclasses with multiple
--- a/hotspot/src/share/vm/runtime/thread.hpp Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/src/share/vm/runtime/thread.hpp Tue Dec 02 12:36:03 2014 +0300
@@ -749,6 +749,7 @@
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 @@
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
--- a/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/test/compiler/whitebox/AllocationCodeBlobTest.java Tue Dec 02 12:36:03 2014 +0300
@@ -29,10 +29,11 @@
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 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 @@
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/ForceNMethodSweepTest.java Tue Dec 02 12:36:03 2014 +0300
@@ -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();
+ }
+ }
+}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/testlibrary/com/oracle/java/testlibrary/InfiniteLoop.java Tue Dec 02 12:36:03 2014 +0300
@@ -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);
+ }
+ }
+}
--- a/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Mon Dec 01 22:41:16 2014 +0300
+++ b/hotspot/test/testlibrary/whitebox/sun/hotspot/WhiteBox.java Tue Dec 02 12:36:03 2014 +0300
@@ -153,7 +153,14 @@
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);