@@ -57,6 +57,8 @@ public class BufferedInputStream extends FilterInputStream {
57
57
58
58
private static final int DEFAULT_BUFFER_SIZE = 8192 ;
59
59
60
+ private static final byte [] EMPTY = new byte [0 ];
61
+
60
62
/**
61
63
* As this class is used early during bootstrap, it's motivated to use
62
64
* Unsafe.compareAndSetObject instead of AtomicReferenceFieldUpdater
@@ -70,6 +72,9 @@ public class BufferedInputStream extends FilterInputStream {
70
72
// initialized to null when BufferedInputStream is sub-classed
71
73
private final InternalLock lock ;
72
74
75
+ // initial buffer size (DEFAULT_BUFFER_SIZE or size specified to constructor)
76
+ private final int initialSize ;
77
+
73
78
/**
74
79
* The internal buffer array where the data is stored. When necessary,
75
80
* it may be replaced by another array of
@@ -166,16 +171,42 @@ private InputStream getInIfOpen() throws IOException {
166
171
}
167
172
168
173
/**
169
- * Check to make sure that buffer has not been nulled out due to
170
- * close; if not return it;
174
+ * Returns the internal buffer, optionally allocating it if empty.
175
+ * @param allocateIfEmpty true to allocate if empty
176
+ * @throws IOException if the stream is closed (buf is null)
171
177
*/
172
- private byte [] getBufIfOpen () throws IOException {
178
+ private byte [] getBufIfOpen (boolean allocateIfEmpty ) throws IOException {
173
179
byte [] buffer = buf ;
174
- if (buffer == null )
180
+ if (allocateIfEmpty && buffer == EMPTY ) {
181
+ buffer = new byte [initialSize ];
182
+ if (!U .compareAndSetReference (this , BUF_OFFSET , EMPTY , buffer )) {
183
+ // re-read buf
184
+ buffer = buf ;
185
+ }
186
+ }
187
+ if (buffer == null ) {
175
188
throw new IOException ("Stream closed" );
189
+ }
176
190
return buffer ;
177
191
}
178
192
193
+ /**
194
+ * Returns the internal buffer, allocating it if empty.
195
+ * @throws IOException if the stream is closed (buf is null)
196
+ */
197
+ private byte [] getBufIfOpen () throws IOException {
198
+ return getBufIfOpen (true );
199
+ }
200
+
201
+ /**
202
+ * Throws IOException if the stream is closed (buf is null).
203
+ */
204
+ private void ensureOpen () throws IOException {
205
+ if (buf == null ) {
206
+ throw new IOException ("Stream closed" );
207
+ }
208
+ }
209
+
179
210
/**
180
211
* Creates a {@code BufferedInputStream}
181
212
* and saves its argument, the input stream
@@ -205,13 +236,15 @@ public BufferedInputStream(InputStream in, int size) {
205
236
if (size <= 0 ) {
206
237
throw new IllegalArgumentException ("Buffer size <= 0" );
207
238
}
208
- buf = new byte [size ];
209
-
210
- // use monitors when BufferedInputStream is sub-classed
239
+ initialSize = size ;
211
240
if (getClass () == BufferedInputStream .class ) {
241
+ // use internal lock and lazily create buffer when not subclassed
212
242
lock = InternalLock .newLockOrNull ();
243
+ buf = EMPTY ;
213
244
} else {
245
+ // use monitors and eagerly create buffer when subclassed
214
246
lock = null ;
247
+ buf = new byte [size ];
215
248
}
216
249
}
217
250
@@ -307,7 +340,8 @@ private int read1(byte[] b, int off, int len) throws IOException {
307
340
if there is no mark/reset activity, do not bother to copy the
308
341
bytes into the local buffer. In this way buffered streams will
309
342
cascade harmlessly. */
310
- if (len >= getBufIfOpen ().length && markpos == -1 ) {
343
+ int size = Math .max (getBufIfOpen (false ).length , initialSize );
344
+ if (len >= size && markpos == -1 ) {
311
345
return getInIfOpen ().read (b , off , len );
312
346
}
313
347
fill ();
@@ -374,7 +408,7 @@ public int read(byte[] b, int off, int len) throws IOException {
374
408
}
375
409
376
410
private int implRead (byte [] b , int off , int len ) throws IOException {
377
- getBufIfOpen (); // Check for closed stream
411
+ ensureOpen ();
378
412
if ((off | len | (off + len ) | (b .length - (off + len ))) < 0 ) {
379
413
throw new IndexOutOfBoundsException ();
380
414
} else if (len == 0 ) {
@@ -421,7 +455,7 @@ public long skip(long n) throws IOException {
421
455
}
422
456
423
457
private long implSkip (long n ) throws IOException {
424
- getBufIfOpen (); // Check for closed stream
458
+ ensureOpen ();
425
459
if (n <= 0 ) {
426
460
return 0 ;
427
461
}
@@ -544,7 +578,7 @@ public void reset() throws IOException {
544
578
}
545
579
546
580
private void implReset () throws IOException {
547
- getBufIfOpen (); // Cause exception if closed
581
+ ensureOpen ();
548
582
if (markpos < 0 )
549
583
throw new IOException ("Resetting to invalid mark" );
550
584
pos = markpos ;
1 commit comments
openjdk-notifier[bot] commentedon Apr 6, 2023
Review
Issues