summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJean Boussier <[email protected]>2024-10-29 15:03:42 +0100
committerHiroshi SHIBATA <[email protected]>2024-11-01 13:04:24 +0900
commit5dc3b15b3c2c2f2c2cc5f1522f865b56574ae63f (patch)
tree4614a66afbb995bdb4a6b4ded261ae9099b32cf8
parentb042d9d9c1e1d8855e40d27a799eb69781b779cd (diff)
[ruby/json] generator.c: store pretty strings in VALUE
Given we expect these to almost always be null, we might as well keep them in RString. And even when provided, assuming we're passed frozen strings we'll save on copying them. This also reduce the size of the struct from 112B to 72B. https://github.com/ruby/json/commit/6382c231b0
-rw-r--r--ext/json/generator/generator.c159
-rw-r--r--ext/json/generator/generator.h27
2 files changed, 74 insertions, 112 deletions
diff --git a/ext/json/generator/generator.c b/ext/json/generator/generator.c
index fc002ff737..59ecb53563 100644
--- a/ext/json/generator/generator.c
+++ b/ext/json/generator/generator.c
@@ -297,14 +297,6 @@ static void convert_UTF8_to_ASCII_only_JSON(FBuffer *out_buffer, VALUE str, cons
RB_GC_GUARD(str);
}
-static char *fstrndup(const char *ptr, unsigned long len) {
- char *result;
- if (len <= 0) return NULL;
- result = ALLOC_N(char, len);
- memcpy(result, ptr, len);
- return result;
-}
-
/*
* Document-module: JSON::Ext::Generator
*
@@ -587,27 +579,35 @@ static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
return cState_partial_generate(state, string, generate_json_string);
}
+static void State_mark(void *ptr)
+{
+ JSON_Generator_State *state = ptr;
+ rb_gc_mark_movable(state->indent);
+ rb_gc_mark_movable(state->space);
+ rb_gc_mark_movable(state->space_before);
+ rb_gc_mark_movable(state->object_nl);
+ rb_gc_mark_movable(state->array_nl);
+}
+
+static void State_compact(void *ptr)
+{
+ JSON_Generator_State *state = ptr;
+ state->indent = rb_gc_location(state->indent);
+ state->space = rb_gc_location(state->space);
+ state->space_before = rb_gc_location(state->space_before);
+ state->object_nl = rb_gc_location(state->object_nl);
+ state->array_nl = rb_gc_location(state->array_nl);
+}
+
static void State_free(void *ptr)
{
JSON_Generator_State *state = ptr;
- if (state->indent) ruby_xfree(state->indent);
- if (state->space) ruby_xfree(state->space);
- if (state->space_before) ruby_xfree(state->space_before);
- if (state->object_nl) ruby_xfree(state->object_nl);
- if (state->array_nl) ruby_xfree(state->array_nl);
ruby_xfree(state);
}
static size_t State_memsize(const void *ptr)
{
- const JSON_Generator_State *state = ptr;
- size_t size = sizeof(*state);
- if (state->indent) size += state->indent_len + 1;
- if (state->space) size += state->space_len + 1;
- if (state->space_before) size += state->space_before_len + 1;
- if (state->object_nl) size += state->object_nl_len + 1;
- if (state->array_nl) size += state->array_nl_len + 1;
- return size;
+ return sizeof(JSON_Generator_State);
}
#ifndef HAVE_RB_EXT_RACTOR_SAFE
@@ -617,7 +617,12 @@ static size_t State_memsize(const void *ptr)
static const rb_data_type_t JSON_Generator_State_type = {
"JSON/Generator/State",
- {NULL, State_free, State_memsize,},
+ {
+ .dmark = State_mark,
+ .dfree = State_free,
+ .dsize = State_memsize,
+ .dcompact = State_compact,
+ },
0, 0,
RUBY_TYPED_WB_PROTECTED | RUBY_TYPED_FREE_IMMEDIATELY | RUBY_TYPED_FROZEN_SHAREABLE,
};
@@ -651,11 +656,11 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
if (arg->iter > 0) fbuffer_append_char(buffer, ',');
if (RB_UNLIKELY(state->object_nl)) {
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
+ fbuffer_append_str(buffer, state->object_nl);
}
if (RB_UNLIKELY(state->indent)) {
for (j = 0; j < depth; j++) {
- fbuffer_append(buffer, state->indent, state->indent_len);
+ fbuffer_append_str(buffer, state->indent);
}
}
@@ -673,9 +678,9 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
}
generate_json_string(buffer, Vstate, state, key_to_s);
- if (RB_UNLIKELY(state->space_before)) fbuffer_append(buffer, state->space_before, state->space_before_len);
+ if (RB_UNLIKELY(state->space_before)) fbuffer_append_str(buffer, state->space_before);
fbuffer_append_char(buffer, ':');
- if (RB_UNLIKELY(state->space)) fbuffer_append(buffer, state->space, state->space_len);
+ if (RB_UNLIKELY(state->space)) fbuffer_append_str(buffer, state->space);
generate_json(buffer, Vstate, state, val);
arg->iter++;
@@ -709,10 +714,10 @@ static void generate_json_object(FBuffer *buffer, VALUE Vstate, JSON_Generator_S
depth = --state->depth;
if (RB_UNLIKELY(state->object_nl)) {
- fbuffer_append(buffer, state->object_nl, state->object_nl_len);
+ fbuffer_append_str(buffer, state->object_nl);
if (RB_UNLIKELY(state->indent)) {
for (j = 0; j < depth; j++) {
- fbuffer_append(buffer, state->indent, state->indent_len);
+ fbuffer_append_str(buffer, state->indent);
}
}
}
@@ -735,25 +740,25 @@ static void generate_json_array(FBuffer *buffer, VALUE Vstate, JSON_Generator_St
}
fbuffer_append_char(buffer, '[');
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
+ if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
for(i = 0; i < RARRAY_LEN(obj); i++) {
if (i > 0) {
fbuffer_append_char(buffer, ',');
- if (RB_UNLIKELY(state->array_nl)) fbuffer_append(buffer, state->array_nl, state->array_nl_len);
+ if (RB_UNLIKELY(state->array_nl)) fbuffer_append_str(buffer, state->array_nl);
}
if (RB_UNLIKELY(state->indent)) {
for (j = 0; j < depth; j++) {
- fbuffer_append(buffer, state->indent, state->indent_len);
+ fbuffer_append_str(buffer, state->indent);
}
}
generate_json(buffer, Vstate, state, RARRAY_AREF(obj, i));
}
state->depth = --depth;
if (RB_UNLIKELY(state->array_nl)) {
- fbuffer_append(buffer, state->array_nl, state->array_nl_len);
+ fbuffer_append_str(buffer, state->array_nl);
if (RB_UNLIKELY(state->indent)) {
for (j = 0; j < depth; j++) {
- fbuffer_append(buffer, state->indent, state->indent_len);
+ fbuffer_append_str(buffer, state->indent);
}
}
}
@@ -1007,11 +1012,11 @@ static VALUE cState_init_copy(VALUE obj, VALUE orig)
if (!objState) rb_raise(rb_eArgError, "unallocated JSON::State");
MEMCPY(objState, origState, JSON_Generator_State, 1);
- objState->indent = fstrndup(origState->indent, origState->indent_len);
- objState->space = fstrndup(origState->space, origState->space_len);
- objState->space_before = fstrndup(origState->space_before, origState->space_before_len);
- objState->object_nl = fstrndup(origState->object_nl, origState->object_nl_len);
- objState->array_nl = fstrndup(origState->array_nl, origState->array_nl_len);
+ objState->indent = origState->indent;
+ objState->space = origState->space;
+ objState->space_before = origState->space_before;
+ objState->object_nl = origState->object_nl;
+ objState->array_nl = origState->array_nl;
return obj;
}
@@ -1041,7 +1046,7 @@ static VALUE cState_from_state_s(VALUE self, VALUE opts)
static VALUE cState_indent(VALUE self)
{
GET_STATE(self);
- return state->indent ? rb_str_new(state->indent, state->indent_len) : rb_str_new2("");
+ return state->indent ? state->indent : rb_str_freeze(rb_utf8_str_new("", 0));
}
/*
@@ -1051,20 +1056,12 @@ static VALUE cState_indent(VALUE self)
*/
static VALUE cState_indent_set(VALUE self, VALUE indent)
{
- unsigned long len;
GET_STATE(self);
Check_Type(indent, T_STRING);
- len = RSTRING_LEN(indent);
- if (len == 0) {
- if (state->indent) {
- ruby_xfree(state->indent);
- state->indent = NULL;
- state->indent_len = 0;
- }
+ if (RSTRING_LEN(indent)) {
+ state->indent = RB_OBJ_FROZEN(indent) ? indent : rb_str_freeze(rb_str_dup(indent));
} else {
- if (state->indent) ruby_xfree(state->indent);
- state->indent = fstrndup(RSTRING_PTR(indent), len);
- state->indent_len = len;
+ state->indent = Qfalse;
}
return Qnil;
}
@@ -1078,7 +1075,7 @@ static VALUE cState_indent_set(VALUE self, VALUE indent)
static VALUE cState_space(VALUE self)
{
GET_STATE(self);
- return state->space ? rb_str_new(state->space, state->space_len) : rb_str_new2("");
+ return state->space ? state->space : rb_str_freeze(rb_utf8_str_new("", 0));
}
/*
@@ -1089,20 +1086,12 @@ static VALUE cState_space(VALUE self)
*/
static VALUE cState_space_set(VALUE self, VALUE space)
{
- unsigned long len;
GET_STATE(self);
Check_Type(space, T_STRING);
- len = RSTRING_LEN(space);
- if (len == 0) {
- if (state->space) {
- ruby_xfree(state->space);
- state->space = NULL;
- state->space_len = 0;
- }
+ if (RSTRING_LEN(space)) {
+ state->space = RB_OBJ_FROZEN(space) ? space : rb_str_freeze(rb_str_dup(space));
} else {
- if (state->space) ruby_xfree(state->space);
- state->space = fstrndup(RSTRING_PTR(space), len);
- state->space_len = len;
+ state->space = Qfalse;
}
return Qnil;
}
@@ -1115,7 +1104,7 @@ static VALUE cState_space_set(VALUE self, VALUE space)
static VALUE cState_space_before(VALUE self)
{
GET_STATE(self);
- return state->space_before ? rb_str_new(state->space_before, state->space_before_len) : rb_str_new2("");
+ return state->space_before ? state->space_before : rb_str_freeze(rb_utf8_str_new("", 0));
}
/*
@@ -1125,20 +1114,12 @@ static VALUE cState_space_before(VALUE self)
*/
static VALUE cState_space_before_set(VALUE self, VALUE space_before)
{
- unsigned long len;
GET_STATE(self);
Check_Type(space_before, T_STRING);
- len = RSTRING_LEN(space_before);
- if (len == 0) {
- if (state->space_before) {
- ruby_xfree(state->space_before);
- state->space_before = NULL;
- state->space_before_len = 0;
- }
+ if (RSTRING_LEN(space_before)) {
+ state->space_before = RB_OBJ_FROZEN(space_before) ? space_before : rb_str_freeze(rb_str_dup(space_before));
} else {
- if (state->space_before) ruby_xfree(state->space_before);
- state->space_before = fstrndup(RSTRING_PTR(space_before), len);
- state->space_before_len = len;
+ state->space_before = Qfalse;
}
return Qnil;
}
@@ -1152,7 +1133,7 @@ static VALUE cState_space_before_set(VALUE self, VALUE space_before)
static VALUE cState_object_nl(VALUE self)
{
GET_STATE(self);
- return state->object_nl ? rb_str_new(state->object_nl, state->object_nl_len) : rb_str_new2("");
+ return state->object_nl ? state->object_nl : rb_str_freeze(rb_utf8_str_new("", 0));
}
/*
@@ -1163,19 +1144,12 @@ static VALUE cState_object_nl(VALUE self)
*/
static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
{
- unsigned long len;
GET_STATE(self);
Check_Type(object_nl, T_STRING);
- len = RSTRING_LEN(object_nl);
- if (len == 0) {
- if (state->object_nl) {
- ruby_xfree(state->object_nl);
- state->object_nl = NULL;
- }
+ if (RSTRING_LEN(object_nl)) {
+ state->object_nl = RB_OBJ_FROZEN(object_nl) ? object_nl : rb_str_freeze(rb_str_dup(object_nl));
} else {
- if (state->object_nl) ruby_xfree(state->object_nl);
- state->object_nl = fstrndup(RSTRING_PTR(object_nl), len);
- state->object_nl_len = len;
+ state->object_nl = Qfalse;
}
return Qnil;
}
@@ -1188,7 +1162,7 @@ static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
static VALUE cState_array_nl(VALUE self)
{
GET_STATE(self);
- return state->array_nl ? rb_str_new(state->array_nl, state->array_nl_len) : rb_str_new2("");
+ return state->array_nl ? state->array_nl : rb_str_freeze(rb_utf8_str_new("", 0));
}
/*
@@ -1198,19 +1172,12 @@ static VALUE cState_array_nl(VALUE self)
*/
static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
{
- unsigned long len;
GET_STATE(self);
Check_Type(array_nl, T_STRING);
- len = RSTRING_LEN(array_nl);
- if (len == 0) {
- if (state->array_nl) {
- ruby_xfree(state->array_nl);
- state->array_nl = NULL;
- }
+ if (RSTRING_LEN(array_nl)) {
+ state->array_nl = RB_OBJ_FROZEN(array_nl) ? array_nl : rb_str_freeze(rb_str_dup(array_nl));
} else {
- if (state->array_nl) ruby_xfree(state->array_nl);
- state->array_nl = fstrndup(RSTRING_PTR(array_nl), len);
- state->array_nl_len = len;
+ state->array_nl = Qfalse;
}
return Qnil;
}
diff --git a/ext/json/generator/generator.h b/ext/json/generator/generator.h
index b6898c955f..e74af24a24 100644
--- a/ext/json/generator/generator.h
+++ b/ext/json/generator/generator.h
@@ -23,28 +23,23 @@ typedef unsigned char _Bool;
#endif
#endif
-static char *fstrndup(const char *ptr, unsigned long len);
-
/* ruby api and some helpers */
typedef struct JSON_Generator_StateStruct {
- char *indent;
- long indent_len;
- char *space;
- long space_len;
- char *space_before;
- long space_before_len;
- char *object_nl;
- long object_nl_len;
- char *array_nl;
- long array_nl_len;
+ VALUE indent;
+ VALUE space;
+ VALUE space_before;
+ VALUE object_nl;
+ VALUE array_nl;
+
long max_nesting;
- char allow_nan;
- char ascii_only;
- char script_safe;
- char strict;
long depth;
long buffer_initial_length;
+
+ bool allow_nan;
+ bool ascii_only;
+ bool script_safe;
+ bool strict;
} JSON_Generator_State;
#define GET_STATE_TO(self, state) \