summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2025-11-03 10:46:20 +0100
committergit <svn-admin@ruby-lang.org>2025-11-03 09:58:01 +0000
commitedebd83ea99651a47d4592f2cef12618da3a0736 (patch)
tree55d6dc6488e06dc5ef79ce1e7ac3f0fb0e2c4d54
parent35a5e5513377d0d1f13c3ab15966a5c51b24066c (diff)
[ruby/json] 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 https://github.com/ruby/json/commit/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 ``` https://github.com/ruby/json/commit/b8cdf3282d Co-Authored-By: Scott Myron <samyron@gmail.com>
-rw-r--r--ext/json/parser/parser.c25
-rw-r--r--test/json/json_parser_test.rb12
2 files changed, 12 insertions, 25 deletions
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c
index d9b578f245..68ff6d7ac3 100644
--- a/ext/json/parser/parser.c
+++ b/ext/json/parser/parser.c
@@ -122,12 +122,6 @@ static VALUE rstring_cache_fetch(rvalue_cache *cache, const char *str, const lon
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rstring = build_interned_string(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
@@ -174,12 +168,6 @@ static VALUE rsymbol_cache_fetch(rvalue_cache *cache, const char *str, const lon
}
}
- if (RB_UNLIKELY(memchr(str, '\\', length))) {
- // We assume the overwhelming majority of names don't need to be escaped.
- // But if they do, we have to fallback to the slow path.
- return Qfalse;
- }
-
VALUE rsymbol = build_symbol(str, length);
if (cache->length < JSON_RVALUE_CACHE_CAPA) {
@@ -652,19 +640,6 @@ static VALUE json_string_unescape(JSON_ParserState *state, const char *string, c
int unescape_len;
char buf[4];
- if (is_name && state->in_array) {
- VALUE cached_key;
- if (RB_UNLIKELY(symbolize)) {
- cached_key = rsymbol_cache_fetch(&state->name_cache, string, bufferSize);
- } else {
- cached_key = rstring_cache_fetch(&state->name_cache, string, bufferSize);
- }
-
- if (RB_LIKELY(cached_key)) {
- return cached_key;
- }
- }
-
VALUE result = rb_str_buf_new(bufferSize);
rb_enc_associate_index(result, utf8_encindex);
buffer = RSTRING_PTR(result);
diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb
index bab16a6fc2..6315c3e667 100644
--- a/test/json/json_parser_test.rb
+++ b/test/json/json_parser_test.rb
@@ -344,6 +344,18 @@ class JSONParserTest < Test::Unit::TestCase
assert_equal orig, parse(json5)
end
+ def test_parse_escaped_key
+ doc = {
+ "test\r1" => 1,
+ "entries" => [
+ "test\t2" => 2,
+ "test\n3" => 3,
+ ]
+ }
+
+ assert_equal doc, parse(JSON.generate(doc))
+ end
+
def test_parse_duplicate_key
expected = {"a" => 2}
expected_sym = {a: 2}