From 14ecf12049d814ab65da1d68bd23523e216716e7 Mon Sep 17 00:00:00 2001 From: Jean Boussier Date: Mon, 23 Mar 2026 21:28:22 +0100 Subject: [PATCH] Use embeddable types Ref: https://bugs.ruby-lang.org/issues/21853 Introduced in Ruby 3.3, will officially be public API in 4.1, but can be used sooner by checking the existence of RUBY_TYPED_EMBEDDABLE --- ext/json/ext/generator/extconf.rb | 2 ++ ext/json/ext/generator/generator.c | 15 ++++----------- ext/json/ext/json.h | 6 ++++++ ext/json/ext/parser/extconf.rb | 1 + ext/json/ext/parser/parser.c | 18 ++++++++++-------- 5 files changed, 23 insertions(+), 19 deletions(-) diff --git a/ext/json/ext/generator/extconf.rb b/ext/json/ext/generator/extconf.rb index ee1bbeab..07ca69d2 100644 --- a/ext/json/ext/generator/extconf.rb +++ b/ext/json/ext/generator/extconf.rb @@ -5,6 +5,8 @@ File.write('Makefile', dummy_makefile("").join) else append_cflags("-std=c99") + have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3 + $defs << "-DJSON_GENERATOR" $defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0" diff --git a/ext/json/ext/generator/generator.c b/ext/json/ext/generator/generator.c index a6302691..b52bc975 100644 --- a/ext/json/ext/generator/generator.c +++ b/ext/json/ext/generator/generator.c @@ -722,27 +722,20 @@ static void State_compact(void *ptr) state->as_json = rb_gc_location(state->as_json); } -static void State_free(void *ptr) -{ - JSON_Generator_State *state = ptr; - ruby_xfree(state); -} - static size_t State_memsize(const void *ptr) { return sizeof(JSON_Generator_State); } static const rb_data_type_t JSON_Generator_State_type = { - "JSON/Generator/State", - { + .wrap_struct_name = "JSON/Generator/State", + .function = { .dmark = State_mark, - .dfree = State_free, + .dfree = RUBY_DEFAULT_FREE, .dsize = State_memsize, .dcompact = State_compact, }, - 0, 0, - RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE, + .flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE, }; static void state_init(JSON_Generator_State *state) diff --git a/ext/json/ext/json.h b/ext/json/ext/json.h index 087a2eae..cad8788e 100644 --- a/ext/json/ext/json.h +++ b/ext/json/ext/json.h @@ -54,6 +54,10 @@ typedef unsigned char _Bool; # define RUBY_TYPED_FROZEN_SHAREABLE 0 #endif +#ifndef HAVE_RUBY_TYPED_EMBEDDABLE +# define RUBY_TYPED_EMBEDDABLE 0 +#endif + #ifndef NORETURN #if defined(__has_attribute) && __has_attribute(noreturn) #define NORETURN(x) __attribute__((noreturn)) x @@ -102,4 +106,6 @@ typedef unsigned char _Bool; #define JSON_CPU_LITTLE_ENDIAN_64BITS 0 #endif + + #endif // _JSON_H_ diff --git a/ext/json/ext/parser/extconf.rb b/ext/json/ext/parser/extconf.rb index 2440e66d..a9509e6b 100644 --- a/ext/json/ext/parser/extconf.rb +++ b/ext/json/ext/parser/extconf.rb @@ -6,6 +6,7 @@ have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0 have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2 have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby +have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3 append_cflags("-std=c99") diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 1a8e2aaf..bab75ab5 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -251,7 +251,9 @@ static void rvalue_stack_free(void *ptr) rvalue_stack *stack = (rvalue_stack *)ptr; if (stack) { ruby_xfree(stack->ptr); +#ifndef HAVE_RUBY_TYPED_EMBEDDABLE ruby_xfree(stack); +#endif } } @@ -262,14 +264,13 @@ static size_t rvalue_stack_memsize(const void *ptr) } static const rb_data_type_t JSON_Parser_rvalue_stack_type = { - "JSON::Ext::Parser/rvalue_stack", - { + .wrap_struct_name = "JSON::Ext::Parser/rvalue_stack", + .function = { .dmark = rvalue_stack_mark, .dfree = rvalue_stack_free, .dsize = rvalue_stack_memsize, }, - 0, 0, - RUBY_TYPED_FREE_IMMEDIATELY, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE, }; static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle, rvalue_stack **stack_ref) @@ -1608,7 +1609,9 @@ static void JSON_ParserConfig_mark(void *ptr) static void JSON_ParserConfig_free(void *ptr) { JSON_ParserConfig *config = ptr; +#ifndef HAVE_RUBY_TYPED_EMBEDDABLE ruby_xfree(config); +#endif } static size_t JSON_ParserConfig_memsize(const void *ptr) @@ -1617,14 +1620,13 @@ static size_t JSON_ParserConfig_memsize(const void *ptr) } static const rb_data_type_t JSON_ParserConfig_type = { - "JSON::Ext::Parser/ParserConfig", - { + .wrap_struct_name = "JSON::Ext::Parser/ParserConfig", + .function = { JSON_ParserConfig_mark, JSON_ParserConfig_free, JSON_ParserConfig_memsize, }, - 0, 0, - RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE, + .flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE, }; static VALUE cJSON_parser_s_allocate(VALUE klass)