mirror of
https://github.com/openjdk/jdk.git
synced 2026-01-28 12:09:14 +00:00
8352565: Add native method implementation of Reference.get()
Reviewed-by: vlivanov, tschatzl, lmesnik
This commit is contained in:
parent
7447276475
commit
56c75453cd
@ -141,7 +141,7 @@ bool Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_arraycopy:
|
||||
case vmIntrinsics::_currentTimeMillis:
|
||||
case vmIntrinsics::_nanoTime:
|
||||
case vmIntrinsics::_Reference_get:
|
||||
case vmIntrinsics::_Reference_get0:
|
||||
// Use the intrinsic version of Reference.get() so that the value in
|
||||
// the referent field can be registered by the G1 pre-barrier code.
|
||||
// Also to prevent commoning reads from this field across safepoint
|
||||
|
||||
@ -3340,7 +3340,7 @@ GraphBuilder::GraphBuilder(Compilation* compilation, IRScope* scope)
|
||||
break;
|
||||
}
|
||||
|
||||
case vmIntrinsics::_Reference_get:
|
||||
case vmIntrinsics::_Reference_get0:
|
||||
{
|
||||
{
|
||||
// With java.lang.ref.reference.get() we must go through the
|
||||
|
||||
@ -1185,7 +1185,7 @@ void LIRGenerator::do_Return(Return* x) {
|
||||
|
||||
// Example: ref.get()
|
||||
// Combination of LoadField and g1 pre-write barrier
|
||||
void LIRGenerator::do_Reference_get(Intrinsic* x) {
|
||||
void LIRGenerator::do_Reference_get0(Intrinsic* x) {
|
||||
|
||||
const int referent_offset = java_lang_ref_Reference::referent_offset();
|
||||
|
||||
@ -2914,8 +2914,8 @@ void LIRGenerator::do_Intrinsic(Intrinsic* x) {
|
||||
case vmIntrinsics::_onSpinWait:
|
||||
__ on_spin_wait();
|
||||
break;
|
||||
case vmIntrinsics::_Reference_get:
|
||||
do_Reference_get(x);
|
||||
case vmIntrinsics::_Reference_get0:
|
||||
do_Reference_get0(x);
|
||||
break;
|
||||
|
||||
case vmIntrinsics::_updateCRC32:
|
||||
|
||||
@ -266,7 +266,7 @@ class LIRGenerator: public InstructionVisitor, public BlockClosure {
|
||||
void do_CompareAndSwap(Intrinsic* x, ValueType* type);
|
||||
void do_PreconditionsCheckIndex(Intrinsic* x, BasicType type);
|
||||
void do_FPIntrinsics(Intrinsic* x);
|
||||
void do_Reference_get(Intrinsic* x);
|
||||
void do_Reference_get0(Intrinsic* x);
|
||||
void do_update_CRC32(Intrinsic* x);
|
||||
void do_update_CRC32C(Intrinsic* x);
|
||||
void do_vectorizedMismatch(Intrinsic* x);
|
||||
|
||||
@ -99,7 +99,7 @@ bool vmIntrinsics::preserves_state(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_dpow:
|
||||
case vmIntrinsics::_Preconditions_checkIndex:
|
||||
case vmIntrinsics::_Preconditions_checkLongIndex:
|
||||
case vmIntrinsics::_Reference_get:
|
||||
case vmIntrinsics::_Reference_get0:
|
||||
case vmIntrinsics::_Continuation_doYield:
|
||||
case vmIntrinsics::_updateCRC32:
|
||||
case vmIntrinsics::_updateBytesCRC32:
|
||||
@ -244,7 +244,7 @@ bool vmIntrinsics::disabled_by_jvm_flags(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_storeFence:
|
||||
case vmIntrinsics::_fullFence:
|
||||
case vmIntrinsics::_countPositives:
|
||||
case vmIntrinsics::_Reference_get:
|
||||
case vmIntrinsics::_Reference_get0:
|
||||
case vmIntrinsics::_Continuation_doYield:
|
||||
case vmIntrinsics::_Continuation_enterSpecial:
|
||||
case vmIntrinsics::_Continuation_pin:
|
||||
|
||||
@ -461,7 +461,7 @@ class methodHandle;
|
||||
do_signature(vectorizedMismatch_signature, "(Ljava/lang/Object;JLjava/lang/Object;JII)I") \
|
||||
\
|
||||
/* java/lang/ref/Reference */ \
|
||||
do_intrinsic(_Reference_get, java_lang_ref_Reference, get_name, void_object_signature, F_R) \
|
||||
do_intrinsic(_Reference_get0, java_lang_ref_Reference, get0_name, void_object_signature, F_RN) \
|
||||
do_intrinsic(_Reference_refersTo0, java_lang_ref_Reference, refersTo0_name, object_boolean_signature, F_RN) \
|
||||
do_intrinsic(_PhantomReference_refersTo0, java_lang_ref_PhantomReference, refersTo0_name, object_boolean_signature, F_RN) \
|
||||
do_intrinsic(_Reference_clear0, java_lang_ref_Reference, clear0_name, void_method_signature, F_RN) \
|
||||
|
||||
@ -422,7 +422,7 @@ class SerializeClosure;
|
||||
template(sp_name, "sp") \
|
||||
template(pc_name, "pc") \
|
||||
template(cs_name, "cs") \
|
||||
template(get_name, "get") \
|
||||
template(get0_name, "get0") \
|
||||
template(refersTo0_name, "refersTo0") \
|
||||
template(clear0_name, "clear0") \
|
||||
template(put_name, "put") \
|
||||
|
||||
@ -353,6 +353,9 @@ JVM_HasReferencePendingList(JNIEnv *env);
|
||||
JNIEXPORT void JNICALL
|
||||
JVM_WaitForReferencePendingList(JNIEnv *env);
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
JVM_ReferenceGet(JNIEnv *env, jobject ref);
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
JVM_ReferenceRefersTo(JNIEnv *env, jobject ref, jobject o);
|
||||
|
||||
|
||||
@ -148,7 +148,7 @@ AbstractInterpreter::MethodKind AbstractInterpreter::method_kind(const methodHan
|
||||
case vmIntrinsics::_fmaF: return java_lang_math_fmaF;
|
||||
case vmIntrinsics::_dsqrt: return java_lang_math_sqrt;
|
||||
case vmIntrinsics::_dsqrt_strict: return java_lang_math_sqrt_strict;
|
||||
case vmIntrinsics::_Reference_get: return java_lang_ref_reference_get;
|
||||
case vmIntrinsics::_Reference_get0: return java_lang_ref_reference_get0;
|
||||
case vmIntrinsics::_Object_init:
|
||||
if (m->code_size() == 1) {
|
||||
// We need to execute the special return bytecode to check for
|
||||
@ -210,7 +210,7 @@ vmIntrinsics::ID AbstractInterpreter::method_intrinsic(MethodKind kind) {
|
||||
case java_lang_math_exp : return vmIntrinsics::_dexp;
|
||||
case java_lang_math_fmaD : return vmIntrinsics::_fmaD;
|
||||
case java_lang_math_fmaF : return vmIntrinsics::_fmaF;
|
||||
case java_lang_ref_reference_get: return vmIntrinsics::_Reference_get;
|
||||
case java_lang_ref_reference_get0: return vmIntrinsics::_Reference_get0;
|
||||
case java_util_zip_CRC32_update : return vmIntrinsics::_updateCRC32;
|
||||
case java_util_zip_CRC32_updateBytes
|
||||
: return vmIntrinsics::_updateBytesCRC32;
|
||||
@ -320,7 +320,7 @@ void AbstractInterpreter::print_method_kind(MethodKind kind) {
|
||||
case java_util_zip_CRC32_updateByteBuffer : tty->print("java_util_zip_CRC32_updateByteBuffer"); break;
|
||||
case java_util_zip_CRC32C_updateBytes : tty->print("java_util_zip_CRC32C_updateBytes"); break;
|
||||
case java_util_zip_CRC32C_updateDirectByteBuffer: tty->print("java_util_zip_CRC32C_updateDirectByteByffer"); break;
|
||||
case java_lang_ref_reference_get : tty->print("java_lang_ref_reference_get"); break;
|
||||
case java_lang_ref_reference_get0 : tty->print("java_lang_ref_reference_get0"); break;
|
||||
case java_lang_Thread_currentThread : tty->print("java_lang_Thread_currentThread"); break;
|
||||
case java_lang_Float_float16ToFloat : tty->print("java_lang_Float_float16ToFloat"); break;
|
||||
case java_lang_Float_floatToFloat16 : tty->print("java_lang_Float_floatToFloat16"); break;
|
||||
|
||||
@ -83,7 +83,7 @@ class AbstractInterpreter: AllStatic {
|
||||
java_lang_math_exp, // implementation of java.lang.Math.exp (x)
|
||||
java_lang_math_fmaF, // implementation of java.lang.Math.fma (x, y, z)
|
||||
java_lang_math_fmaD, // implementation of java.lang.Math.fma (x, y, z)
|
||||
java_lang_ref_reference_get, // implementation of java.lang.ref.Reference.get()
|
||||
java_lang_ref_reference_get0, // implementation of java.lang.ref.Reference.get()
|
||||
java_util_zip_CRC32_update, // implementation of java.util.zip.CRC32.update()
|
||||
java_util_zip_CRC32_updateBytes, // implementation of java.util.zip.CRC32.updateBytes()
|
||||
java_util_zip_CRC32_updateByteBuffer, // implementation of java.util.zip.CRC32.updateByteBuffer()
|
||||
|
||||
@ -204,7 +204,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
||||
method_entry(java_lang_math_pow )
|
||||
method_entry(java_lang_math_fmaF )
|
||||
method_entry(java_lang_math_fmaD )
|
||||
method_entry(java_lang_ref_reference_get)
|
||||
method_entry(java_lang_ref_reference_get0)
|
||||
AbstractInterpreter::initialize_method_handle_entries();
|
||||
|
||||
method_entry(java_util_zip_CRC32C_updateBytes)
|
||||
@ -228,6 +228,7 @@ void TemplateInterpreterGenerator::generate_all() {
|
||||
// entries for `native` methods to use the same address in case
|
||||
// intrinsic is disabled.
|
||||
native_method_entry(java_lang_Thread_currentThread)
|
||||
native_method_entry(java_lang_ref_reference_get0)
|
||||
|
||||
native_method_entry(java_util_zip_CRC32_update)
|
||||
native_method_entry(java_util_zip_CRC32_updateBytes)
|
||||
@ -465,7 +466,7 @@ address TemplateInterpreterGenerator::generate_intrinsic_entry(AbstractInterpret
|
||||
case Interpreter::java_lang_math_fmaF : entry_point = generate_math_entry(kind); break;
|
||||
case Interpreter::java_lang_math_sqrt_strict
|
||||
: entry_point = generate_math_entry(Interpreter::java_lang_math_sqrt); break;
|
||||
case Interpreter::java_lang_ref_reference_get
|
||||
case Interpreter::java_lang_ref_reference_get0
|
||||
: entry_point = generate_Reference_get_entry(); break;
|
||||
case Interpreter::java_util_zip_CRC32_update
|
||||
: entry_point = generate_CRC32_update_entry(); break;
|
||||
|
||||
@ -64,7 +64,7 @@ void ZeroInterpreterGenerator::generate_all() {
|
||||
method_entry(java_lang_math_exp );
|
||||
method_entry(java_lang_math_fmaD );
|
||||
method_entry(java_lang_math_fmaF );
|
||||
method_entry(java_lang_ref_reference_get);
|
||||
method_entry(java_lang_ref_reference_get0);
|
||||
|
||||
AbstractInterpreter::initialize_method_handle_entries();
|
||||
|
||||
@ -107,7 +107,7 @@ address ZeroInterpreterGenerator::generate_method_entry(
|
||||
case Interpreter::java_lang_math_exp : // fall thru
|
||||
case Interpreter::java_lang_math_fmaD : // fall thru
|
||||
case Interpreter::java_lang_math_fmaF : entry_point = generate_math_entry(kind); break;
|
||||
case Interpreter::java_lang_ref_reference_get
|
||||
case Interpreter::java_lang_ref_reference_get0
|
||||
: entry_point = generate_Reference_get_entry(); break;
|
||||
default:
|
||||
fatal("unexpected method kind: %d", kind);
|
||||
|
||||
@ -767,7 +767,7 @@ bool C2Compiler::is_intrinsic_supported(vmIntrinsics::ID id) {
|
||||
case vmIntrinsics::_doubleToRawLongBits:
|
||||
case vmIntrinsics::_doubleToLongBits:
|
||||
case vmIntrinsics::_longBitsToDouble:
|
||||
case vmIntrinsics::_Reference_get:
|
||||
case vmIntrinsics::_Reference_get0:
|
||||
case vmIntrinsics::_Reference_refersTo0:
|
||||
case vmIntrinsics::_PhantomReference_refersTo0:
|
||||
case vmIntrinsics::_Reference_clear0:
|
||||
|
||||
@ -783,19 +783,9 @@ Compile::Compile(ciEnv* ci_env, ciMethod* target, int osr_bci,
|
||||
StartNode* s = new StartNode(root(), tf()->domain());
|
||||
initial_gvn()->set_type_bottom(s);
|
||||
verify_start(s);
|
||||
if (method()->intrinsic_id() == vmIntrinsics::_Reference_get) {
|
||||
// With java.lang.ref.reference.get() we must go through the
|
||||
// intrinsic - even when get() is the root
|
||||
// method of the compile - so that, if necessary, the value in
|
||||
// the referent field of the reference object gets recorded by
|
||||
// the pre-barrier code.
|
||||
cg = find_intrinsic(method(), false);
|
||||
}
|
||||
if (cg == nullptr) {
|
||||
float past_uses = method()->interpreter_invocation_count();
|
||||
float expected_uses = past_uses;
|
||||
cg = CallGenerator::for_inline(method(), expected_uses);
|
||||
}
|
||||
float past_uses = method()->interpreter_invocation_count();
|
||||
float expected_uses = past_uses;
|
||||
cg = CallGenerator::for_inline(method(), expected_uses);
|
||||
}
|
||||
if (failing()) return;
|
||||
if (cg == nullptr) {
|
||||
|
||||
@ -564,7 +564,7 @@ bool LibraryCallKit::try_to_inline(int predicate) {
|
||||
|
||||
case vmIntrinsics::_getCallerClass: return inline_native_Reflection_getCallerClass();
|
||||
|
||||
case vmIntrinsics::_Reference_get: return inline_reference_get();
|
||||
case vmIntrinsics::_Reference_get0: return inline_reference_get0();
|
||||
case vmIntrinsics::_Reference_refersTo0: return inline_reference_refersTo0(false);
|
||||
case vmIntrinsics::_PhantomReference_refersTo0: return inline_reference_refersTo0(true);
|
||||
case vmIntrinsics::_Reference_clear0: return inline_reference_clear0(false);
|
||||
@ -6923,9 +6923,9 @@ bool LibraryCallKit::inline_updateByteBufferAdler32() {
|
||||
return true;
|
||||
}
|
||||
|
||||
//----------------------------inline_reference_get----------------------------
|
||||
//----------------------------inline_reference_get0----------------------------
|
||||
// public T java.lang.ref.Reference.get();
|
||||
bool LibraryCallKit::inline_reference_get() {
|
||||
bool LibraryCallKit::inline_reference_get0() {
|
||||
const int referent_offset = java_lang_ref_Reference::referent_offset();
|
||||
|
||||
// Get the argument:
|
||||
|
||||
@ -300,7 +300,7 @@ class LibraryCallKit : public GraphKit {
|
||||
bool inline_bitshuffle_methods(vmIntrinsics::ID id);
|
||||
bool inline_compare_unsigned(vmIntrinsics::ID id);
|
||||
bool inline_divmod_methods(vmIntrinsics::ID id);
|
||||
bool inline_reference_get();
|
||||
bool inline_reference_get0();
|
||||
bool inline_reference_refersTo0(bool is_phantom);
|
||||
bool inline_reference_clear0(bool is_phantom);
|
||||
bool inline_Class_cast();
|
||||
|
||||
@ -3040,9 +3040,17 @@ JVM_ENTRY(void, JVM_WaitForReferencePendingList(JNIEnv* env))
|
||||
}
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jobject, JVM_ReferenceGet(JNIEnv* env, jobject ref))
|
||||
oop ref_oop = JNIHandles::resolve_non_null(ref);
|
||||
// PhantomReference has its own implementation of get().
|
||||
assert(!java_lang_ref_Reference::is_phantom(ref_oop), "precondition");
|
||||
oop referent = java_lang_ref_Reference::weak_referent(ref_oop);
|
||||
return JNIHandles::make_local(THREAD, referent);
|
||||
JVM_END
|
||||
|
||||
JVM_ENTRY(jboolean, JVM_ReferenceRefersTo(JNIEnv* env, jobject ref, jobject o))
|
||||
oop ref_oop = JNIHandles::resolve_non_null(ref);
|
||||
// PhantomReference has it's own implementation of refersTo().
|
||||
// PhantomReference has its own implementation of refersTo().
|
||||
// See: JVM_PhantomReferenceRefersTo
|
||||
assert(!java_lang_ref_Reference::is_phantom(ref_oop), "precondition");
|
||||
oop referent = java_lang_ref_Reference::weak_referent_no_keepalive(ref_oop);
|
||||
|
||||
@ -357,11 +357,18 @@ public abstract sealed class Reference<@jdk.internal.RequiresIdentity T>
|
||||
* {@code null} if this reference object has been cleared
|
||||
* @see #refersTo
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
public T get() {
|
||||
return this.referent;
|
||||
return get0();
|
||||
}
|
||||
|
||||
/* Implementation of get(). This method exists to avoid making get() all
|
||||
* of virtual, native, and intrinsic candidate. That could have the
|
||||
* undesirable effect of having the native method used instead of the
|
||||
* intrinsic when devirtualization fails.
|
||||
*/
|
||||
@IntrinsicCandidate
|
||||
private native T get0();
|
||||
|
||||
/**
|
||||
* Tests if the referent of this reference object is {@code obj}.
|
||||
* Using a {@code null} {@code obj} returns {@code true} if the
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2020, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2025, 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
|
||||
@ -44,6 +44,12 @@ Java_java_lang_ref_Reference_waitForReferencePendingList(JNIEnv *env, jclass ign
|
||||
JVM_WaitForReferencePendingList(env);
|
||||
}
|
||||
|
||||
JNIEXPORT jobject JNICALL
|
||||
Java_java_lang_ref_Reference_get0(JNIEnv *env, jobject ref)
|
||||
{
|
||||
return JVM_ReferenceGet(env, ref);
|
||||
}
|
||||
|
||||
JNIEXPORT jboolean JNICALL
|
||||
Java_java_lang_ref_Reference_refersTo0(JNIEnv *env, jobject ref, jobject o)
|
||||
{
|
||||
|
||||
181
test/hotspot/jtreg/gc/TestNativeReferenceGet.java
Normal file
181
test/hotspot/jtreg/gc/TestNativeReferenceGet.java
Normal file
@ -0,0 +1,181 @@
|
||||
/*
|
||||
* Copyright (c) 2025, 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. Oracle designates this
|
||||
* particular file as subject to the "Classpath" exception as provided
|
||||
* by Oracle in the LICENSE file that accompanied this code.
|
||||
*
|
||||
* 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 gc;
|
||||
|
||||
/**
|
||||
* @test
|
||||
* @bug 8352565
|
||||
* @summary Determine whether the native method implementation of
|
||||
* Reference.get() works as expected. Disable the intrinsic implementation to
|
||||
* force use of the native method.
|
||||
* @library /test/lib
|
||||
* @modules java.base/java.lang.ref:open
|
||||
* @build jdk.test.whitebox.WhiteBox
|
||||
* @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox
|
||||
* @run main/othervm
|
||||
* -Xbootclasspath/a:.
|
||||
* -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
|
||||
* -XX:DisableIntrinsic=_Reference_get0
|
||||
* gc.TestNativeReferenceGet
|
||||
*/
|
||||
|
||||
import java.lang.ref.ReferenceQueue;
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import jdk.test.whitebox.WhiteBox;
|
||||
|
||||
public final class TestNativeReferenceGet {
|
||||
|
||||
private static final WhiteBox WB = WhiteBox.getWhiteBox();
|
||||
|
||||
private static void gcUntilOld(Object o) {
|
||||
while (!WB.isObjectInOldGen(o)) {
|
||||
WB.fullGC();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class TestObject {
|
||||
public final int value;
|
||||
|
||||
public TestObject(int value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private static final ReferenceQueue<TestObject> queue =
|
||||
new ReferenceQueue<TestObject>();
|
||||
|
||||
private static final class Ref extends WeakReference<TestObject> {
|
||||
public Ref(TestObject obj) {
|
||||
super(obj, queue);
|
||||
}
|
||||
}
|
||||
|
||||
private static final int NUM_REFS = 100;
|
||||
|
||||
private static List<Ref> references = null;
|
||||
private static List<TestObject> referents = null;
|
||||
|
||||
// Create all the objects used by the test, and ensure they are all in the
|
||||
// old generation.
|
||||
private static void setup() {
|
||||
references = new ArrayList<Ref>(NUM_REFS);
|
||||
referents = new ArrayList<TestObject>(NUM_REFS);
|
||||
|
||||
for (int i = 0; i < NUM_REFS; ++i) {
|
||||
TestObject obj = new TestObject(i);
|
||||
referents.add(obj);
|
||||
references.add(new Ref(obj));
|
||||
}
|
||||
|
||||
gcUntilOld(references);
|
||||
gcUntilOld(referents);
|
||||
for (int i = 0; i < NUM_REFS; ++i) {
|
||||
gcUntilOld(references.get(i));
|
||||
gcUntilOld(referents.get(i));
|
||||
}
|
||||
}
|
||||
|
||||
// Discard all the strong references.
|
||||
private static void dropReferents() {
|
||||
// Not using List.clear() because it doesn't document null'ing elements.
|
||||
for (int i = 0; i < NUM_REFS; ++i) {
|
||||
referents.set(i, null);
|
||||
}
|
||||
}
|
||||
|
||||
// Create new strong references from the weak references, by using the
|
||||
// native method implementation of Reference.get() and recording the value
|
||||
// in references.
|
||||
private static void strengthenReferents() {
|
||||
for (int i = 0; i < NUM_REFS; ++i) {
|
||||
referents.set(i, references.get(i).get());
|
||||
}
|
||||
}
|
||||
|
||||
private static void check() {
|
||||
// None of the references should have been cleared and enqueued,
|
||||
// because we have strong references to all the referents.
|
||||
try {
|
||||
while (WB.waitForReferenceProcessing()) {}
|
||||
} catch (InterruptedException e) {
|
||||
throw new RuntimeException("Test interrupted");
|
||||
}
|
||||
if (queue.poll() != null) {
|
||||
throw new RuntimeException("Reference enqueued");
|
||||
}
|
||||
|
||||
// Check details of expected state.
|
||||
for (int i = 0; i < NUM_REFS; ++i) {
|
||||
Ref reference = (Ref) references.get(i);
|
||||
TestObject referent = reference.get();
|
||||
if (referent == null) {
|
||||
throw new RuntimeException("Referent not strengthened");
|
||||
} else if (referent != referents.get(i)) {
|
||||
throw new RuntimeException(
|
||||
"Reference referent differs from saved referent: " + i);
|
||||
} else if (referent.value != i) {
|
||||
throw new RuntimeException(
|
||||
"Referent " + i + " value: " + referent.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void testConcurrent() {
|
||||
System.out.println("Testing concurrent GC");
|
||||
try {
|
||||
WB.concurrentGCAcquireControl();
|
||||
dropReferents();
|
||||
WB.concurrentGCRunTo(WB.BEFORE_MARKING_COMPLETED);
|
||||
strengthenReferents();
|
||||
WB.concurrentGCRunToIdle();
|
||||
check();
|
||||
} finally {
|
||||
WB.concurrentGCReleaseControl();
|
||||
}
|
||||
}
|
||||
|
||||
private static void testNonconcurrent() {
|
||||
System.out.println("Testing nonconcurrent GC");
|
||||
// A GC between clearing and strengthening will result in test failure.
|
||||
// We try to make that unlikely via this immediately preceeding GC.
|
||||
WB.fullGC();
|
||||
dropReferents();
|
||||
strengthenReferents();
|
||||
WB.fullGC();
|
||||
check();
|
||||
}
|
||||
|
||||
public static final void main(String[] args) {
|
||||
setup();
|
||||
if (WB.supportsConcurrentGCBreakpoints()) {
|
||||
testConcurrent();
|
||||
} else {
|
||||
testNonconcurrent();
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
x
Reference in New Issue
Block a user