summaryrefslogtreecommitdiff
path: root/ext
diff options
context:
space:
mode:
authorJean Boussier <jean.boussier@gmail.com>2026-02-06 10:03:12 +0100
committergit <svn-admin@ruby-lang.org>2026-02-06 09:23:16 +0000
commit6e18331074f188ef79241e3f5155f225da4bd440 (patch)
tree8b1d9b19250efcc4449f5b0111109e76e1f01145 /ext
parent17caec3cab53f16ab4e338858560519082e5dd48 (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.c54
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