Skip to content

Commit 55aee21

Browse files
committed
Updated the vectorized scanner to more closely match the C implmeentation.
1 parent 6d71a5b commit 55aee21

File tree

3 files changed

+70
-37
lines changed

3 files changed

+70
-37
lines changed

java/src/json/ext/EscapeScanner.java

Lines changed: 20 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,33 +15,42 @@ static class State {
1515
}
1616

1717
static class VectorSupport {
18-
static Constructor<?> vectorizedEscapeScannerConstructor = null;
18+
static final EscapeScanner VECTORIZED_ESCAPE_SCANNER;
1919

2020
static {
2121
Optional<Module> vectorModule = ModuleLayer.boot().findModule("jdk.incubator.vector");
22+
EscapeScanner scanner = null;
2223
if (vectorModule.isPresent()) {
2324
try {
2425
Class<?> vectorEscapeScannerClass = EscapeScanner.class.getClassLoader().loadClass("json.ext.VectorizedEscapeScanner");
25-
vectorizedEscapeScannerConstructor = vectorEscapeScannerClass.getDeclaredConstructor();
26-
} catch (ClassNotFoundException | NoSuchMethodException e) {
26+
Constructor<?> vectorizedEscapeScannerConstructor = vectorEscapeScannerClass.getDeclaredConstructor();
27+
scanner = (EscapeScanner) vectorizedEscapeScannerConstructor.newInstance();
28+
} catch (ClassNotFoundException | NoSuchMethodException | InstantiationException | IllegalAccessException | InvocationTargetException e) {
2729
// Fallback to the ScalarEscapeScanner if we cannot load the VectorizedEscapeScanner.
2830
System.err.println("Failed to load VectorizedEscapeScanner, falling back to ScalarEscapeScanner: " + e.getMessage());
31+
scanner = null;
2932
}
33+
3034
}
35+
VECTORIZED_ESCAPE_SCANNER = scanner;
3136
}
3237
}
3338

3439
boolean scan(EscapeScanner.State state) throws java.io.IOException;
3540

36-
public static EscapeScanner basicScanner() {
37-
if (VectorSupport.vectorizedEscapeScannerConstructor != null) {
38-
try {
39-
// Attempt to instantiate the vectorized escape scanner if available.
40-
return (EscapeScanner) VectorSupport.vectorizedEscapeScannerConstructor.newInstance();
41-
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {
42-
System.err.println("Failed to instantiate VectorizedEscapeScanner, falling back to ScalarEscapeScanner: " + e.getMessage());
43-
}
41+
default State createState(byte[] ptrBytes, int ptr, int len, int beg) {
42+
State state = new State();
43+
state.ptrBytes = ptrBytes;
44+
state.ptr = ptr;
45+
state.len = len;
46+
state.beg = beg;
47+
state.pos = 0; // Start scanning from the beginning of the segment
48+
return state;
49+
}
4450

51+
public static EscapeScanner basicScanner() {
52+
if (VectorSupport.VECTORIZED_ESCAPE_SCANNER != null) {
53+
return VectorSupport.VECTORIZED_ESCAPE_SCANNER;
4554
}
4655

4756
return new ScalarEscapeScanner(StringEncoder.ESCAPE_TABLE);

java/src/json/ext/StringEncoder.java

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -228,17 +228,18 @@ boolean searchEscape(EscapeScanner.State state) throws IOException {
228228
}
229229

230230
void encodeBasic(ByteList src) throws IOException {
231-
EscapeScanner.State state = new EscapeScanner.State();
232-
state.ptrBytes = src.unsafeBytes();
233-
state.ptr = src.begin();
234-
state.len = src.realSize();
235-
state.beg = 0;
236-
state.pos = 0;
231+
// EscapeScanner.State state = new EscapeScanner.State();
232+
// state.ptrBytes = src.unsafeBytes();
233+
// state.ptr = src.begin();
234+
// state.len = src.realSize();
235+
// state.beg = 0;
236+
// state.pos = 0;
237237

238238
byte[] hexdig = HEX;
239239
byte[] scratch = aux;
240240

241241
EscapeScanner scanner = EscapeScanner.basicScanner();
242+
EscapeScanner.State state = scanner.createState(src.unsafeBytes(), src.begin(), src.realSize(), 0);
242243

243244
while(scanner.scan(state)) {
244245
int ch = Byte.toUnsignedInt(state.ptrBytes[state.ptr + state.pos]);
Lines changed: 43 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,31 @@
11
package json.ext;
22

33
import java.io.IOException;
4+
import javax.naming.directory.NoSuchAttributeException;
45

56
import jdk.incubator.vector.ByteVector;
67
import jdk.incubator.vector.VectorMask;
78
import jdk.incubator.vector.VectorOperators;
89
import jdk.incubator.vector.VectorSpecies;
10+
import jdk.jfr.RecordingState;
911

1012
public class VectorizedEscapeScanner implements EscapeScanner {
1113
public static EscapeScanner.ScalarEscapeScanner FALLBACK = new EscapeScanner.ScalarEscapeScanner(StringEncoder.ESCAPE_TABLE);
1214

13-
// private VectorMask<Byte> needsEscape = null;
14-
// private int chunkStart = 0;
15-
1615
@Override
17-
public boolean scan(State state) throws IOException {
16+
public boolean scan(State _state) throws IOException {
1817
VectorSpecies<Byte> species = ByteVector.SPECIES_PREFERRED;
1918

20-
// if (needsEscape != null) {
21-
// if (needsEscape.anyTrue()) {
22-
// int firstEscapeIndex = needsEscape.firstTrue();
23-
// needsEscape = needsEscape.andNot(VectorMask.fromLong(species, 1L << firstEscapeIndex));
24-
// state.pos = chunkStart + firstEscapeIndex;
25-
// return true;
26-
// } else {
27-
// needsEscape = null;
28-
// }
29-
// }
19+
VectorizedState state = (VectorizedState) _state;
20+
21+
if (state.hasMatches) {
22+
if (state.mask > 0) {
23+
return nextMatch(state);
24+
} else {
25+
state.hasMatches = false;
26+
state.pos = state.chunkStart + species.length();
27+
}
28+
}
3029

3130
while ((state.ptr + state.pos) + species.length() < state.len) {
3231
ByteVector chunk = ByteVector.fromArray(species, state.ptrBytes, state.ptr + state.pos);
@@ -41,17 +40,41 @@ public boolean scan(State state) throws IOException {
4140

4241
VectorMask<Byte> needsEscape = chunk.eq(ByteVector.broadcast(species, '\\')).or(tooLowOrDblQuote).and(negative);
4342
if (needsEscape.anyTrue()) {
44-
// chunkStart = state.ptr + state.pos;
45-
int firstEscapeIndex = needsEscape.firstTrue();
46-
// Clear the bit at firstEscapeIndex to avoid scanning the same byte again
47-
// needsEscape = needsEscape.andNot(VectorMask.fromLong(species, 1L << firstEscapeIndex));
48-
state.pos += firstEscapeIndex;
49-
return true;
43+
state.hasMatches = true;
44+
state.chunkStart = state.ptr + state.pos;
45+
state.mask = needsEscape.toLong();
46+
47+
return nextMatch(state);
5048
}
5149

5250
state.pos += species.length();
5351
}
5452

5553
return FALLBACK.scan(state);
5654
}
55+
56+
private boolean nextMatch(VectorizedState state) {
57+
int index = Long.numberOfTrailingZeros(state.mask);
58+
state.mask &= (state.mask - 1);
59+
state.pos = state.chunkStart + index;
60+
return true;
61+
}
62+
63+
@Override
64+
public EscapeScanner.State createState(byte[] ptrBytes, int ptr, int len, int beg) {
65+
VectorizedState state = new VectorizedState();
66+
state.ptrBytes = ptrBytes;
67+
state.ptr = ptr;
68+
state.len = len;
69+
state.beg = beg;
70+
state.pos = 0;
71+
return state;
72+
}
73+
74+
private static class VectorizedState extends State {
75+
private long mask;
76+
private int chunkStart = 0;
77+
// private int lastMatchingIndex;
78+
private boolean hasMatches;
79+
}
5780
}

0 commit comments

Comments
 (0)