# HG changeset patch # User redestad # Date 1459712436 -7200 # Sun Apr 03 21:40:36 2016 +0200 # Node ID 2e7e22837c8552f0253f25fd34df37f080e8120c # Parent 68f8be44b6a6b33dfa841ec671c0ba6e4056b372 8153334: Replace BufferedInputStreams use of AtomicReferenceFieldUpdater with Unsafe Reviewed-by: alanb, forax diff --git a/src/java.base/share/classes/java/io/BufferedInputStream.java b/src/java.base/share/classes/java/io/BufferedInputStream.java --- a/src/java.base/share/classes/java/io/BufferedInputStream.java +++ b/src/java.base/share/classes/java/io/BufferedInputStream.java @@ -24,7 +24,8 @@ */ package java.io; -import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; + +import jdk.internal.misc.Unsafe; /** * A BufferedInputStream adds @@ -68,15 +69,21 @@ protected volatile byte buf[]; /** - * Atomic updater to provide compareAndSet for buf. This is - * necessary because closes can be asynchronous. We use nullness + * Get Unsafe and offset of buf to provide compareAndSet functionality. + * This is necessary because closes can be asynchronous. We use nullness * of buf[] as primary indicator that this stream is closed. (The * "in" field is also nulled out on close.) */ - private static final - AtomicReferenceFieldUpdater bufUpdater = - AtomicReferenceFieldUpdater.newUpdater - (BufferedInputStream.class, byte[].class, "buf"); + private static final Unsafe UNSAFE = Unsafe.getUnsafe(); + private static final long BUF_OFFSET; + static { + try { + BUF_OFFSET = UNSAFE.objectFieldOffset( + BufferedInputStream.class.getDeclaredField("buf")); + } catch (ReflectiveOperationException e) { + throw new Error(e); + } + } /** * The index one greater than the index of the last valid byte in @@ -212,9 +219,9 @@ */ private void fill() throws IOException { byte[] buffer = getBufIfOpen(); - if (markpos < 0) + if (markpos < 0) { pos = 0; /* no mark: throw away the buffer */ - else if (pos >= buffer.length) /* no room left in buffer */ + } else if (pos >= buffer.length) { /* no room left in buffer */ if (markpos > 0) { /* can throw away early part of the buffer */ int sz = pos - markpos; System.arraycopy(buffer, markpos, buffer, 0, sz); @@ -232,7 +239,8 @@ nsz = marklimit; byte nbuf[] = new byte[nsz]; System.arraycopy(buffer, 0, nbuf, 0, pos); - if (!bufUpdater.compareAndSet(this, buffer, nbuf)) { + if (!UNSAFE.compareAndSwapObject(this, BUF_OFFSET, buffer, + nbuf)) { // Can't replace buf if there was an async close. // Note: This would need to be changed if fill() // is ever made accessible to multiple threads. @@ -242,6 +250,7 @@ } buffer = nbuf; } + } count = pos; int n = getInIfOpen().read(buffer, pos, buffer.length - pos); if (n > 0) @@ -476,7 +485,7 @@ public void close() throws IOException { byte[] buffer; while ( (buffer = buf) != null) { - if (bufUpdater.compareAndSet(this, buffer, null)) { + if (UNSAFE.compareAndSwapObject(this, BUF_OFFSET, buffer, null)) { InputStream input = in; in = null; if (input != null)