On Sun, 11 Oct 2026 19:17:30 GMT, Liam Miller-Cushon <[email protected]> wrote:
>> This change adds Vector API methods that load the code units of a >> `java.lang.String` into a vector without copying, to allow processing a >> `String` with a vector loop instead of a scalar loop over `charAt`. >> >> As discussed in the [panama-dev@ thread 'String processing and Vector >> APIs'](https://mail.openjdk.org/archives/list/[email protected]/thread/YSPX3TBXZTZEFZNXWDYOZCWLUQPC62P6/), >> one motivating use-case is a regex library that wants to accelerate scans >> for character classes. Implementing these methods outside the JDK using >> scalar `charAt` loops is slower than a vectorized implementation. >> >> ### Goals >> >> * Performance - to get the full performance benefit, these APIs should avoid >> copies or re-encoding, since a copy or re-encoding would be O(n) and reduce >> the performance benefit of a vector loop >> * Encapsulation - encapsulation of `java.lang.String` internals must be >> preserved, including preventing modification of the String's backing >> storage, and also preserving encapsulation of String implementation details >> (like the exact encoding under Compact Strings) >> >> ### Design >> >> >> // ByteVector >> static boolean compatibleWith(String string, Charset charset) >> static ByteVector fromString(VectorSpecies<Byte> species, String string, >> Charset charset, int offset) >> static ByteVector fromString(VectorSpecies<Byte> species, String string, >> Charset charset, int offset, VectorMask<Byte> m) >> >> // ShortVector >> static boolean compatibleWith(String string, Charset charset) >> static ShortVector fromString(VectorSpecies<Short> species, String string, >> Charset charset, int offset) >> static ShortVector fromString(VectorSpecies<Short> species, String string, >> Charset charset, int offset, VectorMask<Short> m) >> >> >> `compatibleWith` runs in constant time. If it returns `true`, `fromString` >> loads the String's backing storage without a copy, if it returns false >> `fromString` will throw `IllegalArgumentException` and callers are expected >> to handle falling back to a scalar loop. >> >> >> if (ByteVector.compatibleWith(s, ISO_8859_1)) { >> // ... >> } else if (ShortVector.compatibleWith(s, UTF_16)) { >> // ... >> } else { >> // scalar fallback >> } >> >> >> These methods deal with strings in terms of code units, not encoded bytes. >> `ShortVector.fromString` loads the String's UTF-16 code units in native byte >> order without a BOM and any unpaired surrogates preserved, providing the >> same values as a scalar loop over `charAt`. Guaranteeing a well-formed >> encoding would... > > Liam Miller-Cushon has updated the pull request with a new target base due to > a merge or a rebase. The incremental webrev excludes the unrelated changes > brought in by the merge/rebase. The pull request contains 13 additional > commits since the last revision: > > - Clean up unused import > - Merge remote-tracking branch 'origin/master' into short-vector > - Move asReadOnlyMemorySegment to String > - Add a benchmark > > Also adjust javadoc, convert test to JUnit 5, other small adjustments > - javadoc > - Move access to jdk.internal.foreign.StringSupport > - Make test inputs longer > - Test coverage > - Move to X-Vector.java.template, update javadoc, add masked overloads > - ShortVector.compatibleWith > - ... and 3 more: https://git.openjdk.org/jdk/compare/35dfcfde...1c6ff6ab The proposed approach seems sensible, except that it still amounts at exposing some of the guts out. I understand what problem we're trying to solve -- e.g. mapping string to bytes just to load into a vector is more expensive than the vector op itself. But these `compatible` methods are really asking how the JDK is encoding the string. For instance, if somebody wanted to encode a string in some other 1-byte-per-char coder that is not 8859 (and there are some e.g. in Japanese), this method will say no. And not because the string cannot be encoded as one byte per char (it can!) but simply because the JDK happened to use a particular implementation which is biased towards 8859. Which makes it a bit odd to expose as a general API (although, in an incubating package, maybe it's ok) -- in the sense that it's much less general than it claims to be. The "right" API is to just give the string and the charset to the factory, so that the factory, internally, can decide how best to do things. That's what FFM does. But here the problem is that we don't want to fallback to "slow code" that encodes the string into a byte[] -- we prefer to just have it fail, and then use some other approach (e.g. non-simd). ------------- PR Comment: https://git.openjdk.org/jdk/pull/32373#issuecomment-6167975396
