< prev index next >

src/java.base/share/classes/sun/nio/cs/StreamEncoder.java

Print this page
@@ -36,15 +36,16 @@
  import java.nio.charset.CharsetEncoder;
  import java.nio.charset.CoderResult;
  import java.nio.charset.CodingErrorAction;
  import java.nio.charset.IllegalCharsetNameException;
  import java.nio.charset.UnsupportedCharsetException;
+ import jdk.internal.misc.InternalLock;
  
- public class StreamEncoder extends Writer
- {
+ public final class StreamEncoder extends Writer {
  
-     private static final int DEFAULT_BYTE_BUFFER_SIZE = 8192;
+     private static final int INITIAL_BYTE_BUFFER_CAPACITY = 512;
+     private static final int MAX_BYTE_BUFFER_CAPACITY = 8192;
  
      private volatile boolean closed;
  
      private void ensureOpen() throws IOException {
          if (closed)

@@ -104,35 +105,61 @@
              return encodingName();
          return null;
      }
  
      public void flushBuffer() throws IOException {
-         synchronized (lock) {
-             if (isOpen())
-                 implFlushBuffer();
-             else
-                 throw new IOException("Stream closed");
+         if (lock instanceof InternalLock locker) {
+             locker.lock();
+             try {
+                 lockedFlushBuffer();
+             } finally {
+                 locker.unlock();
+             }
+         } else {
+             synchronized (super.lock) {
+                 lockedFlushBuffer();
+             }
          }
      }
  
+     private void lockedFlushBuffer() throws IOException {
+         if (isOpen())
+             implFlushBuffer();
+         else
+             throw new IOException("Stream closed");
+     }
+ 
      public void write(int c) throws IOException {
          char[] cbuf = new char[1];
          cbuf[0] = (char) c;
          write(cbuf, 0, 1);
      }
  
      public void write(char[] cbuf, int off, int len) throws IOException {
-         synchronized (lock) {
-             ensureOpen();
-             if ((off < 0) || (off > cbuf.length) || (len < 0) ||
-                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
-                 throw new IndexOutOfBoundsException();
-             } else if (len == 0) {
-                 return;
+         if (lock instanceof InternalLock locker) {
+             locker.lock();
+             try {
+                 lockedWrite(cbuf, off, len);
+             } finally {
+                 locker.unlock();
              }
-             implWrite(cbuf, off, len);
+         } else {
+             synchronized (super.lock) {
+                 lockedWrite(cbuf, off, len);
+             }
+         }
+     }
+ 
+     private void lockedWrite(char[] cbuf, int off, int len) throws IOException {
+         ensureOpen();
+         if ((off < 0) || (off > cbuf.length) || (len < 0) ||
+                 ((off + len) > cbuf.length) || ((off + len) < 0)) {
+             throw new IndexOutOfBoundsException();
+         } else if (len == 0) {
+             return;
          }
+         implWrite(cbuf, off, len);
      }
  
      public void write(String str, int off, int len) throws IOException {
          /* Check the len before creating a char buffer */
          if (len < 0)

@@ -143,48 +170,88 @@
      }
  
      public void write(CharBuffer cb) throws IOException {
          int position = cb.position();
          try {
-             synchronized (lock) {
-                 ensureOpen();
-                 implWrite(cb);
+             if (lock instanceof InternalLock locker) {
+                 locker.lock();
+                 try {
+                     lockedWrite(cb);
+                 } finally {
+                     locker.unlock();
+                 }
+             } else {
+                 synchronized (super.lock) {
+                     lockedWrite(cb);
+                 }
              }
          } finally {
              cb.position(position);
          }
      }
  
+     private void lockedWrite(CharBuffer cb) throws IOException {
+         ensureOpen();
+         implWrite(cb);
+     }
+ 
      public void flush() throws IOException {
-         synchronized (lock) {
-             ensureOpen();
-             implFlush();
+         if (lock instanceof InternalLock locker) {
+             locker.lock();
+             try {
+                 lockedFlush();
+             } finally {
+                 locker.unlock();
+             }
+         } else {
+             synchronized (lock) {
+                 lockedFlush();
+             }
          }
      }
  
+     private void lockedFlush() throws IOException {
+         ensureOpen();
+         implFlush();
+     }
+ 
      public void close() throws IOException {
-         synchronized (lock) {
-             if (closed)
-                 return;
+         if (lock instanceof InternalLock locker) {
+             locker.lock();
              try {
-                 implClose();
+                 lockedClose();
              } finally {
-                 closed = true;
+                 locker.unlock();
+             }
+         } else {
+             synchronized (lock) {
+                 lockedClose();
              }
          }
      }
  
+     private void lockedClose() throws IOException {
+         if (closed)
+             return;
+         try {
+             implClose();
+         } finally {
+             closed = true;
+         }
+     }
+ 
      private boolean isOpen() {
          return !closed;
      }
  
  
      // -- Charset-based stream encoder impl --
  
      private final Charset cs;
      private final CharsetEncoder encoder;
-     private final ByteBuffer bb;
+     private ByteBuffer bb;
+     private final int maxBufferCapacity;
  
      // Exactly one of these is non-null
      private final OutputStream out;
      private final WritableByteChannel ch;
  

@@ -204,21 +271,28 @@
          super(lock);
          this.out = out;
          this.ch = null;
          this.cs = enc.charset();
          this.encoder = enc;
-         this.bb = ByteBuffer.allocate(DEFAULT_BYTE_BUFFER_SIZE);
+ 
+         this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
+         this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
      }
  
      private StreamEncoder(WritableByteChannel ch, CharsetEncoder enc, int mbc) {
          this.out = null;
          this.ch = ch;
          this.cs = enc.charset();
          this.encoder = enc;
-         this.bb = ByteBuffer.allocate(mbc < 0
-                                   ? DEFAULT_BYTE_BUFFER_SIZE
-                                   : mbc);
+ 
+         if (mbc > 0) {
+             this.bb = ByteBuffer.allocate(mbc);
+             this.maxBufferCapacity = mbc;
+         } else {
+             this.bb = ByteBuffer.allocate(INITIAL_BYTE_BUFFER_CAPACITY);
+             this.maxBufferCapacity = MAX_BYTE_BUFFER_CAPACITY;
+         }
      }
  
      private void writeBytes() throws IOException {
          bb.flip();
          int lim = bb.limit();

@@ -287,10 +361,12 @@
      {
          if (haveLeftoverChar) {
              flushLeftoverChar(cb, false);
          }
  
+         growByteBufferIfNeeded(cb.remaining());
+ 
          while (cb.hasRemaining()) {
              CoderResult cr = encoder.encode(cb, bb, false);
              if (cr.isUnderflow()) {
                  assert (cb.remaining() <= 1) : cb.remaining();
                  if (cb.remaining() == 1) {

@@ -306,10 +382,25 @@
              }
              cr.throwException();
          }
      }
  
+     /**
+      * Grows bb to a capacity to allow len characters be encoded.
+      */
+     void growByteBufferIfNeeded(int len) throws IOException {
+         int cap = bb.capacity();
+         if (cap < maxBufferCapacity) {
+             int maxBytes = len * Math.round(encoder.maxBytesPerChar());
+             int newCap = Math.min(maxBytes, maxBufferCapacity);
+             if (newCap > cap) {
+                 implFlushBuffer();
+                 bb = ByteBuffer.allocate(newCap);
+             }
+         }
+     }
+ 
      void implFlushBuffer() throws IOException {
          if (bb.position() > 0) {
              writeBytes();
          }
      }
< prev index next >