Skip to content

Commit ea0de13

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 ea0de13

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: 13 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
@@ -102,4 +113,6 @@ typedef unsigned char _Bool;
102113
#define JSON_CPU_LITTLE_ENDIAN_64BITS 0
103114
#endif
104115

116+
117+
105118
#endif // _JSON_H_

ext/json/ext/parser/extconf.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
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
9+
have_const("RUBY_TYPED_EMBEDDABLE", "ruby.h") # RUBY_VERSION >= 3.3
910

1011
append_cflags("-std=c99")
1112

ext/json/ext/parser/parser.c

Lines changed: 28 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)
@@ -281,6 +288,7 @@ static rvalue_stack *rvalue_stack_spill(rvalue_stack *old_stack, VALUE *handle,
281288

282289
stack->capa = old_stack->capa << 1;
283290
stack->ptr = ALLOC_N(VALUE, stack->capa);
291+
284292
stack->type = RVALUE_STACK_HEAP_ALLOCATED;
285293
MEMCPY(stack->ptr, old_stack->ptr, VALUE, old_stack->head);
286294
return stack;
@@ -291,8 +299,12 @@ static void rvalue_stack_eagerly_release(VALUE handle)
291299
if (handle) {
292300
rvalue_stack *stack;
293301
TypedData_Get_Struct(handle, rvalue_stack, &JSON_Parser_rvalue_stack_type, stack);
294-
RTYPEDDATA_DATA(handle) = NULL;
302+
#ifdef HAVE_RUBY_TYPED_EMBEDDABLE
303+
rvalue_stack_free_buffer(stack);
304+
#else
295305
rvalue_stack_free(stack);
306+
RTYPEDDATA_DATA(handle) = NULL;
307+
#endif
296308
}
297309
}
298310

@@ -343,7 +355,7 @@ typedef struct JSON_ParserStruct {
343355
} JSON_ParserConfig;
344356

345357
typedef struct JSON_ParserStateStruct {
346-
VALUE stack_handle;
358+
VALUE *stack_handle;
347359
const char *start;
348360
const char *cursor;
349361
const char *end;
@@ -944,7 +956,7 @@ static inline VALUE json_push_value(JSON_ParserState *state, JSON_ParserConfig *
944956
if (RB_UNLIKELY(config->on_load_proc)) {
945957
value = rb_proc_call_with_block(config->on_load_proc, 1, &value, Qnil);
946958
}
947-
rvalue_stack_push(state->stack, value, &state->stack_handle, &state->stack);
959+
rvalue_stack_push(state->stack, value, state->stack_handle, &state->stack);
948960
return value;
949961
}
950962

@@ -1554,20 +1566,22 @@ static VALUE cParser_parse(JSON_ParserConfig *config, VALUE Vsource)
15541566
const char *start;
15551567
RSTRING_GETMEM(Vsource, start, len);
15561568

1569+
VALUE stack_handle = 0;
15571570
JSON_ParserState _state = {
15581571
.start = start,
15591572
.cursor = start,
15601573
.end = start + len,
15611574
.stack = &stack,
1575+
.stack_handle = &stack_handle,
15621576
};
15631577
JSON_ParserState *state = &_state;
15641578

15651579
VALUE result = json_parse_any(state, config);
15661580

15671581
// This may be skipped in case of exception, but
15681582
// it won't cause a leak.
1569-
rvalue_stack_eagerly_release(state->stack_handle);
1570-
1583+
rvalue_stack_eagerly_release(stack_handle);
1584+
RB_GC_GUARD(stack_handle);
15711585
json_ensure_eof(state);
15721586

15731587
return result;
@@ -1605,26 +1619,19 @@ static void JSON_ParserConfig_mark(void *ptr)
16051619
rb_gc_mark(config->decimal_class);
16061620
}
16071621

1608-
static void JSON_ParserConfig_free(void *ptr)
1609-
{
1610-
JSON_ParserConfig *config = ptr;
1611-
ruby_xfree(config);
1612-
}
1613-
16141622
static size_t JSON_ParserConfig_memsize(const void *ptr)
16151623
{
16161624
return sizeof(JSON_ParserConfig);
16171625
}
16181626

16191627
static const rb_data_type_t JSON_ParserConfig_type = {
1620-
"JSON::Ext::Parser/ParserConfig",
1621-
{
1628+
.wrap_struct_name = "JSON::Ext::Parser/ParserConfig",
1629+
.function = {
16221630
JSON_ParserConfig_mark,
1623-
JSON_ParserConfig_free,
1631+
RUBY_DEFAULT_FREE,
16241632
JSON_ParserConfig_memsize,
16251633
},
1626-
0, 0,
1627-
RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE,
1634+
.flags = RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FROZEN_SHAREABLE | RUBY_TYPED_EMBEDDABLE,
16281635
};
16291636

16301637
static VALUE cJSON_parser_s_allocate(VALUE klass)

0 commit comments

Comments
 (0)