--- old/src/java.base/share/classes/java/lang/ref/Reference.java 2015-08-11 16:57:10.088151627 +0300 +++ new/src/java.base/share/classes/java/lang/ref/Reference.java 2015-08-11 16:57:09.988152068 +0300 @@ -311,4 +311,20 @@ this.queue = (queue == null) ? ReferenceQueue.NULL : queue; } + /** + * Ensures that the object referenced by the given reference + * remains strongly reachable (as defined in the {@link + * java.lang.ref} package documentation), regardless of any prior + * actions of the program that might otherwise cause the object to + * become unreachable; thus, the referenced object is not + * reclaimable by garbage collection at least until after the + * invocation of this method. Invocation of this method does not + * itself initiate garbage collection or finalization. + * + * @implNote This method is treated specially in VM. + * @param ref the reference. If null, this method has no effect. + */ + @HotSpotIntrinsicCandidate + public static void reachabilityFence(Object ref) {} + } --- /dev/null 2015-07-26 14:44:42.425548828 +0300 +++ new/test/java/lang/ref/ReachabilityFence.java 2015-08-11 16:57:10.212151078 +0300 @@ -0,0 +1,139 @@ +/* + * Copyright (c) 1997, 2012, 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 + * @summary Tests if reachabilityFence is working + * + * @run main/othervm/timeout=600 -Xint -Dpremature=false ReachabilityFence + * @run main/othervm/timeout=600 -XX:TieredStopAtLevel=1 -Dpremature=true ReachabilityFence + * @run main/othervm/timeout=600 -XX:TieredStopAtLevel=2 -Dpremature=true ReachabilityFence + * @run main/othervm/timeout=600 -XX:TieredStopAtLevel=3 -Dpremature=true ReachabilityFence + * @run main/othervm/timeout=600 -XX:TieredStopAtLevel=4 -Dpremature=true ReachabilityFence + */ + +import java.lang.IllegalStateException; +import java.lang.Object; +import java.lang.Override; +import java.lang.Throwable; +import java.lang.ref.*; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.util.Vector; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; + + +public class ReachabilityFence { + + /* + * Implementation notes: + * + * This test has positive and negative parts. + * + * Negative test is "nonFenced", and it tests that absent of reachabilityFence, the object can + * be prematurely finalized -- this validates the test itself. Not every VM mode is expected to + * prematurely finalize the objects, and -Dpremature option communicates that to test. If a VM mode + * passes the negative test, then our understanding of what could happen is correct, and we can + * go forward. + * + * Positive test is "fenced", and it checks that given the reachabilityFence at the end of the block, + * the object cannot be finalized. There is no sense running a positive test when premature finalization + * is not expected. It is a job for negative test to verify that invariant. + * + * The test methods should be appropriately compiled, therefore we do several iterations. + */ + + static final long NEGATIVE_ITERS = 5; + static final long POSITIVE_ITERS = 5; + static final long NEGATIVE_TIMEOUT = TimeUnit.SECONDS.toNanos(30); + static final long POSITIVE_TIMEOUT = TimeUnit.SECONDS.toNanos(30); + + static final boolean PREMATURE_FINALIZATION = Boolean.getBoolean("premature"); + + public static void main(String... args) { + boolean finalized = false; + for (int c = 0; c < NEGATIVE_ITERS; c++) { + finalized |= nonFenced(); + } + if (PREMATURE_FINALIZATION && !finalized) { + throw new IllegalStateException("The object had never been finalized before timeout reached."); + } + + if (!PREMATURE_FINALIZATION && finalized) { + throw new IllegalStateException("The object had been finalized without a fence, even though we don't expect it."); + } + + for (int c = 0; c < POSITIVE_ITERS; c++) { + fenced(); + } + } + + public static boolean nonFenced() { + AtomicBoolean finalized = new AtomicBoolean(); + MyFinalizeable o = new MyFinalizeable(finalized); + + long time1 = System.nanoTime(); + long time2 = time1; + while (time2 - time1 < NEGATIVE_TIMEOUT) { + if (finalized.get()) break; + System.gc(); + time2 = System.nanoTime(); + } + + return finalized.get(); + } + + public static void fenced() { + if (!PREMATURE_FINALIZATION) return; + + AtomicBoolean finalized = new AtomicBoolean(); + MyFinalizeable o = new MyFinalizeable(finalized); + + long time1 = System.nanoTime(); + long time2 = time1; + while (time2 - time1 < POSITIVE_TIMEOUT) { + if (finalized.get()) { + throw new IllegalStateException("The object had been prematurely finalized."); + } + System.gc(); + time2 = System.nanoTime(); + } + + Reference.reachabilityFence(o); + } + + private static class MyFinalizeable { + private final AtomicBoolean finalized; + + public MyFinalizeable(AtomicBoolean b) { + this.finalized = b; + } + + @Override + protected void finalize() throws Throwable { + super.finalize(); + finalized.set(true); + } + } + +}