Skip to content

Commit b8cdf32

Browse files
byrootsamyron
andcommitted
parser.c: Skip checking for escape sequences in rstring_cache_fetch
The caller already know if the string contains escape sequences so this check is redundant. Also stop calling `rstring_cache_fetch` from `json_string_unescape` as we know it won't match anyways. ``` == Parsing twitter.json (567916 bytes) ruby 3.4.6 (2025-09-16 revision dbd83256b1) +YJIT +PRISM [arm64-darwin24] Warming up -------------------------------------- after 122.000 i/100ms Calculating ------------------------------------- after 1.226k (± 0.3%) i/s (815.85 μs/i) - 6.222k in 5.076282s Comparison: before: 1206.2 i/s after: 1225.7 i/s - 1.02x faster ``` Co-Authored-By: Scott Myron <samyron@gmail.com>
1 parent 349b490 commit b8cdf32

File tree

2 files changed

+12
-25
lines changed

2 files changed

+12
-25
lines changed

ext/json/ext/parser/parser.c

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,6 @@ static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const lon
122122
}
123123
}
124124

125-
if (RB_UNLIKELY(memchr(str, '\\', length))) {
126-
// We assume the overwhelming majority of names don't need to be escaped.
127-
// But if they do, we have to fallback to the slow path.
128-
return Qfalse;
129-
}
130-
131125
VALUE rstring = build_interned_string(str, length);
132126

133127
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
@@ -174,12 +168,6 @@ static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const lon
174168
}
175169
}
176170

177-
if (RB_UNLIKELY(memchr(str, '\\', length))) {
178-
// We assume the overwhelming majority of names don't need to be escaped.
179-
// But if they do, we have to fallback to the slow path.
180-
return Qfalse;
181-
}
182-
183171
VALUE rsymbol = build_symbol(str, length);
184172

185173
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
@@ -652,19 +640,6 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
652640
int unescape_len;
653641
char buf[4];
654642

655-
if (is_name && state->in_array) {
656-
VALUE cached_key;
657-
if (RB_UNLIKELY(symbolize)) {
658-
cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
659-
} else {
660-
cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize);
661-
}
662-
663-
if (RB_LIKELY(cached_key)) {
664-
return cached_key;
665-
}
666-
}
667-
668643
VALUE result = rb_str_buf_new(bufferSize);
669644
rb_enc_associate_index(result, utf8_encindex);
670645
buffer = RSTRING_PTR(result);

test/json/json_parser_test.rb

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,18 @@ def test_parse_big_integers
344344
assert_equal orig, parse(json5)
345345
end
346346

347+
def test_parse_escaped_key
348+
doc = {
349+
"test\r1" => 1,
350+
"entries" => [
351+
"test\t2" => 2,
352+
"test\n3" => 3,
353+
]
354+
}
355+
356+
assert_equal doc, parse(JSON.generate(doc))
357+
end
358+
347359
def test_parse_duplicate_key
348360
expected = {"a" => 2}
349361
expected_sym = {a: 2}

0 commit comments

Comments
 (0)