Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions ext/json/ext/generator/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"

Expand Down
15 changes: 4 additions & 11 deletions ext/json/ext/generator/generator.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
11 changes: 11 additions & 0 deletions ext/json/ext/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 4 additions & 0 deletions ext/json/ext/parser/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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"])
Expand Down
48 changes: 27 additions & 21 deletions ext/json/ext/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}

Expand All @@ -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)
Expand All @@ -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
}
}

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -1554,20 +1565,22 @@ 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;

VALUE result = json_parse_any(state, config);

// 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;
Expand Down Expand Up @@ -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)
Expand Down