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
3 changes: 3 additions & 0 deletions .document
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ lib
# and some of the ext/ directory (which has its own .document file)
ext

# GC is split between gc.rb and gc/default/default.c
gc/default

# For `prism`, ruby code is in lib and c in the prism folder
prism

Expand Down
32 changes: 32 additions & 0 deletions ext/json/json.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,4 +144,36 @@ static inline void *ruby_xrealloc2_sized(void *ptr, size_t new_elems, size_t ele
#define JSON_CPU_LITTLE_ENDIAN_64BITS 0
#endif

#ifdef JSON_TRUFFLERUBY_RB_CATCH_BUG

#undef RB_BLOCK_CALL_FUNC_ARGLIST
#define RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, func_args) VALUE func_args

NORETURN(static inline) void json_rb_throw_obj(VALUE tag, VALUE obj)
{
VALUE exc = rb_exc_new_str(rb_eException, rb_utf8_str_new_cstr("throw_workaround"));
rb_ivar_set(exc, rb_intern("@throw_tag"), tag);
rb_ivar_set(exc, rb_intern("@throw_obj"), obj);
rb_exc_raise(exc);
}
#define rb_throw_obj json_rb_throw_obj

static inline VALUE json_rb_catch_obj(VALUE tag, VALUE (*func)(VALUE args), VALUE func_args)
{
int status;
VALUE result = rb_protect(func, func_args, &status);
if (status) {
VALUE exc = rb_errinfo();
if (tag == rb_ivar_get(exc, rb_intern("@throw_tag"))) {
rb_set_errinfo(Qnil);
return rb_ivar_get(exc, rb_intern("@throw_obj"));
}
rb_jump_tag(status);
}
return result;
}
#define rb_catch_obj json_rb_catch_obj

#endif // JSON_TRUFFLERUBY_RB_CATCH_BUG

#endif // _JSON_H_
7 changes: 6 additions & 1 deletion ext/json/parser/extconf.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,12 @@
require 'mkmf'

$defs << "-DJSON_DEBUG" if ENV.fetch("JSON_DEBUG", "0") != "0"
$defs << "-DJSON_WORKAROUND_RB_CATCH_BUG" if RUBY_ENGINE == 'truffleruby'

if RUBY_ENGINE == 'truffleruby' && RUBY_ENGINE_VERSION < '40.0'
# Ref: https://github.com/truffleruby/truffleruby/issues/4329
# Ref: https://github.com/truffleruby/truffleruby/pull/4333
$defs << "-DJSON_TRUFFLERUBY_RB_CATCH_BUG"
end

have_func("rb_enc_interned_str", "ruby/encoding.h") # RUBY_VERSION >= 3.0
have_func("rb_str_to_interned_str", "ruby.h") # RUBY_VERSION >= 3.0
Expand Down
36 changes: 3 additions & 33 deletions ext/json/parser/parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -672,43 +672,13 @@ static VALUE parse_error_new(JSON_ParserState *state, VALUE message, long line,
return exc;
}

#ifdef JSON_WORKAROUND_RB_CATCH_BUG
#define JSON_CATCH_FUNC_ARGLIST(yielded_arg, func_args) VALUE func_args

NORETURN(static) void parser_throw_eos(VALUE parser)
{
VALUE exc = rb_exc_new_str(eParserError, rb_utf8_str_new_cstr("EOS"));
rb_ivar_set(exc, rb_intern("@resumable_parser_eos"), parser);
rb_exc_raise(exc);
}

static VALUE parser_catch_eos(VALUE parser, VALUE (*func)(VALUE args), VALUE func_args)
{
int status;
VALUE result = rb_protect(func, func_args, &status);
if (status) {
VALUE error_source = rb_ivar_get(rb_errinfo(), rb_intern("@resumable_parser_eos"));
if (error_source == parser) {
rb_set_errinfo(Qnil);
return parser;
}
rb_jump_tag(status);
}
return result;
}
#else
#define JSON_CATCH_FUNC_ARGLIST RB_BLOCK_CALL_FUNC_ARGLIST
#define parser_throw_eos(parser) rb_throw_obj(parser, parser)
#define parser_catch_eos(parser, func, func_args) rb_catch_obj(parser, func, func_args)
#endif

NORETURN(static) void raise_parse_error(const char *format, JSON_ParserState *state, bool eos)
{
if (state->parser) {
if (eos) {
// the error will be swallowed by ResumableParser#parse, so no
// point building a message or backtrace.
parser_throw_eos(state->parser);
rb_throw_obj(state->parser, state->parser);
} else {
// line and columns can't be accurate in resumable
rb_exc_raise(parse_error_new(state, build_parse_error_message(format, state), 0, 0, eos));
Expand Down Expand Up @@ -2450,7 +2420,7 @@ struct json_parse_any_args {
VALUE parser;
};

static VALUE json_parse_any_resumable_safe0(JSON_CATCH_FUNC_ARGLIST(yielded_arg, _args))
static VALUE json_parse_any_resumable_safe0(RB_BLOCK_CALL_FUNC_ARGLIST(yielded_arg, _args))
{
struct json_parse_any_args *args = (struct json_parse_any_args *)_args;
return (VALUE)json_parse_any(args->state, args->config, true);
Expand All @@ -2459,7 +2429,7 @@ static VALUE json_parse_any_resumable_safe0(JSON_CATCH_FUNC_ARGLIST(yielded_arg,
static VALUE json_parse_any_resumable_safe(VALUE _args)
{
struct json_parse_any_args *args = (struct json_parse_any_args *)_args;
VALUE result = parser_catch_eos(args->parser, json_parse_any_resumable_safe0, _args);
VALUE result = rb_catch_obj(args->parser, json_parse_any_resumable_safe0, _args);
return result == args->parser ? Qfalse : result;
}

Expand Down
Loading