diff --git a/ext/json/ext/generator/extconf.rb b/ext/json/ext/generator/extconf.rb index ee1bbeab..205a887e 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..8737989a 100644 --- a/ext/json/ext/json.h +++ b/ext/json/ext/json.h @@ -54,6 +54,17 @@ typedef unsigned char _Bool; # define RUBY_TYPED_FROZEN_SHAREABLE 0 #endif +#ifdef RUBY_TYPED_EMBEDDABLE +# define HAVE_RUBY_TYPED_EMBEDDABLE 1 +#else +# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE +# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE +# define HAVE_RUBY_TYPED_EMBEDDABLE 1 +# else +# define RUBY_TYPED_EMBEDDABLE 0 +# endif +#endif + #ifndef NORETURN #if defined(__has_attribute) && __has_attribute(noreturn) #define NORETURN(x) __attribute__((noreturn)) x diff --git a/ext/json/ext/parser/extconf.rb b/ext/json/ext/parser/extconf.rb index 2440e66d..f12fc2dd 100644 --- a/ext/json/ext/parser/extconf.rb +++ b/ext/json/ext/parser/extconf.rb @@ -7,6 +7,10 @@ have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2 have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby +if RUBY_ENGINE == "ruby" + have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3 +end + append_cflags("-std=c99") if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"]) diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 1a8e2aaf..361db3a9 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -246,12 +246,20 @@ static void rvalue_stack_mark(void *ptr) } } +static void rvalue_stack_free_buffer(rvalue_stack *stack) +{ + ruby_xfree(stack->ptr); + stack->ptr = NULL; +} + static void rvalue_stack_free(void *ptr) { rvalue_stack *stack = (rvalue_stack *)ptr; if (stack) { - ruby_xfree(stack->ptr); + rvalue_stack_free_buffer(stack); +#ifndef HAVE_RUBY_TYPED_EMBEDDABLE ruby_xfree(stack); +#endif } } @@ -262,14 +270,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) @@ -291,8 +298,12 @@ static void rvalue_stack_eagerly_release(VALUE handle) if (handle) { rvalue_stack *stack; TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack); - RTYPEDDATA_DATA(handle) = NULL; +#ifdef HAVE_RUBY_TYPED_EMBEDDABLE + rvalue_stack_free_buffer(stack); +#else rvalue_stack_free(stack); + RTYPEDDATA_DATA(handle) = NULL; +#endif } } @@ -343,7 +354,7 @@ typedef struct JSON_ParserStruct { } JSON_ParserConfig; typedef struct JSON_ParserStateStruct { - VALUE stack_handle; + VALUE *stack_handle; const char *start; const char *cursor; const char *end; @@ -944,7 +955,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig * if (RB_UNLIKELY(config->on_load_proc)) { value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil); } - rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack); + rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack); return value; } @@ -1554,11 +1565,13 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource) const char *start; RSTRING_GETMEM(Vsource, start, len); + VALUE stack_handle = 0; JSON_ParserState _state = { .start = start, .cursor = start, .end = start + len, .stack = &stack, + .stack_handle = &stack_handle, }; JSON_ParserState *state = &_state; @@ -1566,8 +1579,8 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource) // This may be skipped in case of exception, but // it won't cause a leak. - rvalue_stack_eagerly_release(state->stack_handle); - + rvalue_stack_eagerly_release(stack_handle); + RB_GC_GUARD(stack_handle); json_ensure_eof(state); return result; @@ -1605,26 +1618,19 @@ static void JSON_ParserConfig_mark(void *ptr) rb_gc_mark(config->decimal_class); } -static void JSON_ParserConfig_free(void *ptr) -{ - JSON_ParserConfig *config = ptr; - ruby_xfree(config); -} - static size_t JSON_ParserConfig_memsize(const void *ptr) { return sizeof(JSON_ParserConfig); } 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, + RUBY_DEFAULT_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)