diff options
-rw-r--r-- | ext/json/parser/extconf.rb | 5 | ||||
-rw-r--r-- | ext/json/parser/parser.c | 15 | ||||
-rw-r--r-- | ext/json/parser/parser.rl | 15 | ||||
-rw-r--r-- | test/json/json_ext_parser_test.rb | 20 | ||||
-rw-r--r-- | test/json/test_helper.rb | 18 |
5 files changed, 70 insertions, 3 deletions
diff --git a/ext/json/parser/extconf.rb b/ext/json/parser/extconf.rb index 8705884127..c3c23d2cb4 100644 --- a/ext/json/parser/extconf.rb +++ b/ext/json/parser/extconf.rb @@ -1,9 +1,8 @@ # frozen_string_literal: true require 'mkmf' -have_func("rb_enc_raise", "ruby.h") -have_func("rb_enc_interned_str", "ruby.h") - +have_func("rb_enc_interned_str", "ruby.h") # RUBY_VERSION >= 3.0 +have_func("rb_gc_mark_locations") # Missing on TruffleRuby append_cflags("-std=c99") create_makefile 'json/ext/parser' diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index cdf8983a77..758dba4694 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -2115,6 +2115,19 @@ case 9: } } +#ifndef HAVE_RB_GC_MARK_LOCATIONS +// For TruffleRuby +void rb_gc_mark_locations(const VALUE *start, const VALUE *end) +{ + VALUE *value = start; + + while (value < end) { + rb_gc_mark(*value); + value++; + } +} +#endif + static void JSON_mark(void *ptr) { JSON_Parser *json = ptr; @@ -2124,6 +2137,8 @@ static void JSON_mark(void *ptr) rb_gc_mark(json->array_class); rb_gc_mark(json->decimal_class); rb_gc_mark(json->match_string); + const VALUE *name_cache_entries = &json->name_cache.entries[0]; + rb_gc_mark_locations(name_cache_entries, name_cache_entries + json->name_cache.length); } static void JSON_free(void *ptr) diff --git a/ext/json/parser/parser.rl b/ext/json/parser/parser.rl index 3301f1608c..15ec2b6843 100644 --- a/ext/json/parser/parser.rl +++ b/ext/json/parser/parser.rl @@ -875,6 +875,19 @@ static VALUE cParser_parse(VALUE self) } } +#ifndef HAVE_RB_GC_MARK_LOCATIONS +// For TruffleRuby +void rb_gc_mark_locations(const VALUE *start, const VALUE *end) +{ + VALUE *value = start; + + while (value < end) { + rb_gc_mark(*value); + value++; + } +} +#endif + static void JSON_mark(void *ptr) { JSON_Parser *json = ptr; @@ -884,6 +897,8 @@ static void JSON_mark(void *ptr) rb_gc_mark(json->array_class); rb_gc_mark(json->decimal_class); rb_gc_mark(json->match_string); + const VALUE *name_cache_entries = &json->name_cache.entries[0]; + rb_gc_mark_locations(name_cache_entries, name_cache_entries + json->name_cache.length); } static void JSON_free(void *ptr) diff --git a/test/json/json_ext_parser_test.rb b/test/json/json_ext_parser_test.rb index ff6598f490..9db8ae772f 100644 --- a/test/json/json_ext_parser_test.rb +++ b/test/json/json_ext_parser_test.rb @@ -27,6 +27,26 @@ class JSONExtParserTest < Test::Unit::TestCase assert_equal "unexpected token at 'NaN'", ex.message end + if GC.respond_to?(:stress=) + def test_gc_stress_parser_new + payload = JSON.dump([{ foo: 1, bar: 2, baz: 3, egg: { spam: 4 } }] * 10) + + previous_stress = GC.stress + JSON::Parser.new(payload).parse + ensure + GC.stress = previous_stress + end + + def test_gc_stress + payload = JSON.dump([{ foo: 1, bar: 2, baz: 3, egg: { spam: 4 } }] * 10) + + previous_stress = GC.stress + JSON.parse(payload) + ensure + GC.stress = previous_stress + end + end + def parse(json) JSON::Ext::Parser.new(json).parse end diff --git a/test/json/test_helper.rb b/test/json/test_helper.rb index 7bff9b3391..6fcb76edf8 100644 --- a/test/json/test_helper.rb +++ b/test/json/test_helper.rb @@ -19,6 +19,24 @@ begin rescue LoadError end +if GC.respond_to?(:verify_compaction_references) + # This method was added in Ruby 3.0.0. Calling it this way asks the GC to + # move objects around, helping to find object movement bugs. + begin + GC.verify_compaction_references(double_heap: true, toward: :empty) + rescue NotImplementedError + # Some platforms don't support compaction + end +end + +if GC.respond_to?(:auto_compact=) + begin + GC.auto_compact = true + rescue NotImplementedError + # Some platforms don't support compaction + end +end + unless defined?(Test::Unit::CoreAssertions) require "core_assertions" Test::Unit::TestCase.include Test::Unit::CoreAssertions |