oj 3.13.11 → 3.13.23

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.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +50 -0
  3. data/README.md +2 -0
  4. data/ext/oj/buf.h +4 -0
  5. data/ext/oj/circarray.c +1 -1
  6. data/ext/oj/code.c +15 -22
  7. data/ext/oj/compat.c +10 -10
  8. data/ext/oj/custom.c +62 -108
  9. data/ext/oj/dump.c +85 -97
  10. data/ext/oj/dump.h +12 -8
  11. data/ext/oj/dump_compat.c +46 -88
  12. data/ext/oj/dump_leaf.c +14 -58
  13. data/ext/oj/dump_object.c +33 -156
  14. data/ext/oj/dump_strict.c +17 -29
  15. data/ext/oj/extconf.rb +5 -4
  16. data/ext/oj/fast.c +24 -22
  17. data/ext/oj/intern.c +15 -11
  18. data/ext/oj/intern.h +1 -1
  19. data/ext/oj/mimic_json.c +44 -32
  20. data/ext/oj/object.c +42 -41
  21. data/ext/oj/odd.c +83 -63
  22. data/ext/oj/odd.h +13 -13
  23. data/ext/oj/oj.c +57 -22
  24. data/ext/oj/oj.h +24 -3
  25. data/ext/oj/parse.c +114 -78
  26. data/ext/oj/parse.h +2 -0
  27. data/ext/oj/parser.c +77 -21
  28. data/ext/oj/parser.h +12 -0
  29. data/ext/oj/rails.c +41 -65
  30. data/ext/oj/rails.h +1 -1
  31. data/ext/oj/reader.c +2 -0
  32. data/ext/oj/saj.c +11 -23
  33. data/ext/oj/saj2.c +333 -85
  34. data/ext/oj/saj2.h +23 -0
  35. data/ext/oj/sparse.c +4 -0
  36. data/ext/oj/stream_writer.c +3 -1
  37. data/ext/oj/strict.c +13 -13
  38. data/ext/oj/string_writer.c +12 -5
  39. data/ext/oj/usual.c +82 -129
  40. data/ext/oj/usual.h +68 -0
  41. data/ext/oj/val_stack.c +1 -1
  42. data/ext/oj/validate.c +21 -26
  43. data/ext/oj/wab.c +21 -26
  44. data/lib/oj/saj.rb +20 -6
  45. data/lib/oj/state.rb +1 -1
  46. data/lib/oj/version.rb +1 -1
  47. data/pages/Compatibility.md +1 -1
  48. data/pages/Options.md +6 -0
  49. data/test/activesupport7/abstract_unit.rb +49 -0
  50. data/test/activesupport7/decoding_test.rb +125 -0
  51. data/test/activesupport7/encoding_test.rb +486 -0
  52. data/test/activesupport7/encoding_test_cases.rb +104 -0
  53. data/test/activesupport7/time_zone_test_helpers.rb +47 -0
  54. data/test/bar.rb +3 -8
  55. data/test/foo.rb +3 -3
  56. data/test/helper.rb +8 -2
  57. data/test/json_gem/json_generator_test.rb +5 -4
  58. data/test/json_gem/json_parser_test.rb +8 -1
  59. data/test/json_gem/test_helper.rb +7 -3
  60. data/test/perf_dump.rb +50 -0
  61. data/test/test_compat.rb +25 -0
  62. data/test/test_custom.rb +13 -2
  63. data/test/test_file.rb +23 -7
  64. data/test/test_gc.rb +11 -0
  65. data/test/test_object.rb +8 -10
  66. data/test/test_parser.rb +3 -19
  67. data/test/test_parser_debug.rb +27 -0
  68. data/test/test_parser_saj.rb +92 -2
  69. data/test/test_scp.rb +2 -4
  70. data/test/test_strict.rb +2 -0
  71. data/test/test_various.rb +8 -3
  72. data/test/test_wab.rb +2 -0
  73. data/test/tests.rb +9 -0
  74. data/test/tests_mimic.rb +9 -0
  75. data/test/tests_mimic_addition.rb +9 -0
  76. metadata +13 -116
data/ext/oj/intern.c CHANGED
@@ -37,13 +37,10 @@ typedef struct _hash {
37
37
  struct _hash class_hash;
38
38
  struct _hash attr_hash;
39
39
 
40
- static struct _cache *str_cache = NULL;
41
40
  static VALUE str_cache_obj;
42
41
 
43
- static struct _cache *sym_cache = NULL;
44
42
  static VALUE sym_cache_obj;
45
43
 
46
- static struct _cache *attr_cache = NULL;
47
44
  static VALUE attr_cache_obj;
48
45
 
49
46
  static VALUE form_str(const char *str, size_t len) {
@@ -86,18 +83,22 @@ static VALUE form_attr(const char *str, size_t len) {
86
83
  return (VALUE)rb_intern3(buf, len + 1, oj_utf8_encoding);
87
84
  }
88
85
 
89
- void oj_hash_init() {
86
+ void oj_hash_init(void) {
90
87
  VALUE cache_class = rb_define_class_under(Oj, "Cache", rb_cObject);
88
+ rb_undef_alloc_func(cache_class);
91
89
 
92
- str_cache = cache_create(0, form_str, true, true);
90
+ rb_gc_register_address(&cache_class);
91
+ rb_undef_alloc_func(cache_class);
92
+
93
+ struct _cache *str_cache = cache_create(0, form_str, true, true);
93
94
  str_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, str_cache);
94
95
  rb_gc_register_address(&str_cache_obj);
95
96
 
96
- sym_cache = cache_create(0, form_sym, true, true);
97
+ struct _cache *sym_cache = cache_create(0, form_sym, true, true);
97
98
  sym_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, sym_cache);
98
99
  rb_gc_register_address(&sym_cache_obj);
99
100
 
100
- attr_cache = cache_create(0, form_attr, false, true);
101
+ struct _cache *attr_cache = cache_create(0, form_attr, false, true);
101
102
  attr_cache_obj = Data_Wrap_Struct(cache_class, cache_mark, cache_free, attr_cache);
102
103
  rb_gc_register_address(&attr_cache_obj);
103
104
 
@@ -118,18 +119,18 @@ oj_str_intern(const char *key, size_t len) {
118
119
  #if HAVE_RB_ENC_INTERNED_STR && 0
119
120
  return rb_enc_interned_str(key, len, rb_utf8_encoding());
120
121
  #else
121
- return cache_intern(str_cache, key, len);
122
+ return cache_intern(DATA_PTR(str_cache_obj), key, len);
122
123
  #endif
123
124
  }
124
125
 
125
126
  VALUE
126
127
  oj_sym_intern(const char *key, size_t len) {
127
- return cache_intern(sym_cache, key, len);
128
+ return cache_intern(DATA_PTR(sym_cache_obj), key, len);
128
129
  }
129
130
 
130
131
  ID
131
132
  oj_attr_intern(const char *key, size_t len) {
132
- return cache_intern(attr_cache, key, len);
133
+ return cache_intern(DATA_PTR(attr_cache_obj), key, len);
133
134
  }
134
135
 
135
136
  static uint64_t hash_calc(const uint8_t *key, size_t len) {
@@ -275,6 +276,7 @@ VALUE oj_class_intern(const char *key, size_t len, bool safe, ParseInfo pi, int
275
276
  bucket->len = len;
276
277
  bucket->val = resolve_classpath(pi, key, len, auto_define, error_class);
277
278
  }
279
+ rb_gc_register_mark_object(bucket->val);
278
280
  return bucket->val;
279
281
  }
280
282
 
@@ -287,8 +289,10 @@ char *oj_strndup(const char *s, size_t len) {
287
289
  return d;
288
290
  }
289
291
 
290
- void intern_cleanup() {
292
+ /*
293
+ void intern_cleanup(void) {
291
294
  cache_free(str_cache);
292
295
  cache_free(sym_cache);
293
296
  cache_free(attr_cache);
294
297
  }
298
+ */
data/ext/oj/intern.h CHANGED
@@ -9,7 +9,7 @@
9
9
 
10
10
  struct _parseInfo;
11
11
 
12
- extern void oj_hash_init();
12
+ extern void oj_hash_init(void);
13
13
 
14
14
  extern VALUE oj_str_intern(const char *key, size_t len);
15
15
  extern VALUE oj_sym_intern(const char *key, size_t len);
data/ext/oj/mimic_json.c CHANGED
@@ -198,7 +198,6 @@ static int mimic_limit_arg(VALUE a) {
198
198
  * Returns [_String_] a JSON string.
199
199
  */
200
200
  static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
201
- char buf[4096];
202
201
  struct _out out;
203
202
  struct _options copts = oj_default_options;
204
203
  VALUE rstr;
@@ -206,9 +205,9 @@ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
206
205
 
207
206
  copts.str_rx.head = NULL;
208
207
  copts.str_rx.tail = NULL;
209
- out.buf = buf;
210
- out.end = buf + sizeof(buf) - 10;
211
- out.allocated = false;
208
+
209
+ oj_out_init(&out);
210
+
212
211
  out.caller = CALLER_DUMP;
213
212
  copts.escape_mode = JXEsc;
214
213
  copts.mode = CompatMode;
@@ -257,9 +256,9 @@ static VALUE mimic_dump(int argc, VALUE *argv, VALUE self) {
257
256
  rb_funcall2(io, oj_write_id, 1, args);
258
257
  rstr = io;
259
258
  }
260
- if (out.allocated) {
261
- xfree(out.buf);
262
- }
259
+
260
+ oj_out_free(&out);
261
+
263
262
  return rstr;
264
263
  }
265
264
 
@@ -358,15 +357,16 @@ static VALUE mimic_dump_load(int argc, VALUE *argv, VALUE self) {
358
357
  }
359
358
 
360
359
  static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
361
- char buf[4096];
362
360
  struct _out out;
363
361
  VALUE rstr;
364
362
 
365
- memset(buf, 0, sizeof(buf));
363
+ if (0 == argc) {
364
+ rb_raise(rb_eArgError, "wrong number of arguments (0))");
365
+ }
366
+ memset(out.stack_buffer, 0, sizeof(out.stack_buffer));
367
+
368
+ oj_out_init(&out);
366
369
 
367
- out.buf = buf;
368
- out.end = buf + sizeof(buf) - 10;
369
- out.allocated = false;
370
370
  out.omit_nil = copts->dump_opts.omit_nil;
371
371
  out.caller = CALLER_GENERATE;
372
372
  // For obj.to_json or generate nan is not allowed but if called from dump
@@ -388,6 +388,10 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
388
388
  VALUE active_hack[1];
389
389
 
390
390
  if (Qundef == state_class) {
391
+ rb_warn(
392
+ "Oj::Rails.mimic_JSON was called implicitly. "
393
+ "Call it explicitly beforehand if you want to remove this warning."
394
+ );
391
395
  oj_define_mimic_json(0, NULL, Qnil);
392
396
  }
393
397
  active_hack[0] = rb_funcall(state_class, oj_new_id, 0);
@@ -398,9 +402,9 @@ static VALUE mimic_generate_core(int argc, VALUE *argv, Options copts) {
398
402
  }
399
403
  rstr = rb_str_new2(out.buf);
400
404
  rstr = oj_encode(rstr);
401
- if (out.allocated) {
402
- xfree(out.buf);
403
- }
405
+
406
+ oj_out_free(&out);
407
+
404
408
  return rstr;
405
409
  }
406
410
 
@@ -457,9 +461,12 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
457
461
  // a Hash. I haven't dug deep enough to find out why but using a State
458
462
  // instance and not a Hash gives the desired behavior.
459
463
  *rargs = *argv;
460
- if (1 == argc) {
464
+ if (0 == argc) {
465
+ rb_raise(rb_eArgError, "wrong number of arguments (0))");
466
+ }
467
+ if (1 == argc || Qnil == argv[1]) {
461
468
  h = rb_hash_new();
462
- } else {
469
+ } else {
463
470
  h = argv[1];
464
471
  }
465
472
  if (!oj_hash_has_key(h, oj_indent_sym)) {
@@ -478,6 +485,10 @@ oj_mimic_pretty_generate(int argc, VALUE *argv, VALUE self) {
478
485
  rb_hash_aset(h, oj_array_nl_sym, rb_str_new2("\n"));
479
486
  }
480
487
  if (Qundef == state_class) {
488
+ rb_warn(
489
+ "Oj::Rails.mimic_JSON was called implicitly. "
490
+ "Call it explicitly beforehand if you want to remove this warning."
491
+ );
481
492
  oj_define_mimic_json(0, NULL, Qnil);
482
493
  }
483
494
  rargs[1] = rb_funcall(state_class, oj_new_id, 1, h);
@@ -533,14 +544,6 @@ static int parse_options_cb(VALUE k, VALUE v, VALUE info) {
533
544
  }
534
545
  } else if (oj_decimal_class_sym == k) {
535
546
  pi->options.compat_bigdec = (oj_bigdecimal_class == v);
536
- } else if (oj_max_nesting_sym == k) {
537
- if (Qtrue == v) {
538
- pi->max_depth = 100;
539
- } else if (Qfalse == v || Qnil == v) {
540
- pi->max_depth = 0;
541
- } else if (T_FIXNUM == rb_type(v)) {
542
- pi->max_depth = NUM2INT(v);
543
- }
544
547
  }
545
548
  return ST_CONTINUE;
546
549
  }
@@ -570,11 +573,21 @@ static VALUE mimic_parse_core(int argc, VALUE *argv, VALUE self, bool bang) {
570
573
  pi.max_depth = 100;
571
574
 
572
575
  if (Qnil != ropts) {
576
+ VALUE v;
577
+
573
578
  if (T_HASH != rb_type(ropts)) {
574
579
  rb_raise(rb_eArgError, "options must be a hash.");
575
580
  }
576
581
 
577
582
  rb_hash_foreach(ropts, parse_options_cb, (VALUE)&pi);
583
+ v = rb_hash_lookup(ropts, oj_max_nesting_sym);
584
+ if (Qtrue == v) {
585
+ pi.max_depth = 100;
586
+ } else if (Qfalse == v || Qnil == v) {
587
+ pi.max_depth = 0;
588
+ } else if (T_FIXNUM == rb_type(v)) {
589
+ pi.max_depth = NUM2INT(v);
590
+ }
578
591
  oj_parse_opt_match_string(&pi.options.str_rx, ropts);
579
592
  if (Yes == pi.options.create_ok && Yes == pi.options.sym_key) {
580
593
  rb_raise(rb_eArgError, ":symbolize_names and :create_additions can not both be true.");
@@ -740,16 +753,15 @@ static struct _options mimic_object_to_json_options = {0, // indent
740
753
  }};
741
754
 
742
755
  static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
743
- char buf[4096];
744
756
  struct _out out;
745
757
  VALUE rstr;
746
758
  struct _options copts = oj_default_options;
747
759
 
748
760
  copts.str_rx.head = NULL;
749
761
  copts.str_rx.tail = NULL;
750
- out.buf = buf;
751
- out.end = buf + sizeof(buf) - 10;
752
- out.allocated = false;
762
+
763
+ oj_out_init(&out);
764
+
753
765
  out.omit_nil = copts.dump_opts.omit_nil;
754
766
  copts.mode = CompatMode;
755
767
  copts.to_json = No;
@@ -765,9 +777,9 @@ static VALUE mimic_object_to_json(int argc, VALUE *argv, VALUE self) {
765
777
  }
766
778
  rstr = rb_str_new2(out.buf);
767
779
  rstr = oj_encode(rstr);
768
- if (out.allocated) {
769
- xfree(out.buf);
770
- }
780
+
781
+ oj_out_free(&out);
782
+
771
783
  return rstr;
772
784
  }
773
785
 
data/ext/oj/object.c CHANGED
@@ -67,9 +67,9 @@ static VALUE str_to_value(ParseInfo pi, const char *str, size_t len, const char
67
67
 
68
68
  // The much faster approach (4x faster)
69
69
  static int parse_num(const char *str, const char *end, int cnt) {
70
- int n = 0;
70
+ int n = 0;
71
71
  char c;
72
- int i;
72
+ int i;
73
73
 
74
74
  for (i = cnt; 0 < i; i--, str++) {
75
75
  c = *str;
@@ -83,9 +83,9 @@ static int parse_num(const char *str, const char *end, int cnt) {
83
83
 
84
84
  VALUE
85
85
  oj_parse_xml_time(const char *str, int len) {
86
- VALUE args[8];
86
+ VALUE args[8];
87
87
  const char *end = str + len;
88
- int n;
88
+ int n;
89
89
 
90
90
  // year
91
91
  if (0 > (n = parse_num(str, end, 4))) {
@@ -269,19 +269,10 @@ static int hat_num(ParseInfo pi, Val parent, Val kval, NumInfo ni) {
269
269
  // match the expected value.
270
270
  parent->val = rb_funcall2(parent->val, oj_utc_id, 0, 0);
271
271
  } else if (ni->has_exp) {
272
- int64_t t = (int64_t)(ni->i + ni->exp);
273
- struct _timeInfo ti;
274
- VALUE args[8];
275
-
276
- sec_as_time(t, &ti);
277
- args[0] = LONG2NUM((long)(ti.year));
278
- args[1] = LONG2NUM(ti.mon);
279
- args[2] = LONG2NUM(ti.day);
280
- args[3] = LONG2NUM(ti.hour);
281
- args[4] = LONG2NUM(ti.min);
282
- args[5] = rb_float_new((double)ti.sec + ((double)nsec + 0.5) / 1000000000.0);
283
- args[6] = LONG2NUM(ni->exp);
284
- parent->val = rb_funcall2(rb_cTime, oj_new_id, 7, args);
272
+ struct timespec ts;
273
+ ts.tv_sec = ni->i;
274
+ ts.tv_nsec = nsec;
275
+ parent->val = rb_time_timespec_new(&ts, (int)ni->exp);
285
276
  } else {
286
277
  parent->val = rb_time_nano_new(ni->i, (long)nsec);
287
278
  }
@@ -333,26 +324,30 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
333
324
  // If struct is not defined then we let this fail and raise an exception.
334
325
  sc = oj_name2struct(pi, *RARRAY_PTR(value), rb_eArgError);
335
326
  }
336
- // Create a properly initialized struct instance without calling the initialize method.
337
- parent->val = rb_obj_alloc(sc);
338
- // If the JSON array has more entries than the struct class allows, we record an error.
327
+ if (sc == rb_cRange) {
328
+ parent->val = rb_class_new_instance(len - 1, RARRAY_PTR(value) + 1, rb_cRange);
329
+ } else {
330
+ // Create a properly initialized struct instance without calling the initialize method.
331
+ parent->val = rb_obj_alloc(sc);
332
+ // If the JSON array has more entries than the struct class allows, we record an error.
339
333
  #ifdef RSTRUCT_LEN
340
334
  #if RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
341
335
  slen = (int)NUM2LONG(RSTRUCT_LEN(parent->val));
342
336
  #else // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
343
- slen = (int)RSTRUCT_LEN(parent->val);
337
+ slen = (int)RSTRUCT_LEN(parent->val);
344
338
  #endif // RSTRUCT_LEN_RETURNS_INTEGER_OBJECT
345
339
  #else
346
- slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
340
+ slen = FIX2INT(rb_funcall2(parent->val, oj_length_id, 0, 0));
347
341
  #endif
348
- // MRI >= 1.9
349
- if (len - 1 > slen) {
350
- oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
351
- } else {
352
- int i;
342
+ // MRI >= 1.9
343
+ if (len - 1 > slen) {
344
+ oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "Invalid struct data");
345
+ } else {
346
+ int i;
353
347
 
354
- for (i = 0; i < len - 1; i++) {
355
- rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
348
+ for (i = 0; i < len - 1; i++) {
349
+ rb_struct_aset(parent->val, INT2FIX(i), RARRAY_PTR(value)[i + 1]);
350
+ }
356
351
  }
357
352
  }
358
353
  return 1;
@@ -374,11 +369,17 @@ static int hat_value(ParseInfo pi, Val parent, const char *key, size_t klen, vol
374
369
  }
375
370
 
376
371
  void oj_set_obj_ivar(Val parent, Val kval, VALUE value) {
377
- rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
372
+ if (kval->klen == 5 && strncmp("~mesg", kval->key, 5) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
373
+ parent->val = rb_funcall(parent->val, rb_intern("exception"), 1, value);
374
+ } else if (kval->klen == 3 && strncmp("~bt", kval->key, 3) == 0 && rb_obj_is_kind_of(parent->val, rb_eException)) {
375
+ rb_funcall(parent->val, rb_intern("set_backtrace"), 1, value);
376
+ } else {
377
+ rb_ivar_set(parent->val, oj_attr_intern(kval->key, kval->klen), value);
378
+ }
378
379
  }
379
380
 
380
381
  static void hash_set_cstr(ParseInfo pi, Val kval, const char *str, size_t len, const char *orig) {
381
- const char * key = kval->key;
382
+ const char *key = kval->key;
382
383
  int klen = kval->klen;
383
384
  Val parent = stack_peek(&pi->stack);
384
385
  volatile VALUE rval = Qnil;
@@ -445,13 +446,13 @@ WHICH_TYPE:
445
446
  rb_class2name(rb_obj_class(parent->val)));
446
447
  return;
447
448
  }
448
- if (Yes == pi->options.trace) {
449
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
449
450
  oj_trace_parse_call("set_string", pi, __FILE__, __LINE__, rval);
450
451
  }
451
452
  }
452
453
 
453
454
  static void hash_set_num(ParseInfo pi, Val kval, NumInfo ni) {
454
- const char * key = kval->key;
455
+ const char *key = kval->key;
455
456
  int klen = kval->klen;
456
457
  Val parent = stack_peek(&pi->stack);
457
458
  volatile VALUE rval = Qnil;
@@ -516,7 +517,7 @@ WHICH_TYPE:
516
517
  rb_class2name(rb_obj_class(parent->val)));
517
518
  return;
518
519
  }
519
- if (Yes == pi->options.trace) {
520
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
520
521
  oj_trace_parse_call("add_number", pi, __FILE__, __LINE__, rval);
521
522
  }
522
523
  }
@@ -602,13 +603,13 @@ WHICH_TYPE:
602
603
  rb_class2name(rb_obj_class(parent->val)));
603
604
  return;
604
605
  }
605
- if (Yes == pi->options.trace) {
606
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
606
607
  oj_trace_parse_call("add_value", pi, __FILE__, __LINE__, value);
607
608
  }
608
609
  }
609
610
 
610
611
  static VALUE start_hash(ParseInfo pi) {
611
- if (Yes == pi->options.trace) {
612
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
612
613
  oj_trace_parse_in("start_hash", pi, __FILE__, __LINE__);
613
614
  }
614
615
  return Qnil;
@@ -626,7 +627,7 @@ static void end_hash(ParseInfo pi) {
626
627
  oj_odd_free(oa);
627
628
  parent->odd_args = NULL;
628
629
  }
629
- if (Yes == pi->options.trace) {
630
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
630
631
  oj_trace_parse_hash_end(pi, __FILE__, __LINE__);
631
632
  }
632
633
  }
@@ -654,7 +655,7 @@ static void array_append_cstr(ParseInfo pi, const char *str, size_t len, const c
654
655
  }
655
656
  rval = str_to_value(pi, str, len, orig);
656
657
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
657
- if (Yes == pi->options.trace) {
658
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
658
659
  oj_trace_parse_call("append_string", pi, __FILE__, __LINE__, rval);
659
660
  }
660
661
  }
@@ -663,21 +664,21 @@ static void array_append_num(ParseInfo pi, NumInfo ni) {
663
664
  volatile VALUE rval = oj_num_as_value(ni);
664
665
 
665
666
  rb_ary_push(stack_peek(&pi->stack)->val, rval);
666
- if (Yes == pi->options.trace) {
667
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
667
668
  oj_trace_parse_call("append_number", pi, __FILE__, __LINE__, rval);
668
669
  }
669
670
  }
670
671
 
671
672
  static void add_cstr(ParseInfo pi, const char *str, size_t len, const char *orig) {
672
673
  pi->stack.head->val = str_to_value(pi, str, len, orig);
673
- if (Yes == pi->options.trace) {
674
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
674
675
  oj_trace_parse_call("add_string", pi, __FILE__, __LINE__, pi->stack.head->val);
675
676
  }
676
677
  }
677
678
 
678
679
  static void add_num(ParseInfo pi, NumInfo ni) {
679
680
  pi->stack.head->val = oj_num_as_value(ni);
680
- if (Yes == pi->options.trace) {
681
+ if (RB_UNLIKELY(Yes == pi->options.trace)) {
681
682
  oj_trace_parse_call("add_num", pi, __FILE__, __LINE__, pi->stack.head->val);
682
683
  }
683
684
  }