Skip to content

Commit c9f668a

Browse files
committed
Refactor the SWAR logic into a separate subclass of StringEncoder.
1 parent a574eac commit c9f668a

File tree

4 files changed

+96
-75
lines changed

4 files changed

+96
-75
lines changed

Rakefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ if defined?(RUBY_ENGINE) and RUBY_ENGINE == 'jruby'
120120
"json/ext/OptionsReader*.class",
121121
"json/ext/Generator*.class",
122122
"json/ext/RuntimeInfo*.class",
123-
"json/ext/StringEncoder*.class",
123+
"json/ext/*StringEncoder*.class",
124124
"json/ext/Utils*.class"
125125
]
126126
sh 'jar', 'cf', File.basename(JRUBY_GENERATOR_JAR), *generator_classes

java/src/json/ext/Generator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ public StringEncoder getStringEncoder(ThreadContext context) {
234234
GeneratorState state = getState(context);
235235
stringEncoder = state.asciiOnly() ?
236236
new StringEncoderAsciiOnly(state.scriptSafe()) :
237-
new StringEncoder(state.scriptSafe());
237+
(state.scriptSafe()) ? new StringEncoder(state.scriptSafe()) : StringEncoder.createBasicEncoder();
238238
}
239239
return stringEncoder;
240240
}
Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
package json.ext;
2+
3+
import java.io.IOException;
4+
import java.nio.ByteBuffer;
5+
6+
import org.jruby.util.ByteList;
7+
8+
public class SWARBasicStringEncoder extends StringEncoder {
9+
10+
public SWARBasicStringEncoder() {
11+
super(ESCAPE_TABLE);
12+
}
13+
14+
@Override
15+
void encode(ByteList src) throws IOException {
16+
byte[] hexdig = HEX;
17+
byte[] scratch = aux;
18+
19+
byte[] ptrBytes = src.unsafeBytes();
20+
int ptr = src.begin();
21+
int len = src.realSize();
22+
23+
int beg = 0;
24+
int pos = 0;
25+
26+
ByteBuffer bb = ByteBuffer.wrap(ptrBytes, 0, len);
27+
while (pos + 8 <= len) {
28+
long x = bb.getLong(ptr + pos);
29+
if (skipChunk(x)) {
30+
pos += 8;
31+
continue;
32+
}
33+
for (int i = 0; i < 8; i++) {
34+
int ch = Byte.toUnsignedInt(ptrBytes[ptr + pos + i]);
35+
int ch_len = ESCAPE_TABLE[ch];
36+
if (ch_len > 0) {
37+
beg = pos = flushPos(pos + i, beg, ptrBytes, ptr, 1);
38+
escapeAscii(ch, scratch, hexdig);
39+
break;
40+
}
41+
}
42+
}
43+
44+
if (pos + 4 <= len) {
45+
int x = bb.getInt(ptr + pos);
46+
if (skipChunk(x)) {
47+
pos += 4;
48+
}
49+
}
50+
51+
while (pos < len) {
52+
int ch = Byte.toUnsignedInt(ptrBytes[ptr + pos]);
53+
int ch_len = ESCAPE_TABLE[ch];
54+
if (ch_len > 0) {
55+
beg = pos = flushPos(pos, beg, ptrBytes, ptr, 1);
56+
escapeAscii(ch, scratch, hexdig);
57+
} else {
58+
pos++;
59+
}
60+
}
61+
62+
if (beg < len) {
63+
append(ptrBytes, ptr + beg, len - beg);
64+
}
65+
}
66+
67+
private boolean skipChunk(long x) {
68+
long is_ascii = 0x8080808080808080L & ~x;
69+
long xor2 = x ^ 0x0202020202020202L;
70+
long lt32_or_eq34 = xor2 - 0x2121212121212121L;
71+
long sub92 = x ^ 0x5C5C5C5C5C5C5C5CL;
72+
long eq92 = (sub92 - 0x0101010101010101L);
73+
return ((lt32_or_eq34 | eq92) & is_ascii) == 0;
74+
}
75+
76+
private boolean skipChunk(int x) {
77+
int is_ascii = 0x80808080 & ~x;
78+
int xor2 = x ^ 0x02020202;
79+
int lt32_or_eq34 = xor2 - 0x21212121;
80+
int sub92 = x ^ 0x5C5C5C5C;
81+
int eq92 = (sub92 - 0x01010101);
82+
return ((lt32_or_eq34 | eq92) & is_ascii) == 0;
83+
}
84+
}

java/src/json/ext/StringEncoder.java

Lines changed: 10 additions & 73 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
import java.io.IOException;
99
import java.io.OutputStream;
10-
import java.nio.ByteBuffer;
1110
import java.nio.charset.StandardCharsets;
1211

1312
import org.jcodings.Encoding;
@@ -150,6 +149,14 @@ class StringEncoder extends ByteListTranscoder {
150149
this.escapeTable = escapeTable;
151150
}
152151

152+
static StringEncoder createBasicEncoder() {
153+
if (USE_BASIC_SWAR_ENCODER) {
154+
return new SWARBasicStringEncoder();
155+
} else {
156+
return new StringEncoder(false);
157+
}
158+
}
159+
153160
// C: generate_json_string
154161
void generate(ThreadContext context, RubyString object, OutputStream buffer) throws IOException {
155162
object = ensureValidEncoding(context, object);
@@ -210,73 +217,7 @@ private static RubyString tryWeirdEncodings(ThreadContext context, RubyString st
210217
return str;
211218
}
212219

213-
void encodeBasicSWAR(ByteList src) throws IOException {
214-
byte[] hexdig = HEX;
215-
byte[] scratch = aux;
216-
217-
byte[] ptrBytes = src.unsafeBytes();
218-
int ptr = src.begin();
219-
int len = src.realSize();
220-
221-
int beg = 0;
222-
int pos = 0;
223-
224-
ByteBuffer bb = ByteBuffer.wrap(ptrBytes, 0, len);
225-
while (pos + 8 <= len) {
226-
long x = bb.getLong(ptr + pos);
227-
long is_ascii = 0x8080808080808080L & ~x;
228-
long xor2 = x ^ 0x0202020202020202L;
229-
long lt32_or_eq34 = xor2 - 0x2121212121212121L;
230-
long sub92 = x ^ 0x5C5C5C5C5C5C5C5CL;
231-
long eq92 = (sub92 - 0x0101010101010101L);
232-
boolean needs_escape = ((lt32_or_eq34 | eq92) & is_ascii) != 0;
233-
if (needs_escape) {
234-
// Find the exact byte that needs escaping
235-
for (int i = 0; i < 8; i++) {
236-
int ch = Byte.toUnsignedInt(ptrBytes[ptr + pos + i]);
237-
int ch_len = ESCAPE_TABLE[ch];
238-
if (ch_len > 0) {
239-
beg = pos = flushPos(pos + i, beg, ptrBytes, ptr, 1);
240-
escapeAscii(ch, scratch, hexdig);
241-
break;
242-
}
243-
}
244-
continue;
245-
}
246-
247-
pos += 8;
248-
}
249-
250-
if (pos + 4 <= len) {
251-
int x = bb.getInt(ptr + pos);
252-
int is_ascii = 0x80808080 & ~x;
253-
int xor2 = x ^ 0x02020202;
254-
int lt32_or_eq34 = xor2 - 0x21212121;
255-
int sub92 = x ^ 0x5C5C5C5C;
256-
int eq92 = (sub92 - 0x01010101);
257-
boolean skip_chunk = ((lt32_or_eq34 | eq92) & is_ascii) == 0;
258-
if (skip_chunk) {
259-
pos += 4;
260-
}
261-
}
262-
263-
while (pos < len) {
264-
int ch = Byte.toUnsignedInt(ptrBytes[ptr + pos]);
265-
int ch_len = ESCAPE_TABLE[ch];
266-
if (ch_len > 0) {
267-
beg = pos = flushPos(pos, beg, ptrBytes, ptr, 1);
268-
escapeAscii(ch, scratch, hexdig);
269-
} else {
270-
pos++;
271-
}
272-
}
273-
274-
if (beg < len) {
275-
append(ptrBytes, ptr + beg, len - beg);
276-
}
277-
}
278-
279-
void encodeBasic(ByteList src) throws IOException{
220+
void encodeBasic(ByteList src) throws IOException {
280221
byte[] hexdig = HEX;
281222
byte[] scratch = aux;
282223

@@ -306,11 +247,7 @@ void encodeBasic(ByteList src) throws IOException{
306247
// C: convert_UTF8_to_JSON
307248
void encode(ByteList src) throws IOException {
308249
if (escapeTable == ESCAPE_TABLE) {
309-
if (USE_BASIC_SWAR_ENCODER) {
310-
encodeBasicSWAR(src);
311-
} else {
312-
encodeBasic(src);
313-
}
250+
encodeBasic(src);
314251
return;
315252
}
316253

0 commit comments

Comments
 (0)