Skip to content

Commit 101f734

Browse files
committed
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
1 parent 9aff85e commit 101f734

File tree

5 files changed

+48
-32
lines changed

5 files changed

+48
-32
lines changed

ext/json/ext/generator/extconf.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,8 @@
55
File.write('Makefile', dummy_makefile("").join)
66
else
77
append_cflags("-std=c99")
8+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
9+
810
$defs << "-DJSON_GENERATOR"
911
$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
1012

ext/json/ext/generator/generator.c

Lines changed: 4 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -722,27 +722,20 @@ static void State_compact(void *ptr)
722722
state->as_json = rb_gc_location(state->as_json);
723723
}
724724

725-
static void State_free(void *ptr)
726-
{
727-
JSON_Generator_State *state = ptr;
728-
ruby_xfree(state);
729-
}
730-
731725
static size_t State_memsize(const void *ptr)
732726
{
733727
return sizeof(JSON_Generator_State);
734728
}
735729

736730
static const rb_data_type_t JSON_Generator_State_type = {
737-
"JSON/Generator/State",
738-
{
731+
.wrap_struct_name = "JSON/Generator/State",
732+
.function = {
739733
.dmark = State_mark,
740-
.dfree = State_free,
734+
.dfree = RUBY_DEFAULT_FREE,
741735
.dsize = State_memsize,
742736
.dcompact = State_compact,
743737
},
744-
0, 0,
745-
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
738+
.flags = RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
746739
};
747740

748741
static void state_init(JSON_Generator_State *state)

ext/json/ext/json.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,17 @@ typedef unsigned char _Bool;
5454
# define RUBY_TYPED_FROZEN_SHAREABLE 0
5555
#endif
5656

57+
#ifdef RUBY_TYPED_EMBEDDABLE
58+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
59+
#else
60+
# ifdef HAVE_CONST_RUBY_TYPED_EMBEDDABLE
61+
# define RUBY_TYPED_EMBEDDABLE RUBY_TYPED_EMBEDDABLE
62+
# define HAVE_RUBY_TYPED_EMBEDDABLE 1
63+
# else
64+
# define RUBY_TYPED_EMBEDDABLE 0
65+
# endif
66+
#endif
67+
5768
#ifndef NORETURN
5869
#if defined(__has_attribute) && __has_attribute(noreturn)
5970
#define NORETURN(x) __attribute__((noreturn)) x

ext/json/ext/parser/extconf.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,10 @@
77
have_func("rb_hash_new_capa", "ruby.h") # RUBY_VERSION >= 3.2
88
have_func("rb_hash_bulk_insert", "ruby.h") # Missing on TruffleRuby
99

10+
if RUBY_ENGINE == "ruby"
11+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
12+
end
13+
1014
append_cflags("-std=c99")
1115

1216
if enable_config('parser-use-simd', default=!ENV["JSON_DISABLE_SIMD"])

ext/json/ext/parser/parser.c

Lines changed: 27 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -246,12 +246,20 @@ static void rvalue_stack_mark(void *ptr)
246246
}
247247
}
248248

249+
static void rvalue_stack_free_buffer(rvalue_stack *stack)
250+
{
251+
ruby_xfree(stack->ptr);
252+
stack->ptr = NULL;
253+
}
254+
249255
static void rvalue_stack_free(void *ptr)
250256
{
251257
rvalue_stack *stack = (rvalue_stack *)ptr;
252258
if (stack) {
253-
ruby_xfree(stack->ptr);
259+
rvalue_stack_free_buffer(stack);
260+
#ifndef HAVE_RUBY_TYPED_EMBEDDABLE
254261
ruby_xfree(stack);
262+
#endif
255263
}
256264
}
257265

@@ -262,14 +270,13 @@ static size_t rvalue_stack_memsize(const void *ptr)
262270
}
263271

264272
static const rb_data_type_t JSON_Parser_rvalue_stack_type = {
265-
"JSON::Ext::Parser/rvalue_stack",
266-
{
273+
.wrap_struct_name = "JSON::Ext::Parser/rvalue_stack",
274+
.function = {
267275
.dmark = rvalue_stack_mark,
268276
.dfree = rvalue_stack_free,
269277
.dsize = rvalue_stack_memsize,
270278
},
271-
0, 0,
272-
RUBY_TYPED_FREE_IMMEDIATELY,
279+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_EMBEDDABLE,
273280
};
274281

275282
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)
291298
if (handle) {
292299
rvalue_stack *stack;
293300
TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
294-
RTYPEDDATA_DATA(handle) = NULL;
301+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
302+
rvalue_stack_free_buffer(stack);
303+
#else
295304
rvalue_stack_free(stack);
305+
RTYPEDDATA_DATA(handle) = NULL;
306+
#endif
296307
}
297308
}
298309

@@ -343,7 +354,7 @@ typedef struct JSON_ParserStruct {
343354
} JSON_ParserConfig;
344355

345356
typedef struct JSON_ParserStateStruct {
346-
VALUE stack_handle;
357+
VALUE *stack_handle;
347358
const char *start;
348359
const char *cursor;
349360
const char *end;
@@ -944,7 +955,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
944955
if (RB_UNLIKELY(config->on_load_proc)) {
945956
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
946957
}
947-
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
958+
rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack);
948959
return value;
949960
}
950961

@@ -1554,20 +1565,22 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
15541565
const char *start;
15551566
RSTRING_GETMEM(Vsource, start, len);
15561567

1568+
VALUE stack_handle = 0;
15571569
JSON_ParserState _state = {
15581570
.start = start,
15591571
.cursor = start,
15601572
.end = start + len,
15611573
.stack = &stack,
1574+
.stack_handle = &stack_handle,
15621575
};
15631576
JSON_ParserState *state = &_state;
15641577

15651578
VALUE result = json_parse_any(state, config);
15661579

15671580
// This may be skipped in case of exception, but
15681581
// it won't cause a leak.
1569-
rvalue_stack_eagerly_release(state->stack_handle);
1570-
1582+
rvalue_stack_eagerly_release(stack_handle);
1583+
RB_GC_GUARD(stack_handle);
15711584
json_ensure_eof(state);
15721585

15731586
return result;
@@ -1605,26 +1618,19 @@ static void JSON_ParserConfig_mark(void *ptr)
16051618
rb_gc_mark(config->decimal_class);
16061619
}
16071620

1608-
static void JSON_ParserConfig_free(void *ptr)
1609-
{
1610-
JSON_ParserConfig *config = ptr;
1611-
ruby_xfree(config);
1612-
}
1613-
16141621
static size_t JSON_ParserConfig_memsize(const void *ptr)
16151622
{
16161623
return sizeof(JSON_ParserConfig);
16171624
}
16181625

16191626
static const rb_data_type_t JSON_ParserConfig_type = {
1620-
"JSON::Ext::Parser/ParserConfig",
1621-
{
1627+
.wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
1628+
.function = {
16221629
JSON_ParserConfig_mark,
1623-
JSON_ParserConfig_free,
1630+
RUBY_DEFAULT_FREE,
16241631
JSON_ParserConfig_memsize,
16251632
},
1626-
0, 0,
1627-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
1633+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
16281634
};
16291635

16301636
static VALUE cJSON_parser_s_allocate(VALUE klass)

0 commit comments

Comments
 (0)