summaryrefslogtreecommitdiff
path: root/ext/json/fbuffer
AgeCommit message (Collapse)Author
2025-11-18[ruby/json] Use #if instead of #ifdef when checking for JSON_DEBUG so ↵Scott Myron
debugging code is not generated when JSON_DEBUG=0. https://github.com/ruby/json/commit/4f1adb10d3
2025-11-03[ruby/json] Centralize macro definitionsJean Boussier
https://github.com/ruby/json/commit/1576ea7d47
2025-10-31[ruby/json] Fix memory leak when exception is raised during JSON generation ↵Kazuki Yamaguchi
part 2 Commit https://github.com/ruby/json/commit/44df509dc2de fixed it for StandardError, but other exceptions and jumps are also possible. Use rb_ensure() to release FBuffer instead of rb_rescue(). A reproducer: o = Object.new def o.to_json(a) = throw :a a = ["make heap allocation"*100, o] 10.times do 100_000.times do catch(:a) { JSON(a) } end puts `ps -o rss= -p #{$$}` end https://github.com/ruby/json/commit/9b7b648ecd
2025-08-27JSON.generate: warn or raise on duplicated keyJean Boussier
Because both strings and symbols keys are serialized the same, it always has been possible to generate documents with duplicated keys: ```ruby >> puts JSON.generate({ foo: 1, "foo" => 2 }) {"foo":1,"foo":2} ``` This is pretty much always a mistake and can cause various issues because it's not guaranteed how various JSON parsers will handle this. Until now I didn't think it was possible to catch such case without tanking performance, hence why I only made the parser more strict. But I finally found a way to check for duplicated keys cheaply enough.
2025-08-27[ruby/json] Optimize `fbuffer_append_str_repeat`Jean Boussier
Helps with pretty printting performance: ``` == Encoding activitypub.json (52595 bytes) ruby 3.4.2 (2025-02-15 revision https://github.com/ruby/json/commit/d2930f8e7a) +YJIT +PRISM [arm64-darwin24] Warming up -------------------------------------- after 1.746k i/100ms Calculating ------------------------------------- after 17.481k (± 1.0%) i/s (57.20 μs/i) - 89.046k in 5.094341s Comparison: before: 16038.4 i/s after: 17481.1 i/s - 1.09x faster == Encoding citm_catalog.json (500298 bytes) ruby 3.4.2 (2025-02-15 revision https://github.com/ruby/json/commit/d2930f8e7a) +YJIT +PRISM [arm64-darwin24] Warming up -------------------------------------- after 60.000 i/100ms Calculating ------------------------------------- after 608.157 (± 2.3%) i/s (1.64 ms/i) - 3.060k in 5.034238s Comparison: before: 525.3 i/s after: 608.2 i/s - 1.16x faster == Encoding twitter.json (466906 bytes) ruby 3.4.2 (2025-02-15 revision https://github.com/ruby/json/commit/d2930f8e7a) +YJIT +PRISM [arm64-darwin24] Warming up -------------------------------------- after 160.000 i/100ms Calculating ------------------------------------- after 1.606k (± 0.5%) i/s (622.70 μs/i) - 8.160k in 5.081406s Comparison: before: 1410.3 i/s after: 1605.9 i/s - 1.14x faster ``` https://github.com/ruby/json/commit/f0dda861c5
2025-08-27[ruby/json] Extract `fbuffer_append_str_repeat` functionJean Boussier
https://github.com/ruby/json/commit/12656777dc
2025-05-26[ruby/json] fbuffer.c: add debug mode with bound checks.Jean Boussier
This would have caught https://github.com/ruby/json/pull/808 on CI. https://github.com/ruby/json/commit/8109421fb4
2025-03-27Refactor jeaiii-ltoa.hJean Boussier
Some relatively minor change to make the library more in line with the gem. Some renaming, etc. Notes: Merged: https://github.com/ruby/ruby/pull/12994
2025-03-27Removed trailing spacesHiroshi SHIBATA
2025-03-27Faster integer formattingeno
This commit provides an alternative implementation for a long → decimal conversion. The main difference is that it uses an algorithm pulled from https://github.com/jeaiii/itoa. The source there is C++, it was converted by hand to C for inclusion with this gem. jeaiii's algorithm is covered by the MIT License, see source code. On addition this version now also generates the string directly into the fbuffer, foregoing the need to run a separate memory copy. As a result, I see a speedup of 32% on Apple Silicon M1 for an integer set of benchmarks.
2025-01-20[ruby/json] Replace fbuffer by stack buffers or RB_ALLOCV in parser.cJean Boussier
We only use that buffer for parsing integer and floats, these are unlikely to be very big, and if so we can just use RB_ALLOCV as it will almost always end in a small `alloca`. This allow to no longer need `rb_protect` around the parser. https://github.com/ruby/json/commit/994859916a Notes: Merged: https://github.com/ruby/ruby/pull/12598
2024-11-26[ruby/json] JSON.dump: write directly into the provided IOJean Boussier
Ref: https://github.com/ruby/json/issues/524 Rather than to buffer everything in memory. Unfortunately Ruby doesn't provide an API to write into and IO without first allocating a string, which is a bit wasteful. https://github.com/ruby/json/commit/f017af6c0a
2024-11-05[ruby/json] ResyncJean Boussier
Notes: Merged: https://github.com/ruby/ruby/pull/12003
2024-11-01JSON.generate: call to_json on String subclassesJean Boussier
Fix: https://github.com/ruby/json/issues/667 This is yet another behavior on which the various implementations differed, but the C implementation used to call `to_json` on String subclasses used as keys. This was optimized out in e125072130229e54a651f7b11d7d5a782ae7fb65 but there is an Active Support test case for it, so it's best to make all 3 implementation respect this behavior.
2024-11-01[ruby/json] Make fbuffer_inc_capa easier to inlineJean Boussier
With the extra logic added for stack allocation, and especially the memcpy, it became harder for compilers to inline. This doesn't fully reclaim the speed lost with the stack allocation, but it's getting closer. Before: ``` == Encoding twitter.json (466906 bytes) ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- json 160.000 i/100ms oj 225.000 i/100ms Calculating ------------------------------------- json 1.577k (± 2.0%) i/s (634.20 μs/i) - 8.000k in 5.075561s oj 2.264k (± 2.3%) i/s (441.79 μs/i) - 11.475k in 5.072205s Comparison: json: 1576.8 i/s oj: 2263.5 i/s - 1.44x faster == Encoding citm_catalog.json (500298 bytes) ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- json 101.000 i/100ms oj 123.000 i/100ms Calculating ------------------------------------- json 1.033k (± 2.6%) i/s (968.06 μs/i) - 5.252k in 5.087617s oj 1.257k (± 2.2%) i/s (795.54 μs/i) - 6.396k in 5.090830s Comparison: json: 1033.0 i/s oj: 1257.0 i/s - 1.22x faster ``` After: ``` == Encoding twitter.json (466906 bytes) ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) [arm64-darwin23] Warming up -------------------------------------- json 213.000 i/100ms oj 230.000 i/100ms Calculating ------------------------------------- json 2.064k (± 3.6%) i/s (484.44 μs/i) - 10.437k in 5.063685s oj 2.246k (± 0.7%) i/s (445.19 μs/i) - 11.270k in 5.017541s Comparison: json: 2064.2 i/s oj: 2246.2 i/s - 1.09x faster == Encoding citm_catalog.json (500298 bytes) ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) [arm64-darwin23] Warming up -------------------------------------- json 133.000 i/100ms oj 132.000 i/100ms Calculating ------------------------------------- json 1.327k (± 1.7%) i/s (753.69 μs/i) - 6.650k in 5.013565s oj 1.305k (± 2.2%) i/s (766.40 μs/i) - 6.600k in 5.061089s Comparison: json: 1326.8 i/s oj: 1304.8 i/s - same-ish: difference falls within error ``` https://github.com/ruby/json/commit/89f816e868
2024-11-01[ruby/json] Allocate the initial generator buffer on the stackJean Boussier
Ref: https://github.com/ruby/json/issues/655 Followup: https://github.com/ruby/json/issues/657 Assuming the generator might be used for fairly small documents we can start with a reasonable buffer size of the stack, and if we outgrow it, we can spill on the heap. In a way this is optimizing for micro-benchmarks, but there are valid use case for fiarly small JSON document in actual real world scenarios, so trashing the GC less in such case make sense. Before: ``` ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- Oj 518.700k i/100ms JSON reuse 483.370k i/100ms Calculating ------------------------------------- Oj 5.722M (± 1.8%) i/s (174.76 ns/i) - 29.047M in 5.077823s JSON reuse 5.278M (± 1.5%) i/s (189.46 ns/i) - 26.585M in 5.038172s Comparison: Oj: 5722283.8 i/s JSON reuse: 5278061.7 i/s - 1.08x slower ``` After: ``` ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- Oj 517.837k i/100ms JSON reuse 548.871k i/100ms Calculating ------------------------------------- Oj 5.693M (± 1.6%) i/s (175.65 ns/i) - 28.481M in 5.004056s JSON reuse 5.855M (± 1.2%) i/s (170.80 ns/i) - 29.639M in 5.063004s Comparison: Oj: 5692985.6 i/s JSON reuse: 5854857.9 i/s - 1.03x faster ``` https://github.com/ruby/json/commit/fe607f4806
2024-10-30[ruby/json] Allocate the FBuffer struct on the stackJean Boussier
Ref: https://github.com/ruby/json/issues/655 The actual buffer is still on the heap, but this saves a pair of malloc/free. This helps a lot on micro-benchmarks Before: ``` ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- Oj 531.598k i/100ms JSON reuse 417.666k i/100ms Calculating ------------------------------------- Oj 5.735M (± 1.3%) i/s (174.35 ns/i) - 28.706M in 5.005900s JSON reuse 4.604M (± 1.4%) i/s (217.18 ns/i) - 23.389M in 5.080779s Comparison: Oj: 5735475.6 i/s JSON reuse: 4604380.3 i/s - 1.25x slower ``` After: ``` ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- Oj 518.700k i/100ms JSON reuse 483.370k i/100ms Calculating ------------------------------------- Oj 5.722M (± 1.8%) i/s (174.76 ns/i) - 29.047M in 5.077823s JSON reuse 5.278M (± 1.5%) i/s (189.46 ns/i) - 26.585M in 5.038172s Comparison: Oj: 5722283.8 i/s JSON reuse: 5278061.7 i/s - 1.08x slower ``` Bench: ```ruby require 'benchmark/ips' require 'oj' require 'json' json_encoder = JSON::State.new(JSON.dump_default_options) test_data = [1, "string", { a: 1, b: 2 }, [3, 4, 5]] Oj.default_options = Oj.default_options.merge(mode: :compat) Benchmark.ips do |x| x.config(time: 5, warmup: 2) x.report("Oj") do Oj.dump(test_data) end x.report("JSON reuse") do json_encoder.generate(test_data) end x.compare!(order: :baseline) end ``` https://github.com/ruby/json/commit/72110f7992
2024-10-29[ruby/json] Optimize `fbuffer_append_long`Jean Boussier
Ref: https://github.com/ruby/json/issues/655 Rather than to write the number backward, and then reverse the buffer, we can start from the back of the buffer and write the number in the proper direction. Before: ``` == Encoding integers (8009 bytes) ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- json 8.606k i/100ms oj 9.598k i/100ms Calculating ------------------------------------- json 86.059k (± 0.8%) i/s (11.62 μs/i) - 430.300k in 5.000416s oj 97.409k (± 0.6%) i/s (10.27 μs/i) - 489.498k in 5.025360s Comparison: json: 86058.8 i/s oj: 97408.8 i/s - 1.13x faster ``` After: ``` == Encoding integers (8009 bytes) ruby 3.3.4 (2024-07-09 revision https://github.com/ruby/json/commit/be1089c8ec) +YJIT [arm64-darwin23] Warming up -------------------------------------- json (reuse) 9.500k i/100ms json 9.359k i/100ms oj 9.722k i/100ms Calculating ------------------------------------- json (reuse) 96.270k (± 0.4%) i/s (10.39 μs/i) - 484.500k in 5.032777s json 94.800k (± 2.2%) i/s (10.55 μs/i) - 477.309k in 5.037495s oj 97.131k (± 0.7%) i/s (10.30 μs/i) - 486.100k in 5.004822s Comparison: json (reuse): 96270.1 i/s oj: 97130.5 i/s - same-ish: difference falls within error json: 94799.9 i/s - same-ish: difference falls within error ``` https://github.com/ruby/json/commit/0655b58d14
2024-10-17[ruby/json] Get rid of some more outdated compatibility codeJean Boussier
All these macros are available on Ruby 2.3+ https://github.com/ruby/json/commit/227885f460
2024-10-17[ruby/json] Stop prebuilding object_delim2Yusuke Endoh
Also, remove static functions that are no longer used. This speeds up `JSON.generate` by about 5% in a benchmark. https://github.com/ruby/json/commit/4c984b2017
2024-10-03[flori/json] Optimize `fbuffer_inc_capa`Jean Boussier
On my `JSON.dump` benchmark it shows up as 6% of runtime, compared to 40% for `convert_UTF8_to_JSON`. Since the vast majority of the time this function is called we still have some buffer capacity, we might as well check that first and skip the expensive loop etc. With this change my profiler now report this function as 0.7%, so almost 10x better. https://github.com/flori/json/commit/a7206bf2db Notes: Merged: https://github.com/ruby/ruby/pull/11775
2024-09-03[flori/json] Remove outdated ifdef checksJean Boussier
`json` requires Ruby 2.3, so `HAVE_RUBY_ENCODING_H` and `HAVE_RB_ENC_RAISE` are always true. https://github.com/flori/json/commit/5c8dc6b70a
2017-04-12Merge json-2.0.4.hsbt
* https://github.com/flori/json/releases/tag/v2.0.4 * https://github.com/flori/json/blob/09fabeb03e73ed88dc8ce8f19d76ac59e51dae20/CHANGES.md#2017-03-23-204 git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58323 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-04-12* ext/json/*, test/json/*: Reverted r50231. Because it's not works withhsbt
cross-compile environment. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50267 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2015-04-11* ext/json/*, test/json/*, defs/default_gems: Gemify JSON library.hsbt
[fix GH-867][Feature #11057] * test/ruby/test_extlibs.rb: removed json gem from existence extentions. * gems/bundled_gems: added json gem into bundled gem. * lib/rdoc/rubygems_hook.rb: ignored no json environment. * lib/rubygems/test_case.rb, test/rubygems/*: ditto. * lib/rdoc/test_case.rb, test/rdoc/*: ditto. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50231 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-09-18fbuffer.h: expand argumentsnobu
* ext/json/fbuffer/fbuffer.h (fbuffer_to_s): expand arguments, for fix with rb_str_new macro. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@47626 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2014-01-15ext/json: backward compatibilitiesnobu
* ext/json/fbuffer/fbuffer.h, ext/json/generator/generator.c: add macros for backward compatibilities. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@44615 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-11-20* ext/json: merge JSON 1.8.1.naruse
https://github.com/nurse/json/compare/002ac2771ce32776b32ccd2d06e5604de6c36dcd...e09ffc0d7da25d0393873936c118c188c78dbac3 * Remove Rubinius exception since transcoding should be working now. * Fix https://github.com/flori/json/issues/162 reported by Marc-Andre Lafortune <github_rocks@marc-andre.ca>. Thanks! * Applied patches by Yui NARUSE <naruse@airemix.jp> to suppress warning with -Wchar-subscripts and better validate UTF-8 strings. * Applied patch by ginriki@github to remove unnecessary if. * Add load/dump interface to JSON::GenericObject to make serialize :some_attribute, JSON::GenericObject work in Rails active models for convenient SomeModel#some_attribute.foo.bar access to serialised JSON data. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@43731 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-09-12Eliminate less-than-zero checks for unsigned variablesnobu
* ext/bigdecimal/bigdecimal.c, ext/digest/md5/md5.c, ext/json/fbuffer/fbuffer.h, ext/json/generator/generator.c: Eliminate less-than-zero checks for unsigned variables. According to section 4.1.5 of C89 standard, size_t is an unsigned type. These checks were found with 'cppcheck' static analysis tool. [ruby-core:57117] [Feature #8890] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42920 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-06-07* ext/json/fbuffer/fbuffer.h (fbuffer_append_str): change the place ofnaruse
RB_GC_GUARD. it should be after the object is used. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@41135 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2013-02-12* ext/json: merge JSON 1.7.7.naruse
This includes security fix. [CVE-2013-0269] https://github.com/flori/json/commit/d0a62f3ced7560daba2ad546d83f0479a5ae2cf2 https://groups.google.com/d/topic/rubyonrails-security/4_YvCpLzL58/discussion git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@39208 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-12-12* ext/json: merge JSON 1.7.5.naruse
fix tests and other fixes. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@38346 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-07-25avoid compilation error on AIX by -ansi -std=iso9899:199409 (r36038). ↵kanemoto
[ruby-core:46744] [Bug #6791]. This issue is fixed in upper stream as issue #142. (https://github.com/flori/json/issues/142) git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@36541 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-05-07* ext/json: Merge JSON 1.7.1.naruse
https://github.com/flori/json/commit/e5b9a9465c1159fae533bca320d950b772bcb4ac git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-05-07Revert r35560.naruse
This breaks tests: http://u64.rubyci.org/~chkbuild/ruby-trunk/log/20120507T070102Z.log.html.gz And don't change local codes, contribute it to upstream: https://github.com/flori/json git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35562 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-05-07ext/json/fbuffer/fbuffer.hnobu
* ext/json/fbuffer/fbuffer.h: comment-out unused functions. * ext/json/parser/depend: add dependency. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35560 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-04-15Add debug prints to inspect TC_JSONGenerate#test_gc's timeout issue.naruse
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35336 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-04-08Additional experimental fix for r35261.naruse
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@35264 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
2012-03-11Add missing files of r34971,naruse
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@34973 b2dd03c8-39d4-4d8f-98ff-823fe69b080e