diff options
| author | Jean Boussier <jean.boussier@gmail.com> | 2026-02-06 10:03:12 +0100 |
|---|---|---|
| committer | git <svn-admin@ruby-lang.org> | 2026-02-06 09:23:16 +0000 |
| commit | 6e18331074f188ef79241e3f5155f225da4bd440 (patch) | |
| tree | 8b1d9b19250efcc4449f5b0111109e76e1f01145 /ext | |
| parent | 17caec3cab53f16ab4e338858560519082e5dd48 (diff) | |
[ruby/json] Stop using RB_ALLOCV
While it's a very nice API, if the buffer is too big for the
stack (> 1024B) the buffer object will be mark like a stack region
which is slow and overkill for a char buffer.
https://github.com/ruby/json/commit/4dcbcb84a2
Diffstat (limited to 'ext')
| -rw-r--r-- | ext/json/parser/parser.c | 54 |
1 files changed, 33 insertions, 21 deletions
diff --git a/ext/json/parser/parser.c b/ext/json/parser/parser.c index 93e3b021f1..e4b619b42f 100644 --- a/ext/json/parser/parser.c +++ b/ext/json/parser/parser.c @@ -770,16 +770,36 @@ NOINLINE(static) VALUE json_string_unescape(JSON_ParserState *state, JSON_Parser } #define MAX_FAST_INTEGER_SIZE 18 +#define MAX_NUMBER_STACK_BUFFER 128 + +typedef VALUE (*json_number_decode_func_t)(const char *ptr); + +static inline VALUE json_decode_large_number(const char *start, long len, json_number_decode_func_t func) +{ + if (RB_LIKELY(len < MAX_NUMBER_STACK_BUFFER)) { + char buffer[MAX_NUMBER_STACK_BUFFER]; + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + return func(buffer); + } else { + VALUE buffer_v = rb_str_tmp_new(len); + char *buffer = RSTRING_PTR(buffer_v); + MEMCPY(buffer, start, char, len); + buffer[len] = '\0'; + VALUE number = func(buffer); + RB_GC_GUARD(buffer_v); + return number; + } +} + +static VALUE json_decode_inum(const char *buffer) +{ + return rb_cstr2inum(buffer, 10); +} NOINLINE(static) VALUE json_decode_large_integer(const char *start, long len) { - VALUE buffer_v; - char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); - MEMCPY(buffer, start, char, len); - buffer[len] = '\0'; - VALUE number = rb_cstr2inum(buffer, 10); - RB_ALLOCV_END(buffer_v); - return number; + return json_decode_large_number(start, len, json_decode_inum); } static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, bool negative, const char *start, const char *end) @@ -794,22 +814,14 @@ static inline VALUE json_decode_integer(uint64_t mantissa, int mantissa_digits, return json_decode_large_integer(start, end - start); } -NOINLINE(static) VALUE json_decode_large_float(const char *start, long len) +static VALUE json_decode_dnum(const char *buffer) { - if (RB_LIKELY(len < 64)) { - char buffer[64]; - MEMCPY(buffer, start, char, len); - buffer[len] = '\0'; - return DBL2NUM(rb_cstr_to_dbl(buffer, 1)); - } + return DBL2NUM(rb_cstr_to_dbl(buffer, 1)); +} - VALUE buffer_v; - char *buffer = RB_ALLOCV_N(char, buffer_v, len + 1); - MEMCPY(buffer, start, char, len); - buffer[len] = '\0'; - VALUE number = DBL2NUM(rb_cstr_to_dbl(buffer, 1)); - RB_ALLOCV_END(buffer_v); - return number; +NOINLINE(static) VALUE json_decode_large_float(const char *start, long len) +{ + return json_decode_large_number(start, len, json_decode_dnum); } /* Ruby JSON optimized float decoder using vendored Ryu algorithm |
