From 1da49556247506727a32d260fec68851259cf3b4 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 1 Nov 2024 20:07:57 +0100 Subject: [PATCH 1/2] Speedup #generate_json by using case/when/end MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * if/elsif comparing `obj.class` is significantly slower: https://github.com/ruby/json/pull/668#issuecomment-2450747190 * The only case where an exact class check is needed so far is for String (https://github.com/ruby/json/issues/667). * Before: $ ruby -Ilib:ext benchmark/standalone.rb dump pure JSON::Pure::Generator truffleruby 24.2.0-dev-07b978e4, like ruby 3.2.4, Oracle GraalVM JVM [x86_64-linux] Calculating ------------------------------------- JSON.dump(obj) 6.426k (± 5.9%) i/s (155.62 μs/i) - 32.395k in 5.064479s JSON.dump(obj) 6.380k (± 7.4%) i/s (156.73 μs/i) - 31.806k in 5.021304s JSON.dump(obj) 6.276k (±10.5%) i/s (159.33 μs/i) - 31.217k in 5.060762s JSON.dump(obj) 6.450k (± 7.0%) i/s (155.05 μs/i) - 32.395k in 5.059538s JSON.dump(obj) 6.413k (± 6.2%) i/s (155.93 μs/i) - 32.395k in 5.081573s * After: $ ruby -Ilib:ext benchmark/standalone.rb dump pure JSON::Pure::Generator truffleruby 24.2.0-dev-07b978e4, like ruby 3.2.4, Oracle GraalVM JVM [x86_64-linux] Calculating ------------------------------------- JSON.dump(obj) 8.237k (± 5.0%) i/s (121.41 μs/i) - 41.600k in 5.069507s JSON.dump(obj) 8.179k (± 5.1%) i/s (122.26 μs/i) - 40.768k in 5.002035s JSON.dump(obj) 8.147k (± 7.9%) i/s (122.74 μs/i) - 40.768k in 5.044840s JSON.dump(obj) 8.137k (± 6.9%) i/s (122.90 μs/i) - 40.768k in 5.048690s JSON.dump(obj) 8.112k (±10.2%) i/s (123.27 μs/i) - 39.936k in 5.023502s --- lib/json/pure/generator.rb | 30 ++++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/lib/json/pure/generator.rb b/lib/json/pure/generator.rb index d6cca92c..21e76546 100644 --- a/lib/json/pure/generator.rb +++ b/lib/json/pure/generator.rb @@ -307,20 +307,18 @@ def generate(obj) # Handles @allow_nan, @buffer_initial_length, other ivars must be the default value (see above) private def generate_json(obj, buf) - klass = obj.class - if klass == Hash + case obj + when Hash buf << '{' first = true obj.each_pair do |k,v| buf << ',' unless first key_str = k.to_s - if key_str.is_a?(::String) - if key_str.class == ::String - fast_serialize_string(key_str, buf) - else - generate_json(key_str, buf) - end + if key_str.class == String + fast_serialize_string(key_str, buf) + elsif key_str.is_a?(String) + generate_json(key_str, buf) else raise TypeError, "#{k.class}#to_s returns an instance of #{key_str.class}, expected a String" end @@ -330,7 +328,7 @@ def generate(obj) first = false end buf << '}' - elsif klass == Array + when Array buf << '[' first = true obj.each do |e| @@ -339,9 +337,13 @@ def generate(obj) first = false end buf << ']' - elsif klass == String - fast_serialize_string(obj, buf) - elsif klass == Integer + when String + if obj.class == String + fast_serialize_string(obj, buf) + else + buf << obj.to_json(self) + end + when Integer buf << obj.to_s else # Note: Float is handled this way since Float#to_s is slow anyway @@ -432,8 +434,8 @@ def json_transform(state) result << state.indent * depth if indent key_str = key.to_s - key_json = if key_str.is_a?(::String) - key_str = key_str.to_json(state) + if key_str.is_a?(String) + key_json = key_str.to_json(state) else raise TypeError, "#{key.class}#to_s returns an instance of #{key_str.class}, expected a String" end From 82d21f01c5c20da40e932216da2a91c05d9165a4 Mon Sep 17 00:00:00 2001 From: Benoit Daloze Date: Fri, 1 Nov 2024 20:22:42 +0100 Subject: [PATCH 2/2] Re-enable passing test --- test/json/json_parser_test.rb | 2 -- 1 file changed, 2 deletions(-) diff --git a/test/json/json_parser_test.rb b/test/json/json_parser_test.rb index 6d8456c7..adff9167 100644 --- a/test/json/json_parser_test.rb +++ b/test/json/json_parser_test.rb @@ -32,8 +32,6 @@ def test_argument_encoding_for_binary_unmodified end def test_error_message_encoding - pend if RUBY_ENGINE == 'truffleruby' - bug10705 = '[ruby-core:67386] [Bug #10705]' json = ".\"\xE2\x88\x9A\"" assert_equal(Encoding::UTF_8, json.encoding)