RFR 8170155: StringBuffer and StringBuilder stream methods are not late-binding (original) (raw)

Paul Sandoz paul.sandoz at oracle.com
Mon Nov 28 19:27:06 UTC 2016


On 25 Nov 2016, at 02:47, Tobias Hartmann <tobias.hartmann at oracle.com> wrote:

I'm not sure if it is still desired to do the same boundary check in case of LATIN1 for the benefit of consistency. Assume there might be concurrent access/operation between val = this.value and count = this.count; (for StringBuilder) for example, the this.value got doubled and the this.count got increased. One will end up with StringIndexOutOfBoundsException() from checkOffset, but the other will be ioobe from vm? You mean when hitting a check in an intrinsic compared to when hitting a check in the Java wrapper?

Not quite. There is a spliterator implementation for each coder, in the case of the LATIN1 coder there are no associated intrinsics. I think it’s ok just to perform the explicit bounds check for the UTF16 coder, since for the LATIN1 bounds checks will be performed by baloads.

However, i think there is bug. The coder could change from LATIN1 to UTF16, while holding a reference to a byte[] value as LATIN1.

For StringBuilder i could fix that by atomically reading the value/count/coder, but there is still an issue with StringBuffer. Thus, in the UTF16 coder spliterator we need to perform the explicit bounds before every StringUTF16.getChar().

Webrev updated:

http://cr.openjdk.java.net/~psandoz/jdk9/JDK-8170155-string-buffer-builder-late-binding/webrev/

Paul.

Actually, bound checks should always be done in the Java wrapper method that calls the (unchecked) intrinsic. In general, the unchecked intrinsic should not be called directly. StringUTF16.putChar/getChar() is an exception because there are places where we we need to omit the check for performance reasons.

I'm planning to revisit this with JDK-8156534 in JDK 10. Best regards, Tobias

Sherman

If so i propose the following to make this clearer: return StreamSupport.intStream( () -> { byte[] val = this.value; int count = this.count; if (coder == LATIN1) { return new StringLatin1.CharsSpliterator(val, 0, count, 0); } else { // Perform an explicit bounds check since HotSpot // intrinsics to access UTF-16 characters in the byte[] // array will not perform bounds checks checkOffset(count, val.length>> coder); return new StringUTF16.CharsSpliterator(val, 0, count, 0); } }, Spliterator.ORDERED | Spliterator.SIZED | Spliterator.SUBSIZED, false); Paul.



More information about the core-libs-dev mailing list