json 2.16.0 → 2.19.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -38,7 +38,7 @@ typedef struct JSON_Generator_StateStruct {
38
38
 
39
39
  static VALUE mJSON, cState, cFragment, eGeneratorError, eNestingError, Encoding_UTF_8;
40
40
 
41
- static ID i_to_s, i_to_json, i_new, i_pack, i_unpack, i_create_id, i_extend, i_encode;
41
+ static ID i_to_s, i_to_json, i_new, i_encode;
42
42
  static VALUE sym_indent, sym_space, sym_space_before, sym_object_nl, sym_array_nl, sym_max_nesting, sym_allow_nan, sym_allow_duplicate_key,
43
43
  sym_ascii_only, sym_depth, sym_buffer_initial_length, sym_script_safe, sym_escape_slash, sym_strict, sym_as_json;
44
44
 
@@ -60,8 +60,11 @@ struct generate_json_data {
60
60
  JSON_Generator_State *state;
61
61
  VALUE obj;
62
62
  generator_func func;
63
+ long depth;
63
64
  };
64
65
 
66
+ static SIMD_Implementation simd_impl;
67
+
65
68
  static VALUE cState_from_state_s(VALUE self, VALUE opts);
66
69
  static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func, VALUE io);
67
70
  static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
@@ -71,9 +74,6 @@ static void generate_json_string(FBuffer *buffer, struct generate_json_data *dat
71
74
  static void generate_json_null(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
72
75
  static void generate_json_false(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
73
76
  static void generate_json_true(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
74
- #ifdef RUBY_INTEGER_UNIFICATION
75
- static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
76
- #endif
77
77
  static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
78
78
  static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
79
79
  static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj);
@@ -127,7 +127,7 @@ typedef struct _search_state {
127
127
  #endif /* HAVE_SIMD */
128
128
  } search_state;
129
129
 
130
- static ALWAYS_INLINE() void search_flush(search_state *search)
130
+ ALWAYS_INLINE(static) void search_flush(search_state *search)
131
131
  {
132
132
  // Do not remove this conditional without profiling, specifically escape-heavy text.
133
133
  // escape_UTF8_char_basic will advance search->ptr and search->cursor (effectively a search_flush).
@@ -154,8 +154,6 @@ static const unsigned char escape_table_basic[256] = {
154
154
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
155
155
  };
156
156
 
157
- static unsigned char (*search_escape_basic_impl)(search_state *);
158
-
159
157
  static inline unsigned char search_escape_basic(search_state *search)
160
158
  {
161
159
  while (search->ptr < search->end) {
@@ -170,7 +168,7 @@ static inline unsigned char search_escape_basic(search_state *search)
170
168
  return 0;
171
169
  }
172
170
 
173
- static ALWAYS_INLINE() void escape_UTF8_char_basic(search_state *search)
171
+ ALWAYS_INLINE(static) void escape_UTF8_char_basic(search_state *search)
174
172
  {
175
173
  const unsigned char ch = (unsigned char)*search->ptr;
176
174
  switch (ch) {
@@ -211,11 +209,39 @@ static ALWAYS_INLINE() void escape_UTF8_char_basic(search_state *search)
211
209
  * Everything else (should be UTF-8) is just passed through and
212
210
  * appended to the result.
213
211
  */
212
+
213
+
214
+ #if defined(HAVE_SIMD_NEON)
215
+ static inline unsigned char search_escape_basic_neon(search_state *search);
216
+ #elif defined(HAVE_SIMD_SSE2)
217
+ static inline unsigned char search_escape_basic_sse2(search_state *search);
218
+ #endif
219
+
220
+ static inline unsigned char search_escape_basic(search_state *search);
221
+
214
222
  static inline void convert_UTF8_to_JSON(search_state *search)
215
223
  {
216
- while (search_escape_basic_impl(search)) {
224
+ #ifdef HAVE_SIMD
225
+ #if defined(HAVE_SIMD_NEON)
226
+ while (search_escape_basic_neon(search)) {
217
227
  escape_UTF8_char_basic(search);
218
228
  }
229
+ #elif defined(HAVE_SIMD_SSE2)
230
+ if (simd_impl == SIMD_SSE2) {
231
+ while (search_escape_basic_sse2(search)) {
232
+ escape_UTF8_char_basic(search);
233
+ }
234
+ return;
235
+ }
236
+ while (search_escape_basic(search)) {
237
+ escape_UTF8_char_basic(search);
238
+ }
239
+ #endif
240
+ #else
241
+ while (search_escape_basic(search)) {
242
+ escape_UTF8_char_basic(search);
243
+ }
244
+ #endif /* HAVE_SIMD */
219
245
  }
220
246
 
221
247
  static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
@@ -257,8 +283,10 @@ static inline void escape_UTF8_char(search_state *search, unsigned char ch_len)
257
283
 
258
284
  #ifdef HAVE_SIMD
259
285
 
260
- static ALWAYS_INLINE() char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
286
+ ALWAYS_INLINE(static) char *copy_remaining_bytes(search_state *search, unsigned long vec_len, unsigned long len)
261
287
  {
288
+ RBIMPL_ASSERT_OR_ASSUME(len < vec_len);
289
+
262
290
  // Flush the buffer so everything up until the last 'len' characters are unflushed.
263
291
  search_flush(search);
264
292
 
@@ -268,19 +296,25 @@ static ALWAYS_INLINE() char *copy_remaining_bytes(search_state *search, unsigned
268
296
  char *s = (buf->ptr + buf->len);
269
297
 
270
298
  // Pad the buffer with dummy characters that won't need escaping.
271
- // This seem wateful at first sight, but memset of vector length is very fast.
272
- memset(s, 'X', vec_len);
299
+ // This seem wasteful at first sight, but memset of vector length is very fast.
300
+ // This is a space as it can be directly represented as an immediate on AArch64.
301
+ memset(s, ' ', vec_len);
273
302
 
274
303
  // Optimistically copy the remaining 'len' characters to the output FBuffer. If there are no characters
275
304
  // to escape, then everything ends up in the correct spot. Otherwise it was convenient temporary storage.
276
- MEMCPY(s, search->ptr, char, len);
305
+ if (vec_len == 16) {
306
+ RBIMPL_ASSERT_OR_ASSUME(len >= SIMD_MINIMUM_THRESHOLD);
307
+ json_fast_memcpy16(s, search->ptr, len);
308
+ } else {
309
+ MEMCPY(s, search->ptr, char, len);
310
+ }
277
311
 
278
312
  return s;
279
313
  }
280
314
 
281
315
  #ifdef HAVE_SIMD_NEON
282
316
 
283
- static ALWAYS_INLINE() unsigned char neon_next_match(search_state *search)
317
+ ALWAYS_INLINE(static) unsigned char neon_next_match(search_state *search)
284
318
  {
285
319
  uint64_t mask = search->matches_mask;
286
320
  uint32_t index = trailing_zeros64(mask) >> 2;
@@ -394,7 +428,7 @@ static inline unsigned char search_escape_basic_neon(search_state *search)
394
428
 
395
429
  #ifdef HAVE_SIMD_SSE2
396
430
 
397
- static ALWAYS_INLINE() unsigned char sse2_next_match(search_state *search)
431
+ ALWAYS_INLINE(static) unsigned char sse2_next_match(search_state *search)
398
432
  {
399
433
  int mask = search->matches_mask;
400
434
  int index = trailing_zeros(mask);
@@ -418,7 +452,7 @@ static ALWAYS_INLINE() unsigned char sse2_next_match(search_state *search)
418
452
  #define TARGET_SSE2
419
453
  #endif
420
454
 
421
- static TARGET_SSE2 ALWAYS_INLINE() unsigned char search_escape_basic_sse2(search_state *search)
455
+ ALWAYS_INLINE(static) TARGET_SSE2 unsigned char search_escape_basic_sse2(search_state *search)
422
456
  {
423
457
  if (RB_UNLIKELY(search->has_matches)) {
424
458
  // There are more matches if search->matches_mask > 0.
@@ -666,233 +700,6 @@ static void convert_UTF8_to_ASCII_only_JSON(search_state *search, const unsigned
666
700
  }
667
701
  }
668
702
 
669
- /*
670
- * Document-module: JSON::Ext::Generator
671
- *
672
- * This is the JSON generator implemented as a C extension. It can be
673
- * configured to be used by setting
674
- *
675
- * JSON.generator = JSON::Ext::Generator
676
- *
677
- * with the method generator= in JSON.
678
- *
679
- */
680
-
681
- /* Explanation of the following: that's the only way to not pollute
682
- * standard library's docs with GeneratorMethods::<ClassName> which
683
- * are uninformative and take a large place in a list of classes
684
- */
685
-
686
- /*
687
- * Document-module: JSON::Ext::Generator::GeneratorMethods
688
- * :nodoc:
689
- */
690
-
691
- /*
692
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Array
693
- * :nodoc:
694
- */
695
-
696
- /*
697
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Bignum
698
- * :nodoc:
699
- */
700
-
701
- /*
702
- * Document-module: JSON::Ext::Generator::GeneratorMethods::FalseClass
703
- * :nodoc:
704
- */
705
-
706
- /*
707
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Fixnum
708
- * :nodoc:
709
- */
710
-
711
- /*
712
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Float
713
- * :nodoc:
714
- */
715
-
716
- /*
717
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Hash
718
- * :nodoc:
719
- */
720
-
721
- /*
722
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Integer
723
- * :nodoc:
724
- */
725
-
726
- /*
727
- * Document-module: JSON::Ext::Generator::GeneratorMethods::NilClass
728
- * :nodoc:
729
- */
730
-
731
- /*
732
- * Document-module: JSON::Ext::Generator::GeneratorMethods::Object
733
- * :nodoc:
734
- */
735
-
736
- /*
737
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String
738
- * :nodoc:
739
- */
740
-
741
- /*
742
- * Document-module: JSON::Ext::Generator::GeneratorMethods::String::Extend
743
- * :nodoc:
744
- */
745
-
746
- /*
747
- * Document-module: JSON::Ext::Generator::GeneratorMethods::TrueClass
748
- * :nodoc:
749
- */
750
-
751
- /*
752
- * call-seq: to_json(state = nil)
753
- *
754
- * Returns a JSON string containing a JSON object, that is generated from
755
- * this Hash instance.
756
- * _state_ is a JSON::State object, that can also be used to configure the
757
- * produced JSON string output further.
758
- */
759
- static VALUE mHash_to_json(int argc, VALUE *argv, VALUE self)
760
- {
761
- rb_check_arity(argc, 0, 1);
762
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
763
- return cState_partial_generate(Vstate, self, generate_json_object, Qfalse);
764
- }
765
-
766
- /*
767
- * call-seq: to_json(state = nil)
768
- *
769
- * Returns a JSON string containing a JSON array, that is generated from
770
- * this Array instance.
771
- * _state_ is a JSON::State object, that can also be used to configure the
772
- * produced JSON string output further.
773
- */
774
- static VALUE mArray_to_json(int argc, VALUE *argv, VALUE self)
775
- {
776
- rb_check_arity(argc, 0, 1);
777
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
778
- return cState_partial_generate(Vstate, self, generate_json_array, Qfalse);
779
- }
780
-
781
- #ifdef RUBY_INTEGER_UNIFICATION
782
- /*
783
- * call-seq: to_json(*)
784
- *
785
- * Returns a JSON string representation for this Integer number.
786
- */
787
- static VALUE mInteger_to_json(int argc, VALUE *argv, VALUE self)
788
- {
789
- rb_check_arity(argc, 0, 1);
790
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
791
- return cState_partial_generate(Vstate, self, generate_json_integer, Qfalse);
792
- }
793
-
794
- #else
795
- /*
796
- * call-seq: to_json(*)
797
- *
798
- * Returns a JSON string representation for this Integer number.
799
- */
800
- static VALUE mFixnum_to_json(int argc, VALUE *argv, VALUE self)
801
- {
802
- rb_check_arity(argc, 0, 1);
803
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
804
- return cState_partial_generate(Vstate, self, generate_json_fixnum, Qfalse);
805
- }
806
-
807
- /*
808
- * call-seq: to_json(*)
809
- *
810
- * Returns a JSON string representation for this Integer number.
811
- */
812
- static VALUE mBignum_to_json(int argc, VALUE *argv, VALUE self)
813
- {
814
- rb_check_arity(argc, 0, 1);
815
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
816
- return cState_partial_generate(Vstate, self, generate_json_bignum, Qfalse);
817
- }
818
- #endif
819
-
820
- /*
821
- * call-seq: to_json(*)
822
- *
823
- * Returns a JSON string representation for this Float number.
824
- */
825
- static VALUE mFloat_to_json(int argc, VALUE *argv, VALUE self)
826
- {
827
- rb_check_arity(argc, 0, 1);
828
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
829
- return cState_partial_generate(Vstate, self, generate_json_float, Qfalse);
830
- }
831
-
832
- /*
833
- * call-seq: to_json(*)
834
- *
835
- * This string should be encoded with UTF-8 A call to this method
836
- * returns a JSON string encoded with UTF16 big endian characters as
837
- * \u????.
838
- */
839
- static VALUE mString_to_json(int argc, VALUE *argv, VALUE self)
840
- {
841
- rb_check_arity(argc, 0, 1);
842
- VALUE Vstate = cState_from_state_s(cState, argc == 1 ? argv[0] : Qnil);
843
- return cState_partial_generate(Vstate, self, generate_json_string, Qfalse);
844
- }
845
-
846
- /*
847
- * call-seq: to_json(*)
848
- *
849
- * Returns a JSON string for true: 'true'.
850
- */
851
- static VALUE mTrueClass_to_json(int argc, VALUE *argv, VALUE self)
852
- {
853
- rb_check_arity(argc, 0, 1);
854
- return rb_utf8_str_new("true", 4);
855
- }
856
-
857
- /*
858
- * call-seq: to_json(*)
859
- *
860
- * Returns a JSON string for false: 'false'.
861
- */
862
- static VALUE mFalseClass_to_json(int argc, VALUE *argv, VALUE self)
863
- {
864
- rb_check_arity(argc, 0, 1);
865
- return rb_utf8_str_new("false", 5);
866
- }
867
-
868
- /*
869
- * call-seq: to_json(*)
870
- *
871
- * Returns a JSON string for nil: 'null'.
872
- */
873
- static VALUE mNilClass_to_json(int argc, VALUE *argv, VALUE self)
874
- {
875
- rb_check_arity(argc, 0, 1);
876
- return rb_utf8_str_new("null", 4);
877
- }
878
-
879
- /*
880
- * call-seq: to_json(*)
881
- *
882
- * Converts this object to a string (calling #to_s), converts
883
- * it to a JSON string, and returns the result. This is a fallback, if no
884
- * special method #to_json was defined for some object.
885
- */
886
- static VALUE mObject_to_json(int argc, VALUE *argv, VALUE self)
887
- {
888
- VALUE state;
889
- VALUE string = rb_funcall(self, i_to_s, 0);
890
- rb_scan_args(argc, argv, "01", &state);
891
- Check_Type(string, T_STRING);
892
- state = cState_from_state_s(cState, state);
893
- return cState_partial_generate(state, string, generate_json_string, Qfalse);
894
- }
895
-
896
703
  static void State_mark(void *ptr)
897
704
  {
898
705
  JSON_Generator_State *state = ptr;
@@ -926,11 +733,6 @@ static size_t State_memsize(const void *ptr)
926
733
  return sizeof(JSON_Generator_State);
927
734
  }
928
735
 
929
- #ifndef HAVE_RB_EXT_RACTOR_SAFE
930
- # undef RUBY_TYPED_FROZEN_SHAREABLE
931
- # define RUBY_TYPED_FROZEN_SHAREABLE 0
932
- #endif
933
-
934
736
  static const rb_data_type_t JSON_Generator_State_type = {
935
737
  "JSON/Generator/State",
936
738
  {
@@ -972,12 +774,16 @@ static void vstate_spill(struct generate_json_data *data)
972
774
  RB_OBJ_WRITTEN(vstate, Qundef, state->as_json);
973
775
  }
974
776
 
975
- static inline VALUE vstate_get(struct generate_json_data *data)
777
+ static inline VALUE json_call_to_json(struct generate_json_data *data, VALUE obj)
976
778
  {
977
779
  if (RB_UNLIKELY(!data->vstate)) {
978
780
  vstate_spill(data);
979
781
  }
980
- return data->vstate;
782
+ GET_STATE(data->vstate);
783
+ state->depth = data->depth;
784
+ VALUE tmp = rb_funcall(obj, i_to_json, 1, data->vstate);
785
+ // no need to restore state->depth, vstate is just a temporary State
786
+ return tmp;
981
787
  }
982
788
 
983
789
  static VALUE
@@ -1091,6 +897,7 @@ static void raw_generate_json_string(FBuffer *buffer, struct generate_json_data
1091
897
  search.matches_mask = 0;
1092
898
  search.has_matches = false;
1093
899
  search.chunk_base = NULL;
900
+ search.chunk_end = NULL;
1094
901
  #endif /* HAVE_SIMD */
1095
902
 
1096
903
  switch (rb_enc_str_coderange(obj)) {
@@ -1125,8 +932,7 @@ struct hash_foreach_arg {
1125
932
  bool mixed_keys_encountered;
1126
933
  };
1127
934
 
1128
- NOINLINE()
1129
- static void
935
+ NOINLINE(static) void
1130
936
  json_inspect_hash_with_mixed_keys(struct hash_foreach_arg *arg)
1131
937
  {
1132
938
  if (arg->mixed_keys_encountered) {
@@ -1150,7 +956,7 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
1150
956
  FBuffer *buffer = data->buffer;
1151
957
  JSON_Generator_State *state = data->state;
1152
958
 
1153
- long depth = state->depth;
959
+ long depth = data->depth;
1154
960
  int key_type = rb_type(key);
1155
961
 
1156
962
  if (arg->first) {
@@ -1224,9 +1030,9 @@ json_object_i(VALUE key, VALUE val, VALUE _arg)
1224
1030
  static inline long increase_depth(struct generate_json_data *data)
1225
1031
  {
1226
1032
  JSON_Generator_State *state = data->state;
1227
- long depth = ++state->depth;
1033
+ long depth = ++data->depth;
1228
1034
  if (RB_UNLIKELY(depth > state->max_nesting && state->max_nesting)) {
1229
- rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --state->depth);
1035
+ rb_raise(eNestingError, "nesting of %ld is too deep. Did you try to serialize objects with circular references?", --data->depth);
1230
1036
  }
1231
1037
  return depth;
1232
1038
  }
@@ -1237,7 +1043,7 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
1237
1043
 
1238
1044
  if (RHASH_SIZE(obj) == 0) {
1239
1045
  fbuffer_append(buffer, "{}", 2);
1240
- --data->state->depth;
1046
+ --data->depth;
1241
1047
  return;
1242
1048
  }
1243
1049
 
@@ -1250,7 +1056,7 @@ static void generate_json_object(FBuffer *buffer, struct generate_json_data *dat
1250
1056
  };
1251
1057
  rb_hash_foreach(obj, json_object_i, (VALUE)&arg);
1252
1058
 
1253
- depth = --data->state->depth;
1059
+ depth = --data->depth;
1254
1060
  if (RB_UNLIKELY(data->state->object_nl)) {
1255
1061
  fbuffer_append_str(buffer, data->state->object_nl);
1256
1062
  if (RB_UNLIKELY(data->state->indent)) {
@@ -1266,7 +1072,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
1266
1072
 
1267
1073
  if (RARRAY_LEN(obj) == 0) {
1268
1074
  fbuffer_append(buffer, "[]", 2);
1269
- --data->state->depth;
1075
+ --data->depth;
1270
1076
  return;
1271
1077
  }
1272
1078
 
@@ -1282,7 +1088,7 @@ static void generate_json_array(FBuffer *buffer, struct generate_json_data *data
1282
1088
  }
1283
1089
  generate_json(buffer, data, RARRAY_AREF(obj, i));
1284
1090
  }
1285
- data->state->depth = --depth;
1091
+ data->depth = --depth;
1286
1092
  if (RB_UNLIKELY(data->state->array_nl)) {
1287
1093
  fbuffer_append_str(buffer, data->state->array_nl);
1288
1094
  if (RB_UNLIKELY(data->state->indent)) {
@@ -1296,7 +1102,7 @@ static void generate_json_fallback(FBuffer *buffer, struct generate_json_data *d
1296
1102
  {
1297
1103
  VALUE tmp;
1298
1104
  if (rb_respond_to(obj, i_to_json)) {
1299
- tmp = rb_funcall(obj, i_to_json, 1, vstate_get(data));
1105
+ tmp = json_call_to_json(data, obj);
1300
1106
  Check_Type(tmp, T_STRING);
1301
1107
  fbuffer_append_str(buffer, tmp);
1302
1108
  } else {
@@ -1338,18 +1144,8 @@ static void generate_json_fixnum(FBuffer *buffer, struct generate_json_data *dat
1338
1144
  static void generate_json_bignum(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1339
1145
  {
1340
1146
  VALUE tmp = rb_funcall(obj, i_to_s, 0);
1341
- fbuffer_append_str(buffer, tmp);
1342
- }
1343
-
1344
- #ifdef RUBY_INTEGER_UNIFICATION
1345
- static void generate_json_integer(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1346
- {
1347
- if (FIXNUM_P(obj))
1348
- generate_json_fixnum(buffer, data, obj);
1349
- else
1350
- generate_json_bignum(buffer, data, obj);
1147
+ fbuffer_append_str(buffer, StringValue(tmp));
1351
1148
  }
1352
- #endif
1353
1149
 
1354
1150
  static void generate_json_float(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1355
1151
  {
@@ -1363,7 +1159,7 @@ static void generate_json_float(FBuffer *buffer, struct generate_json_data *data
1363
1159
  if (casted_obj != obj) {
1364
1160
  increase_depth(data);
1365
1161
  generate_json(buffer, data, casted_obj);
1366
- data->state->depth--;
1162
+ data->depth--;
1367
1163
  return;
1368
1164
  }
1369
1165
  }
@@ -1394,7 +1190,7 @@ static void generate_json_fragment(FBuffer *buffer, struct generate_json_data *d
1394
1190
  fbuffer_append_str(buffer, fragment);
1395
1191
  }
1396
1192
 
1397
- static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1193
+ static inline void generate_json_general(FBuffer *buffer, struct generate_json_data *data, VALUE obj, bool fallback)
1398
1194
  {
1399
1195
  bool as_json_called = false;
1400
1196
  start:
@@ -1421,15 +1217,15 @@ start:
1421
1217
  generate_json_bignum(buffer, data, obj);
1422
1218
  break;
1423
1219
  case T_HASH:
1424
- if (klass != rb_cHash) goto general;
1220
+ if (fallback && klass != rb_cHash) goto general;
1425
1221
  generate_json_object(buffer, data, obj);
1426
1222
  break;
1427
1223
  case T_ARRAY:
1428
- if (klass != rb_cArray) goto general;
1224
+ if (fallback && klass != rb_cArray) goto general;
1429
1225
  generate_json_array(buffer, data, obj);
1430
1226
  break;
1431
1227
  case T_STRING:
1432
- if (klass != rb_cString) goto general;
1228
+ if (fallback && klass != rb_cString) goto general;
1433
1229
 
1434
1230
  if (RB_LIKELY(valid_json_string_p(obj))) {
1435
1231
  raw_generate_json_string(buffer, data, obj);
@@ -1445,7 +1241,7 @@ start:
1445
1241
  generate_json_symbol(buffer, data, obj);
1446
1242
  break;
1447
1243
  case T_FLOAT:
1448
- if (klass != rb_cFloat) goto general;
1244
+ if (fallback && klass != rb_cFloat) goto general;
1449
1245
  generate_json_float(buffer, data, obj);
1450
1246
  break;
1451
1247
  case T_STRUCT:
@@ -1469,6 +1265,16 @@ start:
1469
1265
  }
1470
1266
  }
1471
1267
 
1268
+ static void generate_json(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1269
+ {
1270
+ generate_json_general(buffer, data, obj, true);
1271
+ }
1272
+
1273
+ static void generate_json_no_fallback(FBuffer *buffer, struct generate_json_data *data, VALUE obj)
1274
+ {
1275
+ generate_json_general(buffer, data, obj, false);
1276
+ }
1277
+
1472
1278
  static VALUE generate_json_try(VALUE d)
1473
1279
  {
1474
1280
  struct generate_json_data *data = (struct generate_json_data *)d;
@@ -1486,7 +1292,7 @@ static VALUE generate_json_ensure(VALUE d)
1486
1292
  return Qundef;
1487
1293
  }
1488
1294
 
1489
- static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
1295
+ static inline VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func, VALUE io)
1490
1296
  {
1491
1297
  GET_STATE(self);
1492
1298
 
@@ -1498,8 +1304,9 @@ static VALUE cState_partial_generate(VALUE self, VALUE obj, generator_func func,
1498
1304
 
1499
1305
  struct generate_json_data data = {
1500
1306
  .buffer = &buffer,
1501
- .vstate = self,
1307
+ .vstate = Qfalse, // don't use self as it may be frozen and its depth is mutated when calling to_json
1502
1308
  .state = state,
1309
+ .depth = state->depth,
1503
1310
  .obj = obj,
1504
1311
  .func = func
1505
1312
  };
@@ -1522,34 +1329,13 @@ static VALUE cState_generate(int argc, VALUE *argv, VALUE self)
1522
1329
  return cState_partial_generate(self, obj, generate_json, io);
1523
1330
  }
1524
1331
 
1525
- static VALUE cState_generate_new(int argc, VALUE *argv, VALUE self)
1332
+ /* :nodoc: */
1333
+ static VALUE cState_generate_no_fallback(int argc, VALUE *argv, VALUE self)
1526
1334
  {
1527
1335
  rb_check_arity(argc, 1, 2);
1528
1336
  VALUE obj = argv[0];
1529
1337
  VALUE io = argc > 1 ? argv[1] : Qnil;
1530
-
1531
- GET_STATE(self);
1532
-
1533
- JSON_Generator_State new_state;
1534
- MEMCPY(&new_state, state, JSON_Generator_State, 1);
1535
-
1536
- // FIXME: depth shouldn't be part of JSON_Generator_State, as that prevents it from being used concurrently.
1537
- new_state.depth = 0;
1538
-
1539
- char stack_buffer[FBUFFER_STACK_SIZE];
1540
- FBuffer buffer = {
1541
- .io = RTEST(io) ? io : Qfalse,
1542
- };
1543
- fbuffer_stack_init(&buffer, state->buffer_initial_length, stack_buffer, FBUFFER_STACK_SIZE);
1544
-
1545
- struct generate_json_data data = {
1546
- .buffer = &buffer,
1547
- .vstate = Qfalse,
1548
- .state = &new_state,
1549
- .obj = obj,
1550
- .func = generate_json
1551
- };
1552
- return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
1338
+ return cState_partial_generate(self, obj, generate_json_no_fallback, io);
1553
1339
  }
1554
1340
 
1555
1341
  static VALUE cState_initialize(int argc, VALUE *argv, VALUE self)
@@ -1630,6 +1416,7 @@ static VALUE string_config(VALUE config)
1630
1416
  */
1631
1417
  static VALUE cState_indent_set(VALUE self, VALUE indent)
1632
1418
  {
1419
+ rb_check_frozen(self);
1633
1420
  GET_STATE(self);
1634
1421
  RB_OBJ_WRITE(self, &state->indent, string_config(indent));
1635
1422
  return Qnil;
@@ -1655,6 +1442,7 @@ static VALUE cState_space(VALUE self)
1655
1442
  */
1656
1443
  static VALUE cState_space_set(VALUE self, VALUE space)
1657
1444
  {
1445
+ rb_check_frozen(self);
1658
1446
  GET_STATE(self);
1659
1447
  RB_OBJ_WRITE(self, &state->space, string_config(space));
1660
1448
  return Qnil;
@@ -1678,6 +1466,7 @@ static VALUE cState_space_before(VALUE self)
1678
1466
  */
1679
1467
  static VALUE cState_space_before_set(VALUE self, VALUE space_before)
1680
1468
  {
1469
+ rb_check_frozen(self);
1681
1470
  GET_STATE(self);
1682
1471
  RB_OBJ_WRITE(self, &state->space_before, string_config(space_before));
1683
1472
  return Qnil;
@@ -1703,6 +1492,7 @@ static VALUE cState_object_nl(VALUE self)
1703
1492
  */
1704
1493
  static VALUE cState_object_nl_set(VALUE self, VALUE object_nl)
1705
1494
  {
1495
+ rb_check_frozen(self);
1706
1496
  GET_STATE(self);
1707
1497
  RB_OBJ_WRITE(self, &state->object_nl, string_config(object_nl));
1708
1498
  return Qnil;
@@ -1726,6 +1516,7 @@ static VALUE cState_array_nl(VALUE self)
1726
1516
  */
1727
1517
  static VALUE cState_array_nl_set(VALUE self, VALUE array_nl)
1728
1518
  {
1519
+ rb_check_frozen(self);
1729
1520
  GET_STATE(self);
1730
1521
  RB_OBJ_WRITE(self, &state->array_nl, string_config(array_nl));
1731
1522
  return Qnil;
@@ -1749,6 +1540,7 @@ static VALUE cState_as_json(VALUE self)
1749
1540
  */
1750
1541
  static VALUE cState_as_json_set(VALUE self, VALUE as_json)
1751
1542
  {
1543
+ rb_check_frozen(self);
1752
1544
  GET_STATE(self);
1753
1545
  RB_OBJ_WRITE(self, &state->as_json, rb_convert_type(as_json, T_DATA, "Proc", "to_proc"));
1754
1546
  return Qnil;
@@ -1783,6 +1575,17 @@ static long long_config(VALUE num)
1783
1575
  return RTEST(num) ? FIX2LONG(num) : 0;
1784
1576
  }
1785
1577
 
1578
+ // depth must never be negative; reject early with a clear error.
1579
+ static long depth_config(VALUE num)
1580
+ {
1581
+ if (!RTEST(num)) return 0;
1582
+ long d = NUM2LONG(num);
1583
+ if (RB_UNLIKELY(d < 0)) {
1584
+ rb_raise(rb_eArgError, "depth must be >= 0 (got %ld)", d);
1585
+ }
1586
+ return d;
1587
+ }
1588
+
1786
1589
  /*
1787
1590
  * call-seq: max_nesting=(depth)
1788
1591
  *
@@ -1791,6 +1594,7 @@ static long long_config(VALUE num)
1791
1594
  */
1792
1595
  static VALUE cState_max_nesting_set(VALUE self, VALUE depth)
1793
1596
  {
1597
+ rb_check_frozen(self);
1794
1598
  GET_STATE(self);
1795
1599
  state->max_nesting = long_config(depth);
1796
1600
  return Qnil;
@@ -1816,6 +1620,7 @@ static VALUE cState_script_safe(VALUE self)
1816
1620
  */
1817
1621
  static VALUE cState_script_safe_set(VALUE self, VALUE enable)
1818
1622
  {
1623
+ rb_check_frozen(self);
1819
1624
  GET_STATE(self);
1820
1625
  state->script_safe = RTEST(enable);
1821
1626
  return Qnil;
@@ -1847,6 +1652,7 @@ static VALUE cState_strict(VALUE self)
1847
1652
  */
1848
1653
  static VALUE cState_strict_set(VALUE self, VALUE enable)
1849
1654
  {
1655
+ rb_check_frozen(self);
1850
1656
  GET_STATE(self);
1851
1657
  state->strict = RTEST(enable);
1852
1658
  return Qnil;
@@ -1871,6 +1677,7 @@ static VALUE cState_allow_nan_p(VALUE self)
1871
1677
  */
1872
1678
  static VALUE cState_allow_nan_set(VALUE self, VALUE enable)
1873
1679
  {
1680
+ rb_check_frozen(self);
1874
1681
  GET_STATE(self);
1875
1682
  state->allow_nan = RTEST(enable);
1876
1683
  return Qnil;
@@ -1895,6 +1702,7 @@ static VALUE cState_ascii_only_p(VALUE self)
1895
1702
  */
1896
1703
  static VALUE cState_ascii_only_set(VALUE self, VALUE enable)
1897
1704
  {
1705
+ rb_check_frozen(self);
1898
1706
  GET_STATE(self);
1899
1707
  state->ascii_only = RTEST(enable);
1900
1708
  return Qnil;
@@ -1932,8 +1740,9 @@ static VALUE cState_depth(VALUE self)
1932
1740
  */
1933
1741
  static VALUE cState_depth_set(VALUE self, VALUE depth)
1934
1742
  {
1743
+ rb_check_frozen(self);
1935
1744
  GET_STATE(self);
1936
- state->depth = long_config(depth);
1745
+ state->depth = depth_config(depth);
1937
1746
  return Qnil;
1938
1747
  }
1939
1748
 
@@ -1965,6 +1774,7 @@ static void buffer_initial_length_set(JSON_Generator_State *state, VALUE buffer_
1965
1774
  */
1966
1775
  static VALUE cState_buffer_initial_length_set(VALUE self, VALUE buffer_initial_length)
1967
1776
  {
1777
+ rb_check_frozen(self);
1968
1778
  GET_STATE(self);
1969
1779
  buffer_initial_length_set(state, buffer_initial_length);
1970
1780
  return Qnil;
@@ -1997,7 +1807,7 @@ static int configure_state_i(VALUE key, VALUE val, VALUE _arg)
1997
1807
  else if (key == sym_max_nesting) { state->max_nesting = long_config(val); }
1998
1808
  else if (key == sym_allow_nan) { state->allow_nan = RTEST(val); }
1999
1809
  else if (key == sym_ascii_only) { state->ascii_only = RTEST(val); }
2000
- else if (key == sym_depth) { state->depth = long_config(val); }
1810
+ else if (key == sym_depth) { state->depth = depth_config(val); }
2001
1811
  else if (key == sym_buffer_initial_length) { buffer_initial_length_set(state, val); }
2002
1812
  else if (key == sym_script_safe) { state->script_safe = RTEST(val); }
2003
1813
  else if (key == sym_escape_slash) { state->script_safe = RTEST(val); }
@@ -2031,12 +1841,13 @@ static void configure_state(JSON_Generator_State *state, VALUE vstate, VALUE con
2031
1841
 
2032
1842
  static VALUE cState_configure(VALUE self, VALUE opts)
2033
1843
  {
1844
+ rb_check_frozen(self);
2034
1845
  GET_STATE(self);
2035
1846
  configure_state(state, self, opts);
2036
1847
  return self;
2037
1848
  }
2038
1849
 
2039
- static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1850
+ static VALUE cState_m_do_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io, generator_func func)
2040
1851
  {
2041
1852
  JSON_Generator_State state = {0};
2042
1853
  state_init(&state);
@@ -2052,15 +1863,23 @@ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
2052
1863
  .buffer = &buffer,
2053
1864
  .vstate = Qfalse,
2054
1865
  .state = &state,
1866
+ .depth = state.depth,
2055
1867
  .obj = obj,
2056
- .func = generate_json,
1868
+ .func = func,
2057
1869
  };
2058
1870
  return rb_ensure(generate_json_try, (VALUE)&data, generate_json_ensure, (VALUE)&data);
2059
1871
  }
2060
1872
 
2061
- /*
2062
- *
2063
- */
1873
+ static VALUE cState_m_generate(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1874
+ {
1875
+ return cState_m_do_generate(klass, obj, opts, io, generate_json);
1876
+ }
1877
+
1878
+ static VALUE cState_m_generate_no_fallback(VALUE klass, VALUE obj, VALUE opts, VALUE io)
1879
+ {
1880
+ return cState_m_do_generate(klass, obj, opts, io, generate_json_no_fallback);
1881
+ }
1882
+
2064
1883
  void Init_generator(void)
2065
1884
  {
2066
1885
  #ifdef HAVE_RB_EXT_RACTOR_SAFE
@@ -2125,47 +1944,12 @@ void Init_generator(void)
2125
1944
  rb_define_method(cState, "buffer_initial_length", cState_buffer_initial_length, 0);
2126
1945
  rb_define_method(cState, "buffer_initial_length=", cState_buffer_initial_length_set, 1);
2127
1946
  rb_define_method(cState, "generate", cState_generate, -1);
2128
- rb_define_method(cState, "generate_new", cState_generate_new, -1); // :nodoc:
1947
+ rb_define_method(cState, "_generate_no_fallback", cState_generate_no_fallback, -1);
2129
1948
 
2130
1949
  rb_define_private_method(cState, "allow_duplicate_key?", cState_allow_duplicate_key_p, 0);
2131
1950
 
2132
1951
  rb_define_singleton_method(cState, "generate", cState_m_generate, 3);
2133
-
2134
- VALUE mGeneratorMethods = rb_define_module_under(mGenerator, "GeneratorMethods");
2135
-
2136
- VALUE mObject = rb_define_module_under(mGeneratorMethods, "Object");
2137
- rb_define_method(mObject, "to_json", mObject_to_json, -1);
2138
-
2139
- VALUE mHash = rb_define_module_under(mGeneratorMethods, "Hash");
2140
- rb_define_method(mHash, "to_json", mHash_to_json, -1);
2141
-
2142
- VALUE mArray = rb_define_module_under(mGeneratorMethods, "Array");
2143
- rb_define_method(mArray, "to_json", mArray_to_json, -1);
2144
-
2145
- #ifdef RUBY_INTEGER_UNIFICATION
2146
- VALUE mInteger = rb_define_module_under(mGeneratorMethods, "Integer");
2147
- rb_define_method(mInteger, "to_json", mInteger_to_json, -1);
2148
- #else
2149
- VALUE mFixnum = rb_define_module_under(mGeneratorMethods, "Fixnum");
2150
- rb_define_method(mFixnum, "to_json", mFixnum_to_json, -1);
2151
-
2152
- VALUE mBignum = rb_define_module_under(mGeneratorMethods, "Bignum");
2153
- rb_define_method(mBignum, "to_json", mBignum_to_json, -1);
2154
- #endif
2155
- VALUE mFloat = rb_define_module_under(mGeneratorMethods, "Float");
2156
- rb_define_method(mFloat, "to_json", mFloat_to_json, -1);
2157
-
2158
- VALUE mString = rb_define_module_under(mGeneratorMethods, "String");
2159
- rb_define_method(mString, "to_json", mString_to_json, -1);
2160
-
2161
- VALUE mTrueClass = rb_define_module_under(mGeneratorMethods, "TrueClass");
2162
- rb_define_method(mTrueClass, "to_json", mTrueClass_to_json, -1);
2163
-
2164
- VALUE mFalseClass = rb_define_module_under(mGeneratorMethods, "FalseClass");
2165
- rb_define_method(mFalseClass, "to_json", mFalseClass_to_json, -1);
2166
-
2167
- VALUE mNilClass = rb_define_module_under(mGeneratorMethods, "NilClass");
2168
- rb_define_method(mNilClass, "to_json", mNilClass_to_json, -1);
1952
+ rb_define_singleton_method(cState, "_generate_no_fallback", cState_m_generate_no_fallback, 3);
2169
1953
 
2170
1954
  rb_global_variable(&Encoding_UTF_8);
2171
1955
  Encoding_UTF_8 = rb_const_get(rb_path2class("Encoding"), rb_intern("UTF_8"));
@@ -2173,10 +1957,6 @@ void Init_generator(void)
2173
1957
  i_to_s = rb_intern("to_s");
2174
1958
  i_to_json = rb_intern("to_json");
2175
1959
  i_new = rb_intern("new");
2176
- i_pack = rb_intern("pack");
2177
- i_unpack = rb_intern("unpack");
2178
- i_create_id = rb_intern("create_id");
2179
- i_extend = rb_intern("extend");
2180
1960
  i_encode = rb_intern("encode");
2181
1961
 
2182
1962
  sym_indent = ID2SYM(rb_intern("indent"));
@@ -2201,22 +1981,5 @@ void Init_generator(void)
2201
1981
 
2202
1982
  rb_require("json/ext/generator/state");
2203
1983
 
2204
-
2205
- switch (find_simd_implementation()) {
2206
- #ifdef HAVE_SIMD
2207
- #ifdef HAVE_SIMD_NEON
2208
- case SIMD_NEON:
2209
- search_escape_basic_impl = search_escape_basic_neon;
2210
- break;
2211
- #endif /* HAVE_SIMD_NEON */
2212
- #ifdef HAVE_SIMD_SSE2
2213
- case SIMD_SSE2:
2214
- search_escape_basic_impl = search_escape_basic_sse2;
2215
- break;
2216
- #endif /* HAVE_SIMD_SSE2 */
2217
- #endif /* HAVE_SIMD */
2218
- default:
2219
- search_escape_basic_impl = search_escape_basic;
2220
- break;
2221
- }
1984
+ simd_impl = find_simd_implementation();
2222
1985
  }