oj 3.16.6 → 3.17.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +81 -0
- data/README.md +0 -16
- data/ext/oj/compat.c +3 -3
- data/ext/oj/custom.c +17 -11
- data/ext/oj/dump.c +592 -81
- data/ext/oj/dump.h +9 -2
- data/ext/oj/dump_compat.c +15 -9
- data/ext/oj/dump_leaf.c +1 -1
- data/ext/oj/dump_object.c +32 -17
- data/ext/oj/dump_strict.c +20 -14
- data/ext/oj/extconf.rb +10 -7
- data/ext/oj/fast.c +40 -23
- data/ext/oj/intern.c +1 -1
- data/ext/oj/mimic_json.c +11 -7
- data/ext/oj/object.c +8 -8
- data/ext/oj/oj.c +256 -10
- data/ext/oj/oj.h +55 -52
- data/ext/oj/parse.c +243 -46
- data/ext/oj/parser.c +113 -37
- data/ext/oj/parser.h +2 -0
- data/ext/oj/rails.c +41 -36
- data/ext/oj/rxclass.c +1 -1
- data/ext/oj/rxclass.h +1 -1
- data/ext/oj/safe.c +230 -0
- data/ext/oj/safe.h +79 -0
- data/ext/oj/saj.c +13 -8
- data/ext/oj/scp.c +3 -6
- data/ext/oj/simd.h +219 -0
- data/ext/oj/sparse.c +6 -3
- data/ext/oj/stream_writer.c +3 -13
- data/ext/oj/strict.c +2 -4
- data/ext/oj/string_writer.c +5 -7
- data/ext/oj/usual.c +20 -7
- data/ext/oj/wab.c +5 -4
- data/lib/oj/version.rb +1 -1
- data/pages/Encoding.md +1 -1
- metadata +22 -114
- data/test/_test_active.rb +0 -75
- data/test/_test_active_mimic.rb +0 -95
- data/test/_test_mimic_rails.rb +0 -123
- data/test/activerecord/result_test.rb +0 -31
- data/test/activesupport6/abstract_unit.rb +0 -44
- data/test/activesupport6/decoding_test.rb +0 -133
- data/test/activesupport6/encoding_test.rb +0 -542
- data/test/activesupport6/encoding_test_cases.rb +0 -98
- data/test/activesupport6/test_common.rb +0 -17
- data/test/activesupport6/test_helper.rb +0 -163
- data/test/activesupport6/time_zone_test_helpers.rb +0 -39
- data/test/activesupport7/abstract_unit.rb +0 -52
- data/test/activesupport7/decoding_test.rb +0 -125
- data/test/activesupport7/encoding_test.rb +0 -536
- data/test/activesupport7/encoding_test_cases.rb +0 -104
- data/test/activesupport7/time_zone_test_helpers.rb +0 -47
- data/test/files.rb +0 -29
- data/test/foo.rb +0 -26
- data/test/helper.rb +0 -39
- data/test/isolated/shared.rb +0 -309
- data/test/isolated/test_mimic_after.rb +0 -13
- data/test/isolated/test_mimic_alone.rb +0 -12
- data/test/isolated/test_mimic_as_json.rb +0 -45
- data/test/isolated/test_mimic_before.rb +0 -13
- data/test/isolated/test_mimic_define.rb +0 -28
- data/test/isolated/test_mimic_rails_after.rb +0 -22
- data/test/isolated/test_mimic_rails_before.rb +0 -21
- data/test/isolated/test_mimic_redefine.rb +0 -15
- data/test/json_gem/json_addition_test.rb +0 -216
- data/test/json_gem/json_common_interface_test.rb +0 -155
- data/test/json_gem/json_encoding_test.rb +0 -107
- data/test/json_gem/json_ext_parser_test.rb +0 -21
- data/test/json_gem/json_fixtures_test.rb +0 -36
- data/test/json_gem/json_generator_test.rb +0 -413
- data/test/json_gem/json_generic_object_test.rb +0 -90
- data/test/json_gem/json_parser_test.rb +0 -477
- data/test/json_gem/json_string_matching_test.rb +0 -42
- data/test/json_gem/test_helper.rb +0 -30
- data/test/mem.rb +0 -34
- data/test/perf.rb +0 -102
- data/test/perf_compat.rb +0 -128
- data/test/perf_dump.rb +0 -50
- data/test/perf_fast.rb +0 -162
- data/test/perf_file.rb +0 -62
- data/test/perf_object.rb +0 -134
- data/test/perf_once.rb +0 -59
- data/test/perf_parser.rb +0 -183
- data/test/perf_saj.rb +0 -101
- data/test/perf_scp.rb +0 -140
- data/test/perf_simple.rb +0 -289
- data/test/perf_strict.rb +0 -137
- data/test/perf_wab.rb +0 -129
- data/test/prec.rb +0 -23
- data/test/sample/change.rb +0 -13
- data/test/sample/dir.rb +0 -18
- data/test/sample/doc.rb +0 -35
- data/test/sample/file.rb +0 -47
- data/test/sample/group.rb +0 -15
- data/test/sample/hasprops.rb +0 -15
- data/test/sample/layer.rb +0 -11
- data/test/sample/line.rb +0 -20
- data/test/sample/oval.rb +0 -10
- data/test/sample/rect.rb +0 -9
- data/test/sample/shape.rb +0 -34
- data/test/sample/text.rb +0 -19
- data/test/sample.rb +0 -54
- data/test/sample_json.rb +0 -37
- data/test/test_compat.rb +0 -567
- data/test/test_custom.rb +0 -555
- data/test/test_debian.rb +0 -50
- data/test/test_fast.rb +0 -526
- data/test/test_file.rb +0 -250
- data/test/test_gc.rb +0 -60
- data/test/test_generate.rb +0 -21
- data/test/test_hash.rb +0 -39
- data/test/test_integer_range.rb +0 -72
- data/test/test_null.rb +0 -376
- data/test/test_object.rb +0 -1030
- data/test/test_parser.rb +0 -11
- data/test/test_parser_debug.rb +0 -27
- data/test/test_parser_saj.rb +0 -337
- data/test/test_parser_usual.rb +0 -251
- data/test/test_rails.rb +0 -35
- data/test/test_saj.rb +0 -188
- data/test/test_scp.rb +0 -431
- data/test/test_strict.rb +0 -441
- data/test/test_various.rb +0 -801
- data/test/test_wab.rb +0 -311
- data/test/test_writer.rb +0 -380
- data/test/tests.rb +0 -33
- data/test/tests_mimic.rb +0 -23
- data/test/tests_mimic_addition.rb +0 -16
data/ext/oj/dump.c
CHANGED
|
@@ -40,7 +40,7 @@ static size_t ascii_friendly_size(const uint8_t *str, size_t len);
|
|
|
40
40
|
static const char hex_chars[17] = "0123456789abcdef";
|
|
41
41
|
|
|
42
42
|
// JSON standard except newlines are no escaped
|
|
43
|
-
static char newline_friendly_chars[
|
|
43
|
+
static char newline_friendly_chars[257] = "\
|
|
44
44
|
66666666221622666666666666666666\
|
|
45
45
|
11211111111111111111111111111111\
|
|
46
46
|
11111111111111111111111111112111\
|
|
@@ -51,7 +51,7 @@ static char newline_friendly_chars[256] = "\
|
|
|
51
51
|
11111111111111111111111111111111";
|
|
52
52
|
|
|
53
53
|
// JSON standard
|
|
54
|
-
static char hibit_friendly_chars[
|
|
54
|
+
static char hibit_friendly_chars[257] = "\
|
|
55
55
|
66666666222622666666666666666666\
|
|
56
56
|
11211111111111111111111111111111\
|
|
57
57
|
11111111111111111111111111112111\
|
|
@@ -62,7 +62,7 @@ static char hibit_friendly_chars[256] = "\
|
|
|
62
62
|
11111111111111111111111111111111";
|
|
63
63
|
|
|
64
64
|
// JSON standard but escape forward slashes `/`
|
|
65
|
-
static char slash_friendly_chars[
|
|
65
|
+
static char slash_friendly_chars[257] = "\
|
|
66
66
|
66666666222622666666666666666666\
|
|
67
67
|
11211111111111121111111111111111\
|
|
68
68
|
11111111111111111111111111112111\
|
|
@@ -74,7 +74,7 @@ static char slash_friendly_chars[256] = "\
|
|
|
74
74
|
|
|
75
75
|
// High bit set characters are always encoded as unicode. Worse case is 3
|
|
76
76
|
// bytes per character in the output. That makes this conservative.
|
|
77
|
-
static char ascii_friendly_chars[
|
|
77
|
+
static char ascii_friendly_chars[257] = "\
|
|
78
78
|
66666666222622666666666666666666\
|
|
79
79
|
11211111111111111111111111111111\
|
|
80
80
|
11111111111111111111111111112111\
|
|
@@ -85,7 +85,7 @@ static char ascii_friendly_chars[256] = "\
|
|
|
85
85
|
33333333333333333333333333333333";
|
|
86
86
|
|
|
87
87
|
// XSS safe mode
|
|
88
|
-
static char xss_friendly_chars[
|
|
88
|
+
static char xss_friendly_chars[257] = "\
|
|
89
89
|
66666666222622666666666666666666\
|
|
90
90
|
11211161111111121111111111116161\
|
|
91
91
|
11111111111111111111111111112111\
|
|
@@ -96,7 +96,7 @@ static char xss_friendly_chars[256] = "\
|
|
|
96
96
|
33333333333333333333333333333333";
|
|
97
97
|
|
|
98
98
|
// JSON XSS combo
|
|
99
|
-
static char hixss_friendly_chars[
|
|
99
|
+
static char hixss_friendly_chars[257] = "\
|
|
100
100
|
66666666222622666666666666666666\
|
|
101
101
|
11211111111111111111111111111111\
|
|
102
102
|
11111111111111111111111111112111\
|
|
@@ -107,7 +107,7 @@ static char hixss_friendly_chars[256] = "\
|
|
|
107
107
|
11611111111111111111111111111111";
|
|
108
108
|
|
|
109
109
|
// Rails XSS combo
|
|
110
|
-
static char rails_xss_friendly_chars[
|
|
110
|
+
static char rails_xss_friendly_chars[257] = "\
|
|
111
111
|
66666666222622666666666666666666\
|
|
112
112
|
11211161111111111111111111116161\
|
|
113
113
|
11111111111111111111111111112111\
|
|
@@ -118,7 +118,7 @@ static char rails_xss_friendly_chars[256] = "\
|
|
|
118
118
|
11611111111111111111111111111111";
|
|
119
119
|
|
|
120
120
|
// Rails HTML non-escape
|
|
121
|
-
static char rails_friendly_chars[
|
|
121
|
+
static char rails_friendly_chars[257] = "\
|
|
122
122
|
66666666222622666666666666666666\
|
|
123
123
|
11211111111111111111111111111111\
|
|
124
124
|
11111111111111111111111111112111\
|
|
@@ -152,8 +152,146 @@ inline static size_t newline_friendly_size(const uint8_t *str, size_t len) {
|
|
|
152
152
|
return calculate_string_size(str, len, newline_friendly_chars);
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
#ifdef HAVE_SIMD_NEON
|
|
156
|
+
inline static uint8x16x4_t load_uint8x16_4(const unsigned char *table) {
|
|
157
|
+
uint8x16x4_t tab;
|
|
158
|
+
tab.val[0] = vld1q_u8(table);
|
|
159
|
+
tab.val[1] = vld1q_u8(table + 16);
|
|
160
|
+
tab.val[2] = vld1q_u8(table + 32);
|
|
161
|
+
tab.val[3] = vld1q_u8(table + 48);
|
|
162
|
+
return tab;
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
static uint8x16x4_t hibit_friendly_chars_neon[2];
|
|
166
|
+
static uint8x16x4_t rails_friendly_chars_neon[2];
|
|
167
|
+
static uint8x16x4_t rails_xss_friendly_chars_neon[4];
|
|
168
|
+
|
|
169
|
+
void initialize_neon(void) {
|
|
170
|
+
// We only need the first 128 bytes of the hibit friendly chars table. Everything above 127 is
|
|
171
|
+
// set to 1. If that ever changes, the code will need to be updated.
|
|
172
|
+
hibit_friendly_chars_neon[0] = load_uint8x16_4((const unsigned char *)hibit_friendly_chars);
|
|
173
|
+
hibit_friendly_chars_neon[1] = load_uint8x16_4((const unsigned char *)hibit_friendly_chars + 64);
|
|
174
|
+
|
|
175
|
+
// rails_friendly_chars is the same as hibit_friendly_chars. Only the first 128 bytes have values
|
|
176
|
+
// that are not '1'. If that ever changes, the code will need to be updated.
|
|
177
|
+
rails_friendly_chars_neon[0] = load_uint8x16_4((const unsigned char *)rails_friendly_chars);
|
|
178
|
+
rails_friendly_chars_neon[1] = load_uint8x16_4((const unsigned char *)rails_friendly_chars + 64);
|
|
179
|
+
|
|
180
|
+
rails_xss_friendly_chars_neon[0] = load_uint8x16_4((const unsigned char *)rails_xss_friendly_chars);
|
|
181
|
+
rails_xss_friendly_chars_neon[1] = load_uint8x16_4((const unsigned char *)rails_xss_friendly_chars + 64);
|
|
182
|
+
rails_xss_friendly_chars_neon[2] = load_uint8x16_4((const unsigned char *)rails_xss_friendly_chars + 128);
|
|
183
|
+
rails_xss_friendly_chars_neon[3] = load_uint8x16_4((const unsigned char *)rails_xss_friendly_chars + 192);
|
|
184
|
+
|
|
185
|
+
// All bytes should be 0 except for those that need more than 1 byte of output. This will allow the
|
|
186
|
+
// code to limit the lookups to the first 128 bytes (values 0 - 127). Bytes above 127 will result
|
|
187
|
+
// in 0 with the vqtbl4q_u8 instruction.
|
|
188
|
+
uint8x16_t one = vdupq_n_u8('1');
|
|
189
|
+
for (int i = 0; i < 2; i++) {
|
|
190
|
+
for (int j = 0; j < 4; j++) {
|
|
191
|
+
hibit_friendly_chars_neon[i].val[j] = vsubq_u8(hibit_friendly_chars_neon[i].val[j], one);
|
|
192
|
+
rails_friendly_chars_neon[i].val[j] = vsubq_u8(rails_friendly_chars_neon[i].val[j], one);
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
for (int i = 0; i < 4; i++) {
|
|
197
|
+
for (int j = 0; j < 4; j++) {
|
|
198
|
+
rails_xss_friendly_chars_neon[i].val[j] = vsubq_u8(rails_xss_friendly_chars_neon[i].val[j], one);
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
#endif
|
|
203
|
+
|
|
204
|
+
#ifdef HAVE_SIMD_SSE4_2
|
|
205
|
+
|
|
206
|
+
static __m128i hibit_friendly_chars_sse42[8];
|
|
207
|
+
|
|
208
|
+
// From: https://stackoverflow.com/questions/36998538/fastest-way-to-horizontally-sum-sse-unsigned-byte-vector
|
|
209
|
+
inline static OJ_TARGET_SSE42 uint32_t _mm_sum_epu8(const __m128i v) {
|
|
210
|
+
__m128i vsum = _mm_sad_epu8(v, _mm_setzero_si128());
|
|
211
|
+
return _mm_cvtsi128_si32(vsum) + _mm_extract_epi16(vsum, 4);
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
inline static OJ_TARGET_SSE42 size_t hibit_friendly_size_sse42(const uint8_t *str, size_t len) {
|
|
215
|
+
size_t size = 0;
|
|
216
|
+
size_t i = 0;
|
|
217
|
+
|
|
218
|
+
for (; i + sizeof(__m128i) <= len; i += sizeof(__m128i), str += sizeof(__m128i)) {
|
|
219
|
+
size += sizeof(__m128i);
|
|
220
|
+
|
|
221
|
+
__m128i chunk = _mm_loadu_si128((__m128i *)str);
|
|
222
|
+
__m128i tmp = vector_lookup_sse42(chunk, hibit_friendly_chars_sse42, 8);
|
|
223
|
+
size += _mm_sum_epu8(tmp);
|
|
224
|
+
}
|
|
225
|
+
size_t total = size + calculate_string_size(str, len - i, hibit_friendly_chars);
|
|
226
|
+
return total;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
void OJ_TARGET_SSE42 initialize_sse42(void) {
|
|
230
|
+
for (int i = 0; i < 8; i++) {
|
|
231
|
+
hibit_friendly_chars_sse42[i] = _mm_sub_epi8(
|
|
232
|
+
_mm_loadu_si128((__m128i *)(hibit_friendly_chars + i * sizeof(__m128i))),
|
|
233
|
+
_mm_set1_epi8('1'));
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
#else
|
|
238
|
+
|
|
239
|
+
#define SIMD_TARGET
|
|
240
|
+
|
|
241
|
+
#endif /* HAVE_SIMD_SSE4_2 */
|
|
242
|
+
|
|
155
243
|
inline static size_t hibit_friendly_size(const uint8_t *str, size_t len) {
|
|
244
|
+
#ifdef HAVE_SIMD_NEON
|
|
245
|
+
size_t size = 0;
|
|
246
|
+
size_t i = 0;
|
|
247
|
+
|
|
248
|
+
for (; i + sizeof(uint8x16_t) <= len; i += sizeof(uint8x16_t), str += sizeof(uint8x16_t)) {
|
|
249
|
+
size += sizeof(uint8x16_t);
|
|
250
|
+
|
|
251
|
+
// See https://lemire.me/blog/2019/07/23/arbitrary-byte-to-byte-maps-using-arm-neon/
|
|
252
|
+
uint8x16_t chunk = vld1q_u8(str);
|
|
253
|
+
uint8x16_t tmp1 = vqtbl4q_u8(hibit_friendly_chars_neon[0], chunk);
|
|
254
|
+
uint8x16_t tmp2 = vqtbl4q_u8(hibit_friendly_chars_neon[1], veorq_u8(chunk, vdupq_n_u8(0x40)));
|
|
255
|
+
uint8x16_t result = vorrq_u8(tmp1, tmp2);
|
|
256
|
+
uint8_t tmp = vaddvq_u8(result);
|
|
257
|
+
size += tmp;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
#ifdef HAVE_FAST_MEMCPY
|
|
261
|
+
size_t total = 0;
|
|
262
|
+
if (len - i > 4) {
|
|
263
|
+
size += (len - i);
|
|
264
|
+
unsigned char buf[sizeof(uint8x16_t)];
|
|
265
|
+
memset(buf, ' ', sizeof(buf));
|
|
266
|
+
fast_memcpy16(buf, str, len - i);
|
|
267
|
+
|
|
268
|
+
uint8x16_t chunk = vld1q_u8((const unsigned char *)buf);
|
|
269
|
+
uint8x16_t tmp1 = vqtbl4q_u8(hibit_friendly_chars_neon[0], chunk);
|
|
270
|
+
uint8x16_t tmp2 = vqtbl4q_u8(hibit_friendly_chars_neon[1], veorq_u8(chunk, vdupq_n_u8(0x40)));
|
|
271
|
+
uint8x16_t result = vorrq_u8(tmp1, tmp2);
|
|
272
|
+
uint8_t tmp = vaddvq_u8(result);
|
|
273
|
+
|
|
274
|
+
size += tmp;
|
|
275
|
+
|
|
276
|
+
total = size;
|
|
277
|
+
} else {
|
|
278
|
+
total = size + calculate_string_size(str, len - i, hibit_friendly_chars);
|
|
279
|
+
}
|
|
280
|
+
#else
|
|
281
|
+
size_t total = size + calculate_string_size(str, len - i, hibit_friendly_chars);
|
|
282
|
+
#endif
|
|
283
|
+
|
|
284
|
+
return total;
|
|
285
|
+
#elif defined(HAVE_SIMD_SSE4_2)
|
|
286
|
+
if (SIMD_Impl == SIMD_SSE42) {
|
|
287
|
+
if (len >= sizeof(__m128i)) {
|
|
288
|
+
return hibit_friendly_size_sse42(str, len);
|
|
289
|
+
}
|
|
290
|
+
}
|
|
156
291
|
return calculate_string_size(str, len, hibit_friendly_chars);
|
|
292
|
+
#else
|
|
293
|
+
return calculate_string_size(str, len, hibit_friendly_chars);
|
|
294
|
+
#endif
|
|
157
295
|
}
|
|
158
296
|
|
|
159
297
|
inline static size_t slash_friendly_size(const uint8_t *str, size_t len) {
|
|
@@ -183,10 +321,52 @@ inline static size_t hixss_friendly_size(const uint8_t *str, size_t len) {
|
|
|
183
321
|
}
|
|
184
322
|
|
|
185
323
|
inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
186
|
-
long
|
|
187
|
-
|
|
188
|
-
|
|
324
|
+
long size = 0;
|
|
325
|
+
uint32_t hi = 0;
|
|
326
|
+
|
|
327
|
+
#ifdef HAVE_SIMD_NEON
|
|
328
|
+
size_t i = 0;
|
|
329
|
+
|
|
330
|
+
if (len >= sizeof(uint8x16_t)) {
|
|
331
|
+
uint8x16_t has_some_hibit = vdupq_n_u8(0);
|
|
332
|
+
uint8x16_t hibit = vdupq_n_u8(0x80);
|
|
333
|
+
|
|
334
|
+
for (; i + sizeof(uint8x16_t) <= len; i += sizeof(uint8x16_t), str += sizeof(uint8x16_t)) {
|
|
335
|
+
size += sizeof(uint8x16_t);
|
|
189
336
|
|
|
337
|
+
uint8x16_t chunk = vld1q_u8(str);
|
|
338
|
+
|
|
339
|
+
// Check to see if any of these bytes have the high bit set.
|
|
340
|
+
has_some_hibit = vorrq_u8(has_some_hibit, vandq_u8(chunk, hibit));
|
|
341
|
+
|
|
342
|
+
uint8x16_t tmp1 = vqtbl4q_u8(rails_xss_friendly_chars_neon[0], chunk);
|
|
343
|
+
uint8x16_t tmp2 = vqtbl4q_u8(rails_xss_friendly_chars_neon[1], veorq_u8(chunk, vdupq_n_u8(0x40)));
|
|
344
|
+
uint8x16_t tmp3 = vqtbl4q_u8(rails_xss_friendly_chars_neon[2], veorq_u8(chunk, vdupq_n_u8(0x80)));
|
|
345
|
+
uint8x16_t tmp4 = vqtbl4q_u8(rails_xss_friendly_chars_neon[3], veorq_u8(chunk, vdupq_n_u8(0xc0)));
|
|
346
|
+
uint8x16_t result = vorrq_u8(tmp4, vorrq_u8(tmp3, vorrq_u8(tmp1, tmp2)));
|
|
347
|
+
uint8_t tmp = vaddvq_u8(result);
|
|
348
|
+
size += tmp;
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
// 'hi' should be set if any of the bytes we processed have the high bit set. It doesn't matter which ones.
|
|
352
|
+
hi = vmaxvq_u8(has_some_hibit) != 0;
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
size_t len_remaining = len - i;
|
|
356
|
+
|
|
357
|
+
for (; i < len; str++, i++) {
|
|
358
|
+
size += rails_xss_friendly_chars[*str];
|
|
359
|
+
hi |= *str & 0x80;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
size -= (len_remaining * ((size_t)'0'));
|
|
363
|
+
|
|
364
|
+
if (0 == hi) {
|
|
365
|
+
return size;
|
|
366
|
+
}
|
|
367
|
+
return -(size);
|
|
368
|
+
#else
|
|
369
|
+
size_t i = len;
|
|
190
370
|
for (; 0 < i; str++, i--) {
|
|
191
371
|
size += rails_xss_friendly_chars[*str];
|
|
192
372
|
hi |= *str & 0x80;
|
|
@@ -195,13 +375,53 @@ inline static long rails_xss_friendly_size(const uint8_t *str, size_t len) {
|
|
|
195
375
|
return size - len * (size_t)'0';
|
|
196
376
|
}
|
|
197
377
|
return -(size - len * (size_t)'0');
|
|
378
|
+
#endif /* HAVE_SIMD_NEON */
|
|
198
379
|
}
|
|
199
380
|
|
|
200
381
|
inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
|
201
|
-
long
|
|
202
|
-
|
|
203
|
-
|
|
382
|
+
long size = 0;
|
|
383
|
+
uint32_t hi = 0;
|
|
384
|
+
#ifdef HAVE_SIMD_NEON
|
|
385
|
+
size_t i = 0;
|
|
386
|
+
long extra = 0;
|
|
387
|
+
|
|
388
|
+
if (len >= sizeof(uint8x16_t)) {
|
|
389
|
+
uint8x16_t has_some_hibit = vdupq_n_u8(0);
|
|
390
|
+
uint8x16_t hibit = vdupq_n_u8(0x80);
|
|
391
|
+
|
|
392
|
+
for (; i + sizeof(uint8x16_t) <= len; i += sizeof(uint8x16_t), str += sizeof(uint8x16_t)) {
|
|
393
|
+
size += sizeof(uint8x16_t);
|
|
394
|
+
|
|
395
|
+
// See https://lemire.me/blog/2019/07/23/arbitrary-byte-to-byte-maps-using-arm-neon/
|
|
396
|
+
uint8x16_t chunk = vld1q_u8(str);
|
|
397
|
+
|
|
398
|
+
// Check to see if any of these bytes have the high bit set.
|
|
399
|
+
has_some_hibit = vorrq_u8(has_some_hibit, vandq_u8(chunk, hibit));
|
|
400
|
+
|
|
401
|
+
uint8x16_t tmp1 = vqtbl4q_u8(rails_friendly_chars_neon[0], chunk);
|
|
402
|
+
uint8x16_t tmp2 = vqtbl4q_u8(rails_friendly_chars_neon[1], veorq_u8(chunk, vdupq_n_u8(0x40)));
|
|
403
|
+
uint8x16_t result = vorrq_u8(tmp1, tmp2);
|
|
404
|
+
uint8_t tmp = vaddvq_u8(result);
|
|
405
|
+
size += tmp;
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
// 'hi' should be set if any of the bytes we processed have the high bit set. It doesn't matter which ones.
|
|
409
|
+
hi = vmaxvq_u8(has_some_hibit) != 0;
|
|
410
|
+
}
|
|
204
411
|
|
|
412
|
+
for (; i < len; str++, i++, extra++) {
|
|
413
|
+
size += rails_friendly_chars[*str];
|
|
414
|
+
hi |= *str & 0x80;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
size -= (extra * ((size_t)'0'));
|
|
418
|
+
|
|
419
|
+
if (0 == hi) {
|
|
420
|
+
return size;
|
|
421
|
+
}
|
|
422
|
+
return -(size);
|
|
423
|
+
#else
|
|
424
|
+
size_t i = len;
|
|
205
425
|
for (; 0 < i; str++, i--) {
|
|
206
426
|
size += rails_friendly_chars[*str];
|
|
207
427
|
hi |= *str & 0x80;
|
|
@@ -210,9 +430,10 @@ inline static size_t rails_friendly_size(const uint8_t *str, size_t len) {
|
|
|
210
430
|
return size - len * (size_t)'0';
|
|
211
431
|
}
|
|
212
432
|
return -(size - len * (size_t)'0');
|
|
433
|
+
#endif /* HAVE_SIMD_NEON */
|
|
213
434
|
}
|
|
214
435
|
|
|
215
|
-
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus,
|
|
436
|
+
const char *oj_nan_str(VALUE obj, int opt, int mode, bool plus, size_t *lenp) {
|
|
216
437
|
const char *str = NULL;
|
|
217
438
|
|
|
218
439
|
if (AutoNan == opt) {
|
|
@@ -477,7 +698,7 @@ void oj_dump_time(VALUE obj, Out out, int withZone) {
|
|
|
477
698
|
void oj_dump_ruby_time(VALUE obj, Out out) {
|
|
478
699
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
479
700
|
|
|
480
|
-
oj_dump_cstr(RSTRING_PTR(rstr),
|
|
701
|
+
oj_dump_cstr(RSTRING_PTR(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
481
702
|
}
|
|
482
703
|
|
|
483
704
|
void oj_dump_xml_time(VALUE obj, Out out) {
|
|
@@ -711,13 +932,13 @@ void oj_dump_str(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
711
932
|
rb_encoding *enc = rb_enc_from_index(idx);
|
|
712
933
|
obj = rb_str_conv_enc(obj, enc, oj_utf8_encoding);
|
|
713
934
|
}
|
|
714
|
-
oj_dump_cstr(RSTRING_PTR(obj),
|
|
935
|
+
oj_dump_cstr(RSTRING_PTR(obj), RSTRING_LEN(obj), 0, 0, out);
|
|
715
936
|
}
|
|
716
937
|
|
|
717
938
|
void oj_dump_sym(VALUE obj, int depth, Out out, bool as_ok) {
|
|
718
939
|
volatile VALUE s = rb_sym2str(obj);
|
|
719
940
|
|
|
720
|
-
oj_dump_cstr(RSTRING_PTR(s),
|
|
941
|
+
oj_dump_cstr(RSTRING_PTR(s), RSTRING_LEN(s), 0, 0, out);
|
|
721
942
|
}
|
|
722
943
|
|
|
723
944
|
static void debug_raise(const char *orig, size_t cnt, int line) {
|
|
@@ -758,9 +979,155 @@ void oj_dump_raw_json(VALUE obj, int depth, Out out) {
|
|
|
758
979
|
}
|
|
759
980
|
}
|
|
760
981
|
|
|
982
|
+
#if defined(__clang__) || defined(__GNUC__)
|
|
983
|
+
#define FORCE_INLINE __attribute__((always_inline))
|
|
984
|
+
#else
|
|
985
|
+
#define FORCE_INLINE
|
|
986
|
+
#endif
|
|
987
|
+
|
|
988
|
+
#ifdef HAVE_SIMD_NEON
|
|
989
|
+
typedef struct _neon_match_result {
|
|
990
|
+
uint8x16_t needs_escape;
|
|
991
|
+
bool has_some_hibit;
|
|
992
|
+
bool do_unicode_validation;
|
|
993
|
+
uint64_t escape_mask;
|
|
994
|
+
} neon_match_result;
|
|
995
|
+
|
|
996
|
+
static inline FORCE_INLINE neon_match_result
|
|
997
|
+
neon_update(const char *str, uint8x16x4_t *cmap_neon, int neon_table_size, bool do_unicode_validation, bool has_hi) {
|
|
998
|
+
neon_match_result result = {.has_some_hibit = false, .do_unicode_validation = false, .escape_mask = 0};
|
|
999
|
+
|
|
1000
|
+
uint8x16_t chunk = vld1q_u8((const unsigned char *)str);
|
|
1001
|
+
uint8x16_t tmp1 = vqtbl4q_u8(cmap_neon[0], chunk);
|
|
1002
|
+
uint8x16_t tmp2 = vqtbl4q_u8(cmap_neon[1], veorq_u8(chunk, vdupq_n_u8(0x40)));
|
|
1003
|
+
result.needs_escape = vorrq_u8(tmp1, tmp2);
|
|
1004
|
+
if (neon_table_size > 2) {
|
|
1005
|
+
uint8x16_t tmp3 = vqtbl4q_u8(cmap_neon[2], veorq_u8(chunk, vdupq_n_u8(0x80)));
|
|
1006
|
+
uint8x16_t tmp4 = vqtbl4q_u8(cmap_neon[3], veorq_u8(chunk, vdupq_n_u8(0xc0)));
|
|
1007
|
+
result.needs_escape = vorrq_u8(result.needs_escape, vorrq_u8(tmp4, tmp3));
|
|
1008
|
+
}
|
|
1009
|
+
if (has_hi && do_unicode_validation) {
|
|
1010
|
+
uint8x16_t has_some_hibit = vandq_u8(chunk, vdupq_n_u8(0x80));
|
|
1011
|
+
result.has_some_hibit = vmaxvq_u8(has_some_hibit) != 0;
|
|
1012
|
+
result.do_unicode_validation = has_hi && do_unicode_validation && result.has_some_hibit;
|
|
1013
|
+
}
|
|
1014
|
+
const uint8x8_t res = vshrn_n_u16(vreinterpretq_u16_u8(vmvnq_u8(vceqq_u8(result.needs_escape, vdupq_n_u8(0)))), 4);
|
|
1015
|
+
const uint64_t mask = vget_lane_u64(vreinterpret_u64_u8(res), 0);
|
|
1016
|
+
result.escape_mask = mask & 0x8888888888888888ull;
|
|
1017
|
+
return result;
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
#elif defined(HAVE_SIMD_SSE4_2)
|
|
1021
|
+
typedef struct _sse42_match_result {
|
|
1022
|
+
__m128i actions;
|
|
1023
|
+
bool needs_escape;
|
|
1024
|
+
int escape_mask;
|
|
1025
|
+
bool has_some_hibit;
|
|
1026
|
+
bool do_unicode_validation;
|
|
1027
|
+
} sse42_match_result;
|
|
1028
|
+
|
|
1029
|
+
static inline OJ_TARGET_SSE42 sse42_match_result
|
|
1030
|
+
sse42_update(const char *str, __m128i *cmap_sse42, int sse42_tab_size, bool do_unicode_validation, bool has_hi) {
|
|
1031
|
+
sse42_match_result result = {.has_some_hibit = false, .do_unicode_validation = false};
|
|
1032
|
+
|
|
1033
|
+
__m128i chunk = _mm_loadu_si128((__m128i *)str);
|
|
1034
|
+
__m128i actions = vector_lookup_sse42(chunk, cmap_sse42, sse42_tab_size);
|
|
1035
|
+
__m128i needs_escape = _mm_xor_si128(_mm_cmpeq_epi8(actions, _mm_setzero_si128()), _mm_set1_epi8(0xFF));
|
|
1036
|
+
result.actions = _mm_add_epi8(actions, _mm_set1_epi8('1'));
|
|
1037
|
+
|
|
1038
|
+
result.escape_mask = _mm_movemask_epi8(needs_escape);
|
|
1039
|
+
result.needs_escape = result.escape_mask != 0;
|
|
1040
|
+
if (has_hi && do_unicode_validation) {
|
|
1041
|
+
__m128i has_some_hibit = _mm_and_si128(chunk, _mm_set1_epi8(0x80));
|
|
1042
|
+
result.has_some_hibit = _mm_movemask_epi8(has_some_hibit) != 0;
|
|
1043
|
+
result.do_unicode_validation = has_hi && do_unicode_validation && result.has_some_hibit;
|
|
1044
|
+
}
|
|
1045
|
+
return result;
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
#endif /* HAVE_SIMD_NEON */
|
|
1049
|
+
|
|
1050
|
+
static inline FORCE_INLINE const char *process_character(char action,
|
|
1051
|
+
const char *str,
|
|
1052
|
+
const char *end,
|
|
1053
|
+
Out out,
|
|
1054
|
+
const char *orig,
|
|
1055
|
+
bool do_unicode_validation,
|
|
1056
|
+
const char **check_start_) {
|
|
1057
|
+
const char *check_start = *check_start_;
|
|
1058
|
+
switch (action) {
|
|
1059
|
+
case '1':
|
|
1060
|
+
if (do_unicode_validation && check_start <= str) {
|
|
1061
|
+
if (0 != (0x80 & (uint8_t)*str)) {
|
|
1062
|
+
if (0xC0 == (0xC0 & (uint8_t)*str)) {
|
|
1063
|
+
*check_start_ = check_unicode(str, end, orig);
|
|
1064
|
+
} else {
|
|
1065
|
+
raise_invalid_unicode(orig, (int)(end - orig), (int)(str - orig));
|
|
1066
|
+
}
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
*out->cur++ = *str;
|
|
1070
|
+
break;
|
|
1071
|
+
case '2':
|
|
1072
|
+
*out->cur++ = '\\';
|
|
1073
|
+
switch (*str) {
|
|
1074
|
+
case '\\': *out->cur++ = '\\'; break;
|
|
1075
|
+
case '\b': *out->cur++ = 'b'; break;
|
|
1076
|
+
case '\t': *out->cur++ = 't'; break;
|
|
1077
|
+
case '\n': *out->cur++ = 'n'; break;
|
|
1078
|
+
case '\f': *out->cur++ = 'f'; break;
|
|
1079
|
+
case '\r': *out->cur++ = 'r'; break;
|
|
1080
|
+
default: *out->cur++ = *str; break;
|
|
1081
|
+
}
|
|
1082
|
+
break;
|
|
1083
|
+
case '3': // Unicode
|
|
1084
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
|
1085
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
|
1086
|
+
str = dump_unicode(str, end, out, orig);
|
|
1087
|
+
} else {
|
|
1088
|
+
*check_start_ = check_unicode(str, end, orig);
|
|
1089
|
+
*out->cur++ = *str;
|
|
1090
|
+
}
|
|
1091
|
+
break;
|
|
1092
|
+
}
|
|
1093
|
+
str = dump_unicode(str, end, out, orig);
|
|
1094
|
+
break;
|
|
1095
|
+
case '6': // control characters
|
|
1096
|
+
if (*(uint8_t *)str < 0x80) {
|
|
1097
|
+
if (0 == (uint8_t)*str && out->opts->dump_opts.omit_null_byte) {
|
|
1098
|
+
break;
|
|
1099
|
+
}
|
|
1100
|
+
APPEND_CHARS(out->cur, "\\u00", 4);
|
|
1101
|
+
dump_hex((uint8_t)*str, out);
|
|
1102
|
+
} else {
|
|
1103
|
+
if (0xe2 == (uint8_t)*str && do_unicode_validation && 2 <= end - str) {
|
|
1104
|
+
if (0x80 == (uint8_t)str[1] && (0xa8 == (uint8_t)str[2] || 0xa9 == (uint8_t)str[2])) {
|
|
1105
|
+
str = dump_unicode(str, end, out, orig);
|
|
1106
|
+
} else {
|
|
1107
|
+
*check_start_ = check_unicode(str, end, orig);
|
|
1108
|
+
*out->cur++ = *str;
|
|
1109
|
+
}
|
|
1110
|
+
break;
|
|
1111
|
+
}
|
|
1112
|
+
str = dump_unicode(str, end, out, orig);
|
|
1113
|
+
}
|
|
1114
|
+
break;
|
|
1115
|
+
default: break; // ignore, should never happen if the table is correct
|
|
1116
|
+
}
|
|
1117
|
+
|
|
1118
|
+
return str;
|
|
1119
|
+
}
|
|
1120
|
+
|
|
761
1121
|
void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out out) {
|
|
762
|
-
size_t
|
|
763
|
-
char
|
|
1122
|
+
size_t size;
|
|
1123
|
+
char *cmap;
|
|
1124
|
+
#ifdef HAVE_SIMD_NEON
|
|
1125
|
+
uint8x16x4_t *cmap_neon = NULL;
|
|
1126
|
+
int neon_table_size = 0;
|
|
1127
|
+
#elif defined(HAVE_SIMD_SSE4_2)
|
|
1128
|
+
__m128i *cmap_sse42 = NULL;
|
|
1129
|
+
int sse42_tab_size;
|
|
1130
|
+
#endif /* HAVE_SIMD_NEON */
|
|
764
1131
|
const char *orig = str;
|
|
765
1132
|
bool has_hi = false;
|
|
766
1133
|
bool do_unicode_validation = false;
|
|
@@ -792,7 +1159,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
792
1159
|
long sz;
|
|
793
1160
|
|
|
794
1161
|
cmap = rails_xss_friendly_chars;
|
|
795
|
-
|
|
1162
|
+
#ifdef HAVE_SIMD_NEON
|
|
1163
|
+
cmap_neon = rails_xss_friendly_chars_neon;
|
|
1164
|
+
neon_table_size = 4;
|
|
1165
|
+
#endif /* HAVE_NEON_SIMD */
|
|
1166
|
+
sz = rails_xss_friendly_size((uint8_t *)str, cnt);
|
|
796
1167
|
if (sz < 0) {
|
|
797
1168
|
has_hi = true;
|
|
798
1169
|
size = (size_t)-sz;
|
|
@@ -805,7 +1176,11 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
805
1176
|
case RailsEsc: {
|
|
806
1177
|
long sz;
|
|
807
1178
|
cmap = rails_friendly_chars;
|
|
808
|
-
|
|
1179
|
+
#ifdef HAVE_SIMD_NEON
|
|
1180
|
+
cmap_neon = rails_friendly_chars_neon;
|
|
1181
|
+
neon_table_size = 2;
|
|
1182
|
+
#endif /* HAVE_NEON_SIMD */
|
|
1183
|
+
sz = rails_friendly_size((uint8_t *)str, cnt);
|
|
809
1184
|
if (sz < 0) {
|
|
810
1185
|
has_hi = true;
|
|
811
1186
|
size = (size_t)-sz;
|
|
@@ -816,7 +1191,15 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
816
1191
|
break;
|
|
817
1192
|
}
|
|
818
1193
|
case JSONEsc:
|
|
819
|
-
default: cmap = hibit_friendly_chars;
|
|
1194
|
+
default: cmap = hibit_friendly_chars;
|
|
1195
|
+
#ifdef HAVE_SIMD_NEON
|
|
1196
|
+
cmap_neon = hibit_friendly_chars_neon;
|
|
1197
|
+
neon_table_size = 2;
|
|
1198
|
+
#elif defined(HAVE_SIMD_SSE4_2)
|
|
1199
|
+
cmap_sse42 = hibit_friendly_chars_sse42;
|
|
1200
|
+
sse42_tab_size = 8;
|
|
1201
|
+
#endif /* HAVE_NEON_SIMD */
|
|
1202
|
+
size = hibit_friendly_size((uint8_t *)str, cnt);
|
|
820
1203
|
}
|
|
821
1204
|
assure_size(out, size + BUFFER_EXTRA);
|
|
822
1205
|
*out->cur++ = '"';
|
|
@@ -833,7 +1216,16 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
833
1216
|
if (is_sym) {
|
|
834
1217
|
*out->cur++ = ':';
|
|
835
1218
|
}
|
|
1219
|
+
#ifdef HAVE_FAST_MEMCPY
|
|
1220
|
+
if (cnt <= 16) {
|
|
1221
|
+
fast_memcpy16(out->cur, str, cnt);
|
|
1222
|
+
out->cur += size;
|
|
1223
|
+
} else {
|
|
1224
|
+
APPEND_CHARS(out->cur, str, cnt);
|
|
1225
|
+
}
|
|
1226
|
+
#else
|
|
836
1227
|
APPEND_CHARS(out->cur, str, cnt);
|
|
1228
|
+
#endif
|
|
837
1229
|
*out->cur++ = '"';
|
|
838
1230
|
} else {
|
|
839
1231
|
const char *end = str + cnt;
|
|
@@ -842,71 +1234,168 @@ void oj_dump_cstr(const char *str, size_t cnt, bool is_sym, bool escape1, Out ou
|
|
|
842
1234
|
if (is_sym) {
|
|
843
1235
|
*out->cur++ = ':';
|
|
844
1236
|
}
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
1237
|
+
|
|
1238
|
+
#if defined(HAVE_SIMD_NEON) || defined(HAVE_SIMD_SSE4_2)
|
|
1239
|
+
|
|
1240
|
+
#define SEARCH_FLUSH \
|
|
1241
|
+
if (str > cursor) { \
|
|
1242
|
+
APPEND_CHARS(out->cur, cursor, str - cursor); \
|
|
1243
|
+
cursor = str; \
|
|
1244
|
+
}
|
|
1245
|
+
|
|
1246
|
+
const char *chunk_start;
|
|
1247
|
+
const char *chunk_end;
|
|
1248
|
+
const char *cursor = str;
|
|
1249
|
+
char matches[16];
|
|
1250
|
+
#endif /* HAVE_SIMD_NEON || HAVE_SIMD_SSE4_2 */
|
|
1251
|
+
|
|
1252
|
+
#if defined(HAVE_SIMD_NEON)
|
|
1253
|
+
bool use_simd = (cmap_neon != NULL && cnt >= (sizeof(uint8x16_t))) ? true : false;
|
|
1254
|
+
#elif defined(HAVE_SIMD_SSE4_2)
|
|
1255
|
+
bool use_simd = false;
|
|
1256
|
+
if (SIMD_Impl == SIMD_SSE42) {
|
|
1257
|
+
use_simd = (cmap_sse42 != NULL && cnt >= (sizeof(__m128i))) ? true : false;
|
|
1258
|
+
}
|
|
1259
|
+
#endif
|
|
1260
|
+
|
|
1261
|
+
#ifdef HAVE_SIMD_NEON
|
|
1262
|
+
|
|
1263
|
+
#ifdef HAVE_FAST_MEMCPY
|
|
1264
|
+
#define APPEND_CHARS_SMALL(dst, src, length) \
|
|
1265
|
+
fast_memcpy16((dst), (src), (length)); \
|
|
1266
|
+
(dst) += (length);
|
|
1267
|
+
#define MEMCPY16 fast_memcpy16
|
|
1268
|
+
#else
|
|
1269
|
+
#define APPEND_CHARS_SMALL(dst, src, length) APPEND_CHARS(dst, str, length);
|
|
1270
|
+
#define MEMCPY16 memcpy
|
|
1271
|
+
#endif
|
|
1272
|
+
|
|
1273
|
+
if (use_simd) {
|
|
1274
|
+
while (str < end) {
|
|
1275
|
+
const char *chunk_ptr = NULL;
|
|
1276
|
+
if (str + sizeof(uint8x16_t) <= end) {
|
|
1277
|
+
chunk_ptr = str;
|
|
1278
|
+
chunk_start = str;
|
|
1279
|
+
chunk_end = str + sizeof(uint8x16_t);
|
|
1280
|
+
} else if ((end - str) >= SIMD_MINIMUM_THRESHOLD) {
|
|
1281
|
+
memset(out->cur, ' ', sizeof(uint8x16_t));
|
|
1282
|
+
MEMCPY16(out->cur, str, (end - str));
|
|
1283
|
+
chunk_ptr = out->cur;
|
|
1284
|
+
chunk_start = str;
|
|
1285
|
+
chunk_end = end;
|
|
1286
|
+
} else {
|
|
1287
|
+
break;
|
|
869
1288
|
}
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1289
|
+
neon_match_result result = neon_update(chunk_ptr,
|
|
1290
|
+
cmap_neon,
|
|
1291
|
+
neon_table_size,
|
|
1292
|
+
do_unicode_validation,
|
|
1293
|
+
has_hi);
|
|
1294
|
+
if ((result.do_unicode_validation) || result.escape_mask != 0) {
|
|
1295
|
+
SEARCH_FLUSH;
|
|
1296
|
+
bool process_each = result.do_unicode_validation;
|
|
1297
|
+
uint8x16_t actions = vaddq_u8(result.needs_escape, vdupq_n_u8('1'));
|
|
1298
|
+
vst1q_u8((unsigned char *)matches, actions);
|
|
1299
|
+
// If no byte in this chunk had the high bit set then we can skip
|
|
1300
|
+
// all of the '1' bytes by directly copying them to the output.
|
|
1301
|
+
if (!process_each) {
|
|
1302
|
+
while (result.escape_mask) {
|
|
1303
|
+
int esc_pos = OJ_CTZ64(result.escape_mask) >> 2;
|
|
1304
|
+
long run_len = esc_pos - (str - chunk_start);
|
|
1305
|
+
if (run_len > 0) {
|
|
1306
|
+
APPEND_CHARS_SMALL(out->cur, str, run_len);
|
|
1307
|
+
str += run_len;
|
|
1308
|
+
}
|
|
1309
|
+
str = process_character(matches[esc_pos],
|
|
1310
|
+
str,
|
|
1311
|
+
end,
|
|
1312
|
+
out,
|
|
1313
|
+
orig,
|
|
1314
|
+
do_unicode_validation,
|
|
1315
|
+
&check_start);
|
|
1316
|
+
str++;
|
|
1317
|
+
result.escape_mask &= result.escape_mask - 1;
|
|
1318
|
+
}
|
|
1319
|
+
if (str < chunk_end) {
|
|
1320
|
+
APPEND_CHARS_SMALL(out->cur, str, chunk_end - str);
|
|
1321
|
+
str = chunk_end;
|
|
1322
|
+
}
|
|
875
1323
|
} else {
|
|
876
|
-
|
|
877
|
-
|
|
1324
|
+
while (str < chunk_end) {
|
|
1325
|
+
long match_index = str - chunk_start;
|
|
1326
|
+
str = process_character(matches[match_index],
|
|
1327
|
+
str,
|
|
1328
|
+
end,
|
|
1329
|
+
out,
|
|
1330
|
+
orig,
|
|
1331
|
+
do_unicode_validation,
|
|
1332
|
+
&check_start);
|
|
1333
|
+
str++;
|
|
1334
|
+
}
|
|
878
1335
|
}
|
|
879
|
-
|
|
1336
|
+
cursor = str;
|
|
1337
|
+
continue;
|
|
880
1338
|
}
|
|
881
|
-
str =
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
1339
|
+
str = chunk_end;
|
|
1340
|
+
}
|
|
1341
|
+
SEARCH_FLUSH;
|
|
1342
|
+
}
|
|
1343
|
+
#endif
|
|
1344
|
+
|
|
1345
|
+
#ifdef HAVE_SIMD_SSE4_2
|
|
1346
|
+
if (SIMD_Impl == SIMD_SSE42) {
|
|
1347
|
+
if (use_simd) {
|
|
1348
|
+
while (str < end) {
|
|
1349
|
+
const char *chunk_ptr = NULL;
|
|
1350
|
+
if (str + sizeof(__m128i) <= end) {
|
|
1351
|
+
chunk_ptr = str;
|
|
1352
|
+
chunk_start = str;
|
|
1353
|
+
chunk_end = str + sizeof(__m128i);
|
|
1354
|
+
} else if ((end - str) >= SIMD_MINIMUM_THRESHOLD) {
|
|
1355
|
+
memset(out->cur, 'A', sizeof(__m128i));
|
|
1356
|
+
memcpy(out->cur, str, (end - str));
|
|
1357
|
+
chunk_ptr = out->cur;
|
|
1358
|
+
chunk_start = str;
|
|
1359
|
+
chunk_end = end;
|
|
1360
|
+
} else {
|
|
886
1361
|
break;
|
|
887
1362
|
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
1363
|
+
sse42_match_result result = sse42_update(chunk_ptr,
|
|
1364
|
+
cmap_sse42,
|
|
1365
|
+
sse42_tab_size,
|
|
1366
|
+
do_unicode_validation,
|
|
1367
|
+
has_hi);
|
|
1368
|
+
if ((result.do_unicode_validation) || result.needs_escape) {
|
|
1369
|
+
SEARCH_FLUSH;
|
|
1370
|
+
_mm_storeu_si128((__m128i *)matches, result.actions);
|
|
1371
|
+
while (str < chunk_end) {
|
|
1372
|
+
long match_index = str - chunk_start;
|
|
1373
|
+
str = process_character(matches[match_index],
|
|
1374
|
+
str,
|
|
1375
|
+
end,
|
|
1376
|
+
out,
|
|
1377
|
+
orig,
|
|
1378
|
+
do_unicode_validation,
|
|
1379
|
+
&check_start);
|
|
1380
|
+
str++;
|
|
897
1381
|
}
|
|
898
|
-
|
|
1382
|
+
cursor = str;
|
|
1383
|
+
continue;
|
|
899
1384
|
}
|
|
900
|
-
str =
|
|
1385
|
+
str = chunk_end;
|
|
901
1386
|
}
|
|
902
|
-
|
|
903
|
-
default: break; // ignore, should never happen if the table is correct
|
|
1387
|
+
SEARCH_FLUSH;
|
|
904
1388
|
}
|
|
905
1389
|
}
|
|
1390
|
+
#endif /* HAVE_SIMD_SSE4_2 */
|
|
1391
|
+
|
|
1392
|
+
for (; str < end; str++) {
|
|
1393
|
+
str = process_character(cmap[(uint8_t)*str], str, end, out, orig, do_unicode_validation, &check_start);
|
|
1394
|
+
}
|
|
906
1395
|
*out->cur++ = '"';
|
|
907
1396
|
}
|
|
908
1397
|
if (do_unicode_validation && 0 < str - orig && 0 != (0x80 & *(str - 1))) {
|
|
909
|
-
uint8_t c = (uint8_t)
|
|
1398
|
+
uint8_t c = (uint8_t)*(str - 1);
|
|
910
1399
|
int i;
|
|
911
1400
|
int scnt = (int)(str - orig);
|
|
912
1401
|
|
|
@@ -957,7 +1446,7 @@ void oj_dump_class(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
957
1446
|
void oj_dump_obj_to_s(VALUE obj, Out out) {
|
|
958
1447
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
959
1448
|
|
|
960
|
-
oj_dump_cstr(RSTRING_PTR(rstr),
|
|
1449
|
+
oj_dump_cstr(RSTRING_PTR(rstr), RSTRING_LEN(rstr), 0, 0, out);
|
|
961
1450
|
}
|
|
962
1451
|
|
|
963
1452
|
void oj_dump_raw(const char *str, size_t cnt, Out out) {
|
|
@@ -1092,7 +1581,7 @@ void oj_dump_fixnum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1092
1581
|
|
|
1093
1582
|
void oj_dump_bignum(VALUE obj, int depth, Out out, bool as_ok) {
|
|
1094
1583
|
volatile VALUE rs = rb_big2str(obj, 10);
|
|
1095
|
-
|
|
1584
|
+
size_t cnt = RSTRING_LEN(rs);
|
|
1096
1585
|
bool dump_as_string = false;
|
|
1097
1586
|
|
|
1098
1587
|
if (out->opts->int_range_max != 0 || out->opts->int_range_min != 0) { // Bignum cannot be inside of Fixnum range
|
|
@@ -1114,7 +1603,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1114
1603
|
char buf[64];
|
|
1115
1604
|
char *b;
|
|
1116
1605
|
double d = rb_num2dbl(obj);
|
|
1117
|
-
|
|
1606
|
+
size_t cnt = 0;
|
|
1118
1607
|
|
|
1119
1608
|
if (0.0 == d) {
|
|
1120
1609
|
b = buf;
|
|
@@ -1225,7 +1714,7 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1225
1714
|
} else if (0 == out->opts->float_prec) {
|
|
1226
1715
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
1227
1716
|
|
|
1228
|
-
cnt =
|
|
1717
|
+
cnt = RSTRING_LEN(rstr);
|
|
1229
1718
|
if ((int)sizeof(buf) <= cnt) {
|
|
1230
1719
|
cnt = sizeof(buf) - 1;
|
|
1231
1720
|
}
|
|
@@ -1239,8 +1728,8 @@ void oj_dump_float(VALUE obj, int depth, Out out, bool as_ok) {
|
|
|
1239
1728
|
*out->cur = '\0';
|
|
1240
1729
|
}
|
|
1241
1730
|
|
|
1242
|
-
|
|
1243
|
-
|
|
1731
|
+
size_t oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char *format) {
|
|
1732
|
+
size_t cnt = snprintf(buf, blen, format, d);
|
|
1244
1733
|
|
|
1245
1734
|
// Round off issues at 16 significant digits so check for obvious ones of
|
|
1246
1735
|
// 0001 and 9999.
|
|
@@ -1248,7 +1737,29 @@ int oj_dump_float_printf(char *buf, size_t blen, VALUE obj, double d, const char
|
|
|
1248
1737
|
volatile VALUE rstr = oj_safe_string_convert(obj);
|
|
1249
1738
|
|
|
1250
1739
|
strcpy(buf, RSTRING_PTR(rstr));
|
|
1251
|
-
cnt =
|
|
1740
|
+
cnt = RSTRING_LEN(rstr);
|
|
1252
1741
|
}
|
|
1253
1742
|
return cnt;
|
|
1254
1743
|
}
|
|
1744
|
+
|
|
1745
|
+
bool oj_key_skip(VALUE key, const char *only, const char *except) {
|
|
1746
|
+
const char *skey;
|
|
1747
|
+
|
|
1748
|
+
switch (rb_type(key)) {
|
|
1749
|
+
case RUBY_T_STRING: skey = StringValueCStr(key); break;
|
|
1750
|
+
case RUBY_T_SYMBOL: skey = rb_id2name(rb_sym2id(key)); break;
|
|
1751
|
+
default: skey = NULL; break;
|
|
1752
|
+
}
|
|
1753
|
+
if (NULL != skey && '\0' != *skey) {
|
|
1754
|
+
size_t size = strlen(skey);
|
|
1755
|
+
char *buf = alloca(size + 3);
|
|
1756
|
+
|
|
1757
|
+
buf[0] = ':';
|
|
1758
|
+
strcpy(buf + 1, skey);
|
|
1759
|
+
buf[size + 1] = ':';
|
|
1760
|
+
buf[size + 2] = '\0';
|
|
1761
|
+
|
|
1762
|
+
return ((NULL != only && NULL == strstr(only, buf)) || (NULL != except && NULL != strstr(except, buf)));
|
|
1763
|
+
}
|
|
1764
|
+
return NULL != only;
|
|
1765
|
+
}
|