From d4929412970953254966e508795080f53e8f3346 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 7 Nov 2024 16:16:11 -0800 Subject: [PATCH 1/4] pull stack manipulation in to macro --- ext/json/ext/parser/parser.c | 196 +++++++++++++++++----------------- ext/json/ext/parser/parser.rl | 14 +-- 2 files changed, 107 insertions(+), 103 deletions(-) diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 09ca4f75a..d99fd8355 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -464,6 +464,8 @@ enum {JSON_object_en_main = 1}; #define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack) +#define PEEK(count) rvalue_stack_peek(json->stack, count) +#define POP(count) rvalue_stack_pop(json->stack, count) static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) { @@ -476,14 +478,14 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu long stack_head = json->stack->head; -#line 480 "parser.c" +#line 482 "parser.c" { cs = JSON_object_start; } -#line 529 "parser.rl" +#line 531 "parser.rl" -#line 487 "parser.c" +#line 489 "parser.c" { short _widec; if ( p == pe ) @@ -528,7 +530,7 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 532 "parser.c" +#line 534 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -609,7 +611,7 @@ case 8: if ( ++p == pe ) goto _test_eof9; case 9: -#line 613 "parser.c" +#line 615 "parser.c" _widec = (*p); if ( (*p) < 13 ) { if ( (*p) > 9 ) { @@ -677,7 +679,7 @@ case 9: if ( ++p == pe ) goto _test_eof32; case 32: -#line 681 "parser.c" +#line 683 "parser.c" goto st0; st10: if ( ++p == pe ) @@ -1017,7 +1019,7 @@ case 31: _out: {} } -#line 530 "parser.rl" +#line 532 "parser.rl" if (cs >= JSON_object_first_final) { long count = json->stack->head - stack_head; @@ -1025,7 +1027,7 @@ case 31: if (RB_UNLIKELY(json->object_class)) { VALUE object = rb_class_new_instance(0, 0, json->object_class); long index = 0; - VALUE *items = rvalue_stack_peek(json->stack, count); + VALUE *items = PEEK(count); while (index < count) { VALUE name = items[index++]; VALUE value = items[index++]; @@ -1039,10 +1041,10 @@ case 31: #else hash = rb_hash_new(); #endif - rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash); + rb_hash_bulk_insert(count, PEEK(count), hash); *result = hash; } - rvalue_stack_pop(json->stack, count); + POP(count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; @@ -1068,7 +1070,7 @@ case 31: } -#line 1072 "parser.c" +#line 1074 "parser.c" enum {JSON_value_start = 1}; enum {JSON_value_first_final = 29}; enum {JSON_value_error = 0}; @@ -1076,7 +1078,7 @@ enum {JSON_value_error = 0}; enum {JSON_value_en_main = 1}; -#line 661 "parser.rl" +#line 663 "parser.rl" static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1084,14 +1086,14 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 1088 "parser.c" +#line 1090 "parser.c" { cs = JSON_value_start; } -#line 668 "parser.rl" +#line 670 "parser.rl" -#line 1095 "parser.c" +#line 1097 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1125,7 +1127,7 @@ case 1: cs = 0; goto _out; tr2: -#line 608 "parser.rl" +#line 610 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); if (np == NULL) { @@ -1137,7 +1139,7 @@ cs = 0; } goto st29; tr3: -#line 618 "parser.rl" +#line 620 "parser.rl" { char *np; if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) { @@ -1157,7 +1159,7 @@ cs = 0; } goto st29; tr7: -#line 636 "parser.rl" +#line 638 "parser.rl" { char *np; np = JSON_parse_array(json, p, pe, result, current_nesting + 1); @@ -1165,7 +1167,7 @@ cs = 0; } goto st29; tr11: -#line 642 "parser.rl" +#line 644 "parser.rl" { char *np; np = JSON_parse_object(json, p, pe, result, current_nesting + 1); @@ -1173,7 +1175,7 @@ cs = 0; } goto st29; tr25: -#line 601 "parser.rl" +#line 603 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -1183,7 +1185,7 @@ cs = 0; } goto st29; tr27: -#line 594 "parser.rl" +#line 596 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -1193,19 +1195,19 @@ cs = 0; } goto st29; tr31: -#line 588 "parser.rl" +#line 590 "parser.rl" { *result = Qfalse; } goto st29; tr34: -#line 585 "parser.rl" +#line 587 "parser.rl" { *result = Qnil; } goto st29; tr37: -#line 591 "parser.rl" +#line 593 "parser.rl" { *result = Qtrue; } @@ -1214,9 +1216,9 @@ cs = 0; if ( ++p == pe ) goto _test_eof29; case 29: -#line 648 "parser.rl" +#line 650 "parser.rl" { p--; {p++; cs = 29; goto _out;} } -#line 1220 "parser.c" +#line 1222 "parser.c" switch( (*p) ) { case 13: goto st29; case 32: goto st29; @@ -1457,7 +1459,7 @@ case 28: _out: {} } -#line 669 "parser.rl" +#line 671 "parser.rl" if (json->freeze) { OBJ_FREEZE(*result); @@ -1472,7 +1474,7 @@ case 28: } -#line 1476 "parser.c" +#line 1478 "parser.c" enum {JSON_integer_start = 1}; enum {JSON_integer_first_final = 3}; enum {JSON_integer_error = 0}; @@ -1480,7 +1482,7 @@ enum {JSON_integer_error = 0}; enum {JSON_integer_en_main = 1}; -#line 690 "parser.rl" +#line 692 "parser.rl" #define MAX_FAST_INTEGER_SIZE 18 @@ -1520,7 +1522,7 @@ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result) } -#line 1524 "parser.c" +#line 1526 "parser.c" enum {JSON_float_start = 1}; enum {JSON_float_first_final = 6}; enum {JSON_float_error = 0}; @@ -1528,7 +1530,7 @@ enum {JSON_float_error = 0}; enum {JSON_float_en_main = 1}; -#line 742 "parser.rl" +#line 744 "parser.rl" static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1537,15 +1539,15 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu bool is_float = false; -#line 1541 "parser.c" +#line 1543 "parser.c" { cs = JSON_float_start; } -#line 750 "parser.rl" +#line 752 "parser.rl" json->memo = p; -#line 1549 "parser.c" +#line 1551 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1585,24 +1587,24 @@ case 6: goto st0; goto tr7; tr7: -#line 734 "parser.rl" +#line 736 "parser.rl" { p--; {p++; cs = 7; goto _out;} } goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 1596 "parser.c" +#line 1598 "parser.c" goto st0; tr8: -#line 735 "parser.rl" +#line 737 "parser.rl" { is_float = true; } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1606 "parser.c" +#line 1608 "parser.c" if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; @@ -1621,14 +1623,14 @@ case 8: goto st0; goto tr7; tr9: -#line 735 "parser.rl" +#line 737 "parser.rl" { is_float = true; } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: -#line 1632 "parser.c" +#line 1634 "parser.c" switch( (*p) ) { case 43: goto st5; case 45: goto st5; @@ -1685,7 +1687,7 @@ case 10: _out: {} } -#line 752 "parser.rl" +#line 754 "parser.rl" if (cs >= JSON_float_first_final) { if (!is_float) { @@ -1741,7 +1743,7 @@ case 10: -#line 1745 "parser.c" +#line 1747 "parser.c" enum {JSON_array_start = 1}; enum {JSON_array_first_final = 22}; enum {JSON_array_error = 0}; @@ -1749,7 +1751,7 @@ enum {JSON_array_error = 0}; enum {JSON_array_en_main = 1}; -#line 832 "parser.rl" +#line 834 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1762,14 +1764,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul long stack_head = json->stack->head; -#line 1766 "parser.c" +#line 1768 "parser.c" { cs = JSON_array_start; } -#line 844 "parser.rl" +#line 846 "parser.rl" -#line 1773 "parser.c" +#line 1775 "parser.c" { short _widec; if ( p == pe ) @@ -1809,7 +1811,7 @@ case 2: goto st2; goto st0; tr2: -#line 812 "parser.rl" +#line 814 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v, current_nesting); @@ -1824,12 +1826,12 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1828 "parser.c" +#line 1830 "parser.c" _widec = (*p); if ( 44 <= (*p) && (*p) <= 44 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1876,14 +1878,14 @@ case 7: goto st3; goto st7; tr4: -#line 824 "parser.rl" +#line 826 "parser.rl" { p--; {p++; cs = 22; goto _out;} } goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: -#line 1887 "parser.c" +#line 1889 "parser.c" goto st0; st8: if ( ++p == pe ) @@ -1951,13 +1953,13 @@ case 13: if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -1965,19 +1967,19 @@ case 13: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2016,13 +2018,13 @@ case 14: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2041,20 +2043,20 @@ case 15: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 42 ) { if ( 43 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2077,13 +2079,13 @@ case 16: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -2091,19 +2093,19 @@ case 16: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2127,20 +2129,20 @@ case 17: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 10 ) { if ( 11 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 824 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2212,24 +2214,24 @@ case 21: _out: {} } -#line 845 "parser.rl" +#line 847 "parser.rl" if(cs >= JSON_array_first_final) { long count = json->stack->head - stack_head; if (RB_UNLIKELY(json->array_class)) { VALUE array = rb_class_new_instance(0, 0, json->array_class); - VALUE *items = rvalue_stack_peek(json->stack, count); + VALUE *items = PEEK(count); long index; for (index = 0; index < count; index++) { rb_funcall(array, i_leftshift, 1, items[index]); } *result = array; } else { - VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(json->stack, count)); + VALUE array = rb_ary_new_from_values(count, PEEK(count)); *result = array; } - rvalue_stack_pop(json->stack, count); + POP(count); return p + 1; } else { @@ -2406,7 +2408,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE } -#line 2410 "parser.c" +#line 2412 "parser.c" enum {JSON_string_start = 1}; enum {JSON_string_first_final = 9}; enum {JSON_string_error = 0}; @@ -2414,7 +2416,7 @@ enum {JSON_string_error = 0}; enum {JSON_string_en_main = 1}; -#line 1068 "parser.rl" +#line 1070 "parser.rl" static int @@ -2435,15 +2437,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu VALUE match_string; -#line 2439 "parser.c" +#line 2441 "parser.c" { cs = JSON_string_start; } -#line 1088 "parser.rl" +#line 1090 "parser.rl" json->memo = p; -#line 2447 "parser.c" +#line 2449 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2468,14 +2470,14 @@ case 2: goto st0; goto st2; tr2: -#line 1050 "parser.rl" +#line 1052 "parser.rl" { *result = json_string_fastpath(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} p--; {p++; cs = 9; goto _out;} } -#line 1043 "parser.rl" +#line 1045 "parser.rl" { *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} @@ -2484,7 +2486,7 @@ case 2: } goto st9; tr6: -#line 1043 "parser.rl" +#line 1045 "parser.rl" { *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} @@ -2496,7 +2498,7 @@ case 2: if ( ++p == pe ) goto _test_eof9; case 9: -#line 2500 "parser.c" +#line 2502 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -2584,7 +2586,7 @@ case 8: _out: {} } -#line 1090 "parser.rl" +#line 1092 "parser.rl" if (json->create_additions && RTEST(match_string = json->match_string)) { VALUE klass; @@ -2737,7 +2739,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 2741 "parser.c" +#line 2743 "parser.c" enum {JSON_start = 1}; enum {JSON_first_final = 10}; enum {JSON_error = 0}; @@ -2745,7 +2747,7 @@ enum {JSON_error = 0}; enum {JSON_en_main = 1}; -#line 1256 "parser.rl" +#line 1258 "parser.rl" /* @@ -2774,16 +2776,16 @@ static VALUE cParser_parse(VALUE self) json->stack = &stack; -#line 2778 "parser.c" +#line 2780 "parser.c" { cs = JSON_start; } -#line 1284 "parser.rl" +#line 1286 "parser.rl" p = json->source; pe = p + json->len; -#line 2787 "parser.c" +#line 2789 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2817,7 +2819,7 @@ case 1: cs = 0; goto _out; tr2: -#line 1248 "parser.rl" +#line 1250 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -2827,7 +2829,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 2831 "parser.c" +#line 2833 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2916,7 +2918,7 @@ case 9: _out: {} } -#line 1287 "parser.rl" +#line 1289 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); @@ -2952,16 +2954,16 @@ static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts) json->stack = &stack; -#line 2956 "parser.c" +#line 2958 "parser.c" { cs = JSON_start; } -#line 1322 "parser.rl" +#line 1324 "parser.rl" p = json->source; pe = p + json->len; -#line 2965 "parser.c" +#line 2967 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2995,7 +2997,7 @@ case 1: cs = 0; goto _out; tr2: -#line 1248 "parser.rl" +#line 1250 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -3005,7 +3007,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 3009 "parser.c" +#line 3011 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -3094,7 +3096,7 @@ case 9: _out: {} } -#line 1325 "parser.rl" +#line 1327 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 9a1f73923..42831a4dc 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -514,6 +514,8 @@ static void raise_parse_error(const char *format, const char *start) }%% #define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack) +#define PEEK(count) rvalue_stack_peek(json->stack, count) +#define POP(count) rvalue_stack_pop(json->stack, count) static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) { @@ -534,7 +536,7 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (RB_UNLIKELY(json->object_class)) { VALUE object = rb_class_new_instance(0, 0, json->object_class); long index = 0; - VALUE *items = rvalue_stack_peek(json->stack, count); + VALUE *items = PEEK(count); while (index < count) { VALUE name = items[index++]; VALUE value = items[index++]; @@ -548,10 +550,10 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu #else hash = rb_hash_new(); #endif - rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash); + rb_hash_bulk_insert(count, PEEK(count), hash); *result = hash; } - rvalue_stack_pop(json->stack, count); + POP(count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; @@ -848,17 +850,17 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if (RB_UNLIKELY(json->array_class)) { VALUE array = rb_class_new_instance(0, 0, json->array_class); - VALUE *items = rvalue_stack_peek(json->stack, count); + VALUE *items = PEEK(count); long index; for (index = 0; index < count; index++) { rb_funcall(array, i_leftshift, 1, items[index]); } *result = array; } else { - VALUE array = rb_ary_new_from_values(count, rvalue_stack_peek(json->stack, count)); + VALUE array = rb_ary_new_from_values(count, PEEK(count)); *result = array; } - rvalue_stack_pop(json->stack, count); + POP(count); return p + 1; } else { From afefa04d9d808c54527f5ec955303b9e764865ee Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 7 Nov 2024 16:37:59 -0800 Subject: [PATCH 2/4] no pushing and popping for arrays --- ext/json/ext/parser/parser.c | 118 +++++++++++++++++----------------- ext/json/ext/parser/parser.rl | 30 ++++----- 2 files changed, 74 insertions(+), 74 deletions(-) diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index d99fd8355..06e1a7167 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -421,7 +421,7 @@ typedef struct JSON_ParserStruct { static const rb_data_type_t JSON_Parser_type; static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push); static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); @@ -599,7 +599,7 @@ case 8: tr11: #line 482 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, result, current_nesting); + char *np = JSON_parse_value(json, p, pe, result, current_nesting, true); if (np == NULL) { p--; {p++; cs = 9; goto _out;} } else { @@ -1081,7 +1081,7 @@ enum {JSON_value_en_main = 1}; #line 663 "parser.rl" -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push) { int cs = EVIL; @@ -1466,7 +1466,9 @@ case 28: } if (cs >= JSON_value_first_final) { - PUSH(*result); + if (push) { + PUSH(*result); + } return p; } else { return NULL; @@ -1474,7 +1476,7 @@ case 28: } -#line 1478 "parser.c" +#line 1480 "parser.c" enum {JSON_integer_start = 1}; enum {JSON_integer_first_final = 3}; enum {JSON_integer_error = 0}; @@ -1482,7 +1484,7 @@ enum {JSON_integer_error = 0}; enum {JSON_integer_en_main = 1}; -#line 692 "parser.rl" +#line 694 "parser.rl" #define MAX_FAST_INTEGER_SIZE 18 @@ -1522,7 +1524,7 @@ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result) } -#line 1526 "parser.c" +#line 1528 "parser.c" enum {JSON_float_start = 1}; enum {JSON_float_first_final = 6}; enum {JSON_float_error = 0}; @@ -1530,7 +1532,7 @@ enum {JSON_float_error = 0}; enum {JSON_float_en_main = 1}; -#line 744 "parser.rl" +#line 746 "parser.rl" static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1539,15 +1541,15 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu bool is_float = false; -#line 1543 "parser.c" +#line 1545 "parser.c" { cs = JSON_float_start; } -#line 752 "parser.rl" +#line 754 "parser.rl" json->memo = p; -#line 1551 "parser.c" +#line 1553 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1587,24 +1589,24 @@ case 6: goto st0; goto tr7; tr7: -#line 736 "parser.rl" +#line 738 "parser.rl" { p--; {p++; cs = 7; goto _out;} } goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 1598 "parser.c" +#line 1600 "parser.c" goto st0; tr8: -#line 737 "parser.rl" +#line 739 "parser.rl" { is_float = true; } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1608 "parser.c" +#line 1610 "parser.c" if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; @@ -1623,14 +1625,14 @@ case 8: goto st0; goto tr7; tr9: -#line 737 "parser.rl" +#line 739 "parser.rl" { is_float = true; } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: -#line 1634 "parser.c" +#line 1636 "parser.c" switch( (*p) ) { case 43: goto st5; case 45: goto st5; @@ -1687,7 +1689,7 @@ case 10: _out: {} } -#line 754 "parser.rl" +#line 756 "parser.rl" if (cs >= JSON_float_first_final) { if (!is_float) { @@ -1743,7 +1745,7 @@ case 10: -#line 1747 "parser.c" +#line 1749 "parser.c" enum {JSON_array_start = 1}; enum {JSON_array_first_final = 22}; enum {JSON_array_error = 0}; @@ -1751,7 +1753,7 @@ enum {JSON_array_error = 0}; enum {JSON_array_en_main = 1}; -#line 834 "parser.rl" +#line 837 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1761,17 +1763,19 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if (json->max_nesting && current_nesting > json->max_nesting) { rb_raise(eNestingError, "nesting of %d is too deep", current_nesting); } - long stack_head = json->stack->head; + + // speculate that it's a regular array + VALUE ary = rb_ary_new(); -#line 1768 "parser.c" +#line 1772 "parser.c" { cs = JSON_array_start; } -#line 846 "parser.rl" +#line 851 "parser.rl" -#line 1775 "parser.c" +#line 1779 "parser.c" { short _widec; if ( p == pe ) @@ -1811,13 +1815,14 @@ case 2: goto st2; goto st0; tr2: -#line 814 "parser.rl" +#line 816 "parser.rl" { VALUE v = Qnil; - char *np = JSON_parse_value(json, p, pe, &v, current_nesting); + char *np = JSON_parse_value(json, p, pe, &v, current_nesting, false); if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { + rb_ary_push(ary, v); {p = (( np))-1;} } } @@ -1826,12 +1831,12 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1830 "parser.c" +#line 1835 "parser.c" _widec = (*p); if ( 44 <= (*p) && (*p) <= 44 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1878,14 +1883,14 @@ case 7: goto st3; goto st7; tr4: -#line 826 "parser.rl" +#line 829 "parser.rl" { p--; {p++; cs = 22; goto _out;} } goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: -#line 1889 "parser.c" +#line 1894 "parser.c" goto st0; st8: if ( ++p == pe ) @@ -1953,13 +1958,13 @@ case 13: if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -1967,19 +1972,19 @@ case 13: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2018,13 +2023,13 @@ case 14: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2043,20 +2048,20 @@ case 15: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 42 ) { if ( 43 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2079,13 +2084,13 @@ case 16: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -2093,19 +2098,19 @@ case 16: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2129,20 +2134,20 @@ case 17: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 10 ) { if ( 11 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 824 "parser.rl" +#line 827 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2214,24 +2219,19 @@ case 21: _out: {} } -#line 847 "parser.rl" +#line 852 "parser.rl" if(cs >= JSON_array_first_final) { - long count = json->stack->head - stack_head; - if (RB_UNLIKELY(json->array_class)) { VALUE array = rb_class_new_instance(0, 0, json->array_class); - VALUE *items = PEEK(count); long index; - for (index = 0; index < count; index++) { - rb_funcall(array, i_leftshift, 1, items[index]); + for (index = 0; index < RARRAY_LEN(ary); index++) { + rb_funcall(array, i_leftshift, 1, rb_ary_entry(ary, index)); } *result = array; } else { - VALUE array = rb_ary_new_from_values(count, PEEK(count)); - *result = array; + *result = ary; } - POP(count); return p + 1; } else { @@ -2821,7 +2821,7 @@ cs = 0; tr2: #line 1250 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, &result, 0); + char *np = JSON_parse_value(json, p, pe, &result, 0, false); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; @@ -2999,7 +2999,7 @@ cs = 0; tr2: #line 1250 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, &result, 0); + char *np = JSON_parse_value(json, p, pe, &result, 0, false); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 42831a4dc..08ff7a321 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -419,7 +419,7 @@ typedef struct JSON_ParserStruct { static const rb_data_type_t JSON_Parser_type; static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push); static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); @@ -480,7 +480,7 @@ static void raise_parse_error(const char *format, const char *start) write data; action parse_value { - char *np = JSON_parse_value(json, fpc, pe, result, current_nesting); + char *np = JSON_parse_value(json, fpc, pe, result, current_nesting, true); if (np == NULL) { fhold; fbreak; } else { @@ -662,7 +662,7 @@ main := ignore* ( ) ignore* %*exit; }%% -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push) { int cs = EVIL; @@ -674,7 +674,9 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul } if (cs >= JSON_value_first_final) { - PUSH(*result); + if (push) { + PUSH(*result); + } return p; } else { return NULL; @@ -813,10 +815,11 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu action parse_value { VALUE v = Qnil; - char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting); + char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting, false); if (np == NULL) { fhold; fbreak; } else { + rb_ary_push(ary, v); fexec np; } } @@ -840,27 +843,24 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul if (json->max_nesting && current_nesting > json->max_nesting) { rb_raise(eNestingError, "nesting of %d is too deep", current_nesting); } - long stack_head = json->stack->head; + + // speculate that it's a regular array + VALUE ary = rb_ary_new(); %% write init; %% write exec; if(cs >= JSON_array_first_final) { - long count = json->stack->head - stack_head; - if (RB_UNLIKELY(json->array_class)) { VALUE array = rb_class_new_instance(0, 0, json->array_class); - VALUE *items = PEEK(count); long index; - for (index = 0; index < count; index++) { - rb_funcall(array, i_leftshift, 1, items[index]); + for (index = 0; index < RARRAY_LEN(ary); index++) { + rb_funcall(array, i_leftshift, 1, rb_ary_entry(ary, index)); } *result = array; } else { - VALUE array = rb_ary_new_from_values(count, PEEK(count)); - *result = array; + *result = ary; } - POP(count); return p + 1; } else { @@ -1248,7 +1248,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) include JSON_common; action parse_value { - char *np = JSON_parse_value(json, fpc, pe, &result, 0); + char *np = JSON_parse_value(json, fpc, pe, &result, 0, false); if (np == NULL) { fhold; fbreak; } else fexec np; } From adec7cec71e7951b630707b50e261901b00561b8 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 7 Nov 2024 16:55:40 -0800 Subject: [PATCH 3/4] no push pop for hash --- ext/json/ext/parser/parser.c | 253 ++++++++++++++++------------------ ext/json/ext/parser/parser.rl | 27 ++-- lib/json.rb | 8 ++ 3 files changed, 139 insertions(+), 149 deletions(-) diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 06e1a7167..75ff68b92 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -460,7 +460,7 @@ enum {JSON_object_error = 0}; enum {JSON_object_en_main = 1}; -#line 514 "parser.rl" +#line 515 "parser.rl" #define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack) @@ -475,17 +475,21 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu rb_raise(eNestingError, "nesting of %d is too deep", current_nesting); } + // speculate we are parsing a hash + VALUE hash = rb_hash_new(); + VALUE key = Qnil; + long stack_head = json->stack->head; -#line 482 "parser.c" +#line 486 "parser.c" { cs = JSON_object_start; } -#line 531 "parser.rl" +#line 536 "parser.rl" -#line 489 "parser.c" +#line 493 "parser.c" { short _widec; if ( p == pe ) @@ -514,14 +518,13 @@ case 2: goto st2; goto st0; tr2: -#line 493 "parser.rl" +#line 495 "parser.rl" { char *np; json->parsing_name = true; - np = JSON_parse_string(json, p, pe, result); + np = JSON_parse_string(json, p, pe, &key); json->parsing_name = false; if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { - PUSH(*result); {p = (( np))-1;} } } @@ -530,7 +533,7 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 534 "parser.c" +#line 537 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -599,10 +602,12 @@ case 8: tr11: #line 482 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, result, current_nesting, true); + VALUE val; + char *np = JSON_parse_value(json, p, pe, &val, current_nesting, true); if (np == NULL) { p--; {p++; cs = 9; goto _out;} } else { + rb_hash_aset(hash, key, val); {p = (( np))-1;} } } @@ -611,20 +616,20 @@ case 8: if ( ++p == pe ) goto _test_eof9; case 9: -#line 615 "parser.c" +#line 620 "parser.c" _widec = (*p); if ( (*p) < 13 ) { if ( (*p) > 9 ) { if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -632,26 +637,26 @@ case 9: if ( 32 <= (*p) && (*p) <= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 44 ) { if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -672,14 +677,14 @@ case 9: goto st10; goto st0; tr4: -#line 504 "parser.rl" +#line 505 "parser.rl" { p--; {p++; cs = 32; goto _out;} } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 683 "parser.c" +#line 688 "parser.c" goto st0; st10: if ( ++p == pe ) @@ -781,13 +786,13 @@ case 20: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -806,20 +811,20 @@ case 21: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 42 ) { if ( 43 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -842,13 +847,13 @@ case 22: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -856,19 +861,19 @@ case 22: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -892,20 +897,20 @@ case 23: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 10 ) { if ( 11 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 493 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1019,32 +1024,18 @@ case 31: _out: {} } -#line 532 "parser.rl" +#line 537 "parser.rl" if (cs >= JSON_object_first_final) { long count = json->stack->head - stack_head; if (RB_UNLIKELY(json->object_class)) { VALUE object = rb_class_new_instance(0, 0, json->object_class); - long index = 0; - VALUE *items = PEEK(count); - while (index < count) { - VALUE name = items[index++]; - VALUE value = items[index++]; - rb_funcall(object, i_aset, 2, name, value); - } + rb_funcall(cParser, rb_intern("convert_hash"), 2, hash, object); *result = object; } else { - VALUE hash; -#ifdef HAVE_RB_HASH_NEW_CAPA - hash = rb_hash_new_capa(count >> 1); -#else - hash = rb_hash_new(); -#endif - rb_hash_bulk_insert(count, PEEK(count), hash); *result = hash; } - POP(count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; @@ -1070,7 +1061,7 @@ case 31: } -#line 1074 "parser.c" +#line 1065 "parser.c" enum {JSON_value_start = 1}; enum {JSON_value_first_final = 29}; enum {JSON_value_error = 0}; @@ -1078,7 +1069,7 @@ enum {JSON_value_error = 0}; enum {JSON_value_en_main = 1}; -#line 663 "parser.rl" +#line 654 "parser.rl" static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push) @@ -1086,14 +1077,14 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 1090 "parser.c" +#line 1081 "parser.c" { cs = JSON_value_start; } -#line 670 "parser.rl" +#line 661 "parser.rl" -#line 1097 "parser.c" +#line 1088 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1127,7 +1118,7 @@ case 1: cs = 0; goto _out; tr2: -#line 610 "parser.rl" +#line 601 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); if (np == NULL) { @@ -1139,7 +1130,7 @@ cs = 0; } goto st29; tr3: -#line 620 "parser.rl" +#line 611 "parser.rl" { char *np; if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) { @@ -1159,7 +1150,7 @@ cs = 0; } goto st29; tr7: -#line 638 "parser.rl" +#line 629 "parser.rl" { char *np; np = JSON_parse_array(json, p, pe, result, current_nesting + 1); @@ -1167,7 +1158,7 @@ cs = 0; } goto st29; tr11: -#line 644 "parser.rl" +#line 635 "parser.rl" { char *np; np = JSON_parse_object(json, p, pe, result, current_nesting + 1); @@ -1175,7 +1166,7 @@ cs = 0; } goto st29; tr25: -#line 603 "parser.rl" +#line 594 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -1185,7 +1176,7 @@ cs = 0; } goto st29; tr27: -#line 596 "parser.rl" +#line 587 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -1195,19 +1186,19 @@ cs = 0; } goto st29; tr31: -#line 590 "parser.rl" +#line 581 "parser.rl" { *result = Qfalse; } goto st29; tr34: -#line 587 "parser.rl" +#line 578 "parser.rl" { *result = Qnil; } goto st29; tr37: -#line 593 "parser.rl" +#line 584 "parser.rl" { *result = Qtrue; } @@ -1216,9 +1207,9 @@ cs = 0; if ( ++p == pe ) goto _test_eof29; case 29: -#line 650 "parser.rl" +#line 641 "parser.rl" { p--; {p++; cs = 29; goto _out;} } -#line 1222 "parser.c" +#line 1213 "parser.c" switch( (*p) ) { case 13: goto st29; case 32: goto st29; @@ -1459,7 +1450,7 @@ case 28: _out: {} } -#line 671 "parser.rl" +#line 662 "parser.rl" if (json->freeze) { OBJ_FREEZE(*result); @@ -1476,7 +1467,7 @@ case 28: } -#line 1480 "parser.c" +#line 1471 "parser.c" enum {JSON_integer_start = 1}; enum {JSON_integer_first_final = 3}; enum {JSON_integer_error = 0}; @@ -1484,7 +1475,7 @@ enum {JSON_integer_error = 0}; enum {JSON_integer_en_main = 1}; -#line 694 "parser.rl" +#line 685 "parser.rl" #define MAX_FAST_INTEGER_SIZE 18 @@ -1524,7 +1515,7 @@ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result) } -#line 1528 "parser.c" +#line 1519 "parser.c" enum {JSON_float_start = 1}; enum {JSON_float_first_final = 6}; enum {JSON_float_error = 0}; @@ -1532,7 +1523,7 @@ enum {JSON_float_error = 0}; enum {JSON_float_en_main = 1}; -#line 746 "parser.rl" +#line 737 "parser.rl" static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1541,15 +1532,15 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu bool is_float = false; -#line 1545 "parser.c" +#line 1536 "parser.c" { cs = JSON_float_start; } -#line 754 "parser.rl" +#line 745 "parser.rl" json->memo = p; -#line 1553 "parser.c" +#line 1544 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1589,24 +1580,24 @@ case 6: goto st0; goto tr7; tr7: -#line 738 "parser.rl" +#line 729 "parser.rl" { p--; {p++; cs = 7; goto _out;} } goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 1600 "parser.c" +#line 1591 "parser.c" goto st0; tr8: -#line 739 "parser.rl" +#line 730 "parser.rl" { is_float = true; } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1610 "parser.c" +#line 1601 "parser.c" if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; @@ -1625,14 +1616,14 @@ case 8: goto st0; goto tr7; tr9: -#line 739 "parser.rl" +#line 730 "parser.rl" { is_float = true; } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: -#line 1636 "parser.c" +#line 1627 "parser.c" switch( (*p) ) { case 43: goto st5; case 45: goto st5; @@ -1689,7 +1680,7 @@ case 10: _out: {} } -#line 756 "parser.rl" +#line 747 "parser.rl" if (cs >= JSON_float_first_final) { if (!is_float) { @@ -1745,7 +1736,7 @@ case 10: -#line 1749 "parser.c" +#line 1740 "parser.c" enum {JSON_array_start = 1}; enum {JSON_array_first_final = 22}; enum {JSON_array_error = 0}; @@ -1753,7 +1744,7 @@ enum {JSON_array_error = 0}; enum {JSON_array_en_main = 1}; -#line 837 "parser.rl" +#line 828 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1768,14 +1759,14 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul VALUE ary = rb_ary_new(); -#line 1772 "parser.c" +#line 1763 "parser.c" { cs = JSON_array_start; } -#line 851 "parser.rl" +#line 842 "parser.rl" -#line 1779 "parser.c" +#line 1770 "parser.c" { short _widec; if ( p == pe ) @@ -1815,7 +1806,7 @@ case 2: goto st2; goto st0; tr2: -#line 816 "parser.rl" +#line 807 "parser.rl" { VALUE v = Qnil; char *np = JSON_parse_value(json, p, pe, &v, current_nesting, false); @@ -1831,12 +1822,12 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1835 "parser.c" +#line 1826 "parser.c" _widec = (*p); if ( 44 <= (*p) && (*p) <= 44 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1883,14 +1874,14 @@ case 7: goto st3; goto st7; tr4: -#line 829 "parser.rl" +#line 820 "parser.rl" { p--; {p++; cs = 22; goto _out;} } goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: -#line 1894 "parser.c" +#line 1885 "parser.c" goto st0; st8: if ( ++p == pe ) @@ -1958,13 +1949,13 @@ case 13: if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -1972,19 +1963,19 @@ case 13: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2023,13 +2014,13 @@ case 14: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2048,20 +2039,20 @@ case 15: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 42 ) { if ( 43 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2084,13 +2075,13 @@ case 16: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -2098,19 +2089,19 @@ case 16: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2134,20 +2125,20 @@ case 17: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 10 ) { if ( 11 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 827 "parser.rl" +#line 818 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2219,7 +2210,7 @@ case 21: _out: {} } -#line 852 "parser.rl" +#line 843 "parser.rl" if(cs >= JSON_array_first_final) { if (RB_UNLIKELY(json->array_class)) { @@ -2408,7 +2399,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE } -#line 2412 "parser.c" +#line 2403 "parser.c" enum {JSON_string_start = 1}; enum {JSON_string_first_final = 9}; enum {JSON_string_error = 0}; @@ -2416,7 +2407,7 @@ enum {JSON_string_error = 0}; enum {JSON_string_en_main = 1}; -#line 1070 "parser.rl" +#line 1061 "parser.rl" static int @@ -2437,15 +2428,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu VALUE match_string; -#line 2441 "parser.c" +#line 2432 "parser.c" { cs = JSON_string_start; } -#line 1090 "parser.rl" +#line 1081 "parser.rl" json->memo = p; -#line 2449 "parser.c" +#line 2440 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2470,14 +2461,14 @@ case 2: goto st0; goto st2; tr2: -#line 1052 "parser.rl" +#line 1043 "parser.rl" { *result = json_string_fastpath(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} p--; {p++; cs = 9; goto _out;} } -#line 1045 "parser.rl" +#line 1036 "parser.rl" { *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} @@ -2486,7 +2477,7 @@ case 2: } goto st9; tr6: -#line 1045 "parser.rl" +#line 1036 "parser.rl" { *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} @@ -2498,7 +2489,7 @@ case 2: if ( ++p == pe ) goto _test_eof9; case 9: -#line 2502 "parser.c" +#line 2493 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -2586,7 +2577,7 @@ case 8: _out: {} } -#line 1092 "parser.rl" +#line 1083 "parser.rl" if (json->create_additions && RTEST(match_string = json->match_string)) { VALUE klass; @@ -2739,7 +2730,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 2743 "parser.c" +#line 2734 "parser.c" enum {JSON_start = 1}; enum {JSON_first_final = 10}; enum {JSON_error = 0}; @@ -2747,7 +2738,7 @@ enum {JSON_error = 0}; enum {JSON_en_main = 1}; -#line 1258 "parser.rl" +#line 1249 "parser.rl" /* @@ -2776,16 +2767,16 @@ static VALUE cParser_parse(VALUE self) json->stack = &stack; -#line 2780 "parser.c" +#line 2771 "parser.c" { cs = JSON_start; } -#line 1286 "parser.rl" +#line 1277 "parser.rl" p = json->source; pe = p + json->len; -#line 2789 "parser.c" +#line 2780 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2819,7 +2810,7 @@ case 1: cs = 0; goto _out; tr2: -#line 1250 "parser.rl" +#line 1241 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result, 0, false); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -2829,7 +2820,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 2833 "parser.c" +#line 2824 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2918,7 +2909,7 @@ case 9: _out: {} } -#line 1289 "parser.rl" +#line 1280 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); @@ -2954,16 +2945,16 @@ static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts) json->stack = &stack; -#line 2958 "parser.c" +#line 2949 "parser.c" { cs = JSON_start; } -#line 1324 "parser.rl" +#line 1315 "parser.rl" p = json->source; pe = p + json->len; -#line 2967 "parser.c" +#line 2958 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2997,7 +2988,7 @@ case 1: cs = 0; goto _out; tr2: -#line 1250 "parser.rl" +#line 1241 "parser.rl" { char *np = JSON_parse_value(json, p, pe, &result, 0, false); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} @@ -3007,7 +2998,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 3011 "parser.c" +#line 3002 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -3096,7 +3087,7 @@ case 9: _out: {} } -#line 1327 "parser.rl" +#line 1318 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index 08ff7a321..bac5e263c 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -480,10 +480,12 @@ static void raise_parse_error(const char *format, const char *start) write data; action parse_value { - char *np = JSON_parse_value(json, fpc, pe, result, current_nesting, true); + VALUE val; + char *np = JSON_parse_value(json, fpc, pe, &val, current_nesting, true); if (np == NULL) { fhold; fbreak; } else { + rb_hash_aset(hash, key, val); fexec np; } } @@ -493,10 +495,9 @@ static void raise_parse_error(const char *format, const char *start) action parse_name { char *np; json->parsing_name = true; - np = JSON_parse_string(json, fpc, pe, result); + np = JSON_parse_string(json, fpc, pe, &key); json->parsing_name = false; if (np == NULL) { fhold; fbreak; } else { - PUSH(*result); fexec np; } } @@ -525,6 +526,10 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu rb_raise(eNestingError, "nesting of %d is too deep", current_nesting); } + // speculate we are parsing a hash + VALUE hash = rb_hash_new(); + VALUE key = Qnil; + long stack_head = json->stack->head; %% write init; @@ -535,25 +540,11 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (RB_UNLIKELY(json->object_class)) { VALUE object = rb_class_new_instance(0, 0, json->object_class); - long index = 0; - VALUE *items = PEEK(count); - while (index < count) { - VALUE name = items[index++]; - VALUE value = items[index++]; - rb_funcall(object, i_aset, 2, name, value); - } + rb_funcall(cParser, rb_intern("convert_hash"), 2, hash, object); *result = object; } else { - VALUE hash; -#ifdef HAVE_RB_HASH_NEW_CAPA - hash = rb_hash_new_capa(count >> 1); -#else - hash = rb_hash_new(); -#endif - rb_hash_bulk_insert(count, PEEK(count), hash); *result = hash; } - POP(count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; diff --git a/lib/json.rb b/lib/json.rb index dfd9b7dfc..7dabfa928 100644 --- a/lib/json.rb +++ b/lib/json.rb @@ -584,4 +584,12 @@ module JSON require 'json/version' require 'json/ext' + + class Parser + def self.convert_hash(from, to) # :nodoc: + from.each_pair { |k,v| to[k] = v } + to + end + private_class_method :convert_hash + end end From 816220377440098d4393fc0e97a684f736bac4c6 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Fri, 8 Nov 2024 07:32:07 -0800 Subject: [PATCH 4/4] add stack based cache --- ext/json/ext/parser/parser.c | 321 ++++++++++++++++++---------------- ext/json/ext/parser/parser.rl | 93 ++++++---- 2 files changed, 234 insertions(+), 180 deletions(-) diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 75ff68b92..baac2b554 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -421,7 +421,7 @@ typedef struct JSON_ParserStruct { static const rb_data_type_t JSON_Parser_type; static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push); +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); @@ -460,7 +460,7 @@ enum {JSON_object_error = 0}; enum {JSON_object_en_main = 1}; -#line 515 "parser.rl" +#line 527 "parser.rl" #define PUSH(result) rvalue_stack_push(json->stack, result, &json->stack_handle, &json->stack) @@ -475,21 +475,23 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu rb_raise(eNestingError, "nesting of %d is too deep", current_nesting); } + VALUE cache[20]; + unsigned int cache_count = 0; // speculate we are parsing a hash - VALUE hash = rb_hash_new(); + VALUE hash = 0; VALUE key = Qnil; long stack_head = json->stack->head; -#line 486 "parser.c" +#line 488 "parser.c" { cs = JSON_object_start; } -#line 536 "parser.rl" +#line 550 "parser.rl" -#line 493 "parser.c" +#line 495 "parser.c" { short _widec; if ( p == pe ) @@ -518,11 +520,12 @@ case 2: goto st2; goto st0; tr2: -#line 495 "parser.rl" +#line 506 "parser.rl" { char *np; json->parsing_name = true; - np = JSON_parse_string(json, p, pe, &key); + np = JSON_parse_string(json, p, pe, &cache[cache_count]); + cache_count++; json->parsing_name = false; if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { {p = (( np))-1;} @@ -533,7 +536,7 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 537 "parser.c" +#line 540 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -603,11 +606,22 @@ case 8: #line 482 "parser.rl" { VALUE val; - char *np = JSON_parse_value(json, p, pe, &val, current_nesting, true); + char *np = JSON_parse_value(json, p, pe, &cache[cache_count], current_nesting); if (np == NULL) { p--; {p++; cs = 9; goto _out;} } else { - rb_hash_aset(hash, key, val); + cache_count++; + if (cache_count == 20) { + if (!hash) { +#ifdef HAVE_RB_HASH_NEW_CAPA + hash = rb_hash_new_capa(20); +#else + hash = rb_hash_new(); +#endif + } + rb_hash_bulk_insert(20, cache, hash); + cache_count = 0; + } {p = (( np))-1;} } } @@ -616,20 +630,20 @@ case 8: if ( ++p == pe ) goto _test_eof9; case 9: -#line 620 "parser.c" +#line 634 "parser.c" _widec = (*p); if ( (*p) < 13 ) { if ( (*p) > 9 ) { if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -637,26 +651,26 @@ case 9: if ( 32 <= (*p) && (*p) <= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 44 ) { if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -677,14 +691,14 @@ case 9: goto st10; goto st0; tr4: -#line 505 "parser.rl" +#line 517 "parser.rl" { p--; {p++; cs = 32; goto _out;} } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 688 "parser.c" +#line 702 "parser.c" goto st0; st10: if ( ++p == pe ) @@ -786,13 +800,13 @@ case 20: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -811,20 +825,20 @@ case 21: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 42 ) { if ( 43 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -847,13 +861,13 @@ case 22: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -861,19 +875,19 @@ case 22: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -897,20 +911,20 @@ case 23: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 10 ) { if ( 11 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 493 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1024,11 +1038,24 @@ case 31: _out: {} } -#line 537 "parser.rl" +#line 551 "parser.rl" if (cs >= JSON_object_first_final) { long count = json->stack->head - stack_head; + if (!hash) { +#ifdef HAVE_RB_HASH_NEW_CAPA + hash = rb_hash_new_capa(cache_count); +#else + hash = rb_hash_new(); +#endif + } + + if (cache_count > 0) { + rb_hash_bulk_insert(cache_count, cache, hash); + cache_count = 0; + } + if (RB_UNLIKELY(json->object_class)) { VALUE object = rb_class_new_instance(0, 0, json->object_class); rb_funcall(cParser, rb_intern("convert_hash"), 2, hash, object); @@ -1061,7 +1088,7 @@ case 31: } -#line 1065 "parser.c" +#line 1092 "parser.c" enum {JSON_value_start = 1}; enum {JSON_value_first_final = 29}; enum {JSON_value_error = 0}; @@ -1069,22 +1096,22 @@ enum {JSON_value_error = 0}; enum {JSON_value_en_main = 1}; -#line 654 "parser.rl" +#line 681 "parser.rl" -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push) +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) { int cs = EVIL; -#line 1081 "parser.c" +#line 1108 "parser.c" { cs = JSON_value_start; } -#line 661 "parser.rl" +#line 688 "parser.rl" -#line 1088 "parser.c" +#line 1115 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1118,7 +1145,7 @@ case 1: cs = 0; goto _out; tr2: -#line 601 "parser.rl" +#line 628 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); if (np == NULL) { @@ -1130,7 +1157,7 @@ cs = 0; } goto st29; tr3: -#line 611 "parser.rl" +#line 638 "parser.rl" { char *np; if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) { @@ -1150,7 +1177,7 @@ cs = 0; } goto st29; tr7: -#line 629 "parser.rl" +#line 656 "parser.rl" { char *np; np = JSON_parse_array(json, p, pe, result, current_nesting + 1); @@ -1158,7 +1185,7 @@ cs = 0; } goto st29; tr11: -#line 635 "parser.rl" +#line 662 "parser.rl" { char *np; np = JSON_parse_object(json, p, pe, result, current_nesting + 1); @@ -1166,7 +1193,7 @@ cs = 0; } goto st29; tr25: -#line 594 "parser.rl" +#line 621 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -1176,7 +1203,7 @@ cs = 0; } goto st29; tr27: -#line 587 "parser.rl" +#line 614 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -1186,19 +1213,19 @@ cs = 0; } goto st29; tr31: -#line 581 "parser.rl" +#line 608 "parser.rl" { *result = Qfalse; } goto st29; tr34: -#line 578 "parser.rl" +#line 605 "parser.rl" { *result = Qnil; } goto st29; tr37: -#line 584 "parser.rl" +#line 611 "parser.rl" { *result = Qtrue; } @@ -1207,9 +1234,9 @@ cs = 0; if ( ++p == pe ) goto _test_eof29; case 29: -#line 641 "parser.rl" +#line 668 "parser.rl" { p--; {p++; cs = 29; goto _out;} } -#line 1213 "parser.c" +#line 1240 "parser.c" switch( (*p) ) { case 13: goto st29; case 32: goto st29; @@ -1450,16 +1477,13 @@ case 28: _out: {} } -#line 662 "parser.rl" +#line 689 "parser.rl" if (json->freeze) { OBJ_FREEZE(*result); } if (cs >= JSON_value_first_final) { - if (push) { - PUSH(*result); - } return p; } else { return NULL; @@ -1467,7 +1491,7 @@ case 28: } -#line 1471 "parser.c" +#line 1495 "parser.c" enum {JSON_integer_start = 1}; enum {JSON_integer_first_final = 3}; enum {JSON_integer_error = 0}; @@ -1475,7 +1499,7 @@ enum {JSON_integer_error = 0}; enum {JSON_integer_en_main = 1}; -#line 685 "parser.rl" +#line 709 "parser.rl" #define MAX_FAST_INTEGER_SIZE 18 @@ -1515,7 +1539,7 @@ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result) } -#line 1519 "parser.c" +#line 1543 "parser.c" enum {JSON_float_start = 1}; enum {JSON_float_first_final = 6}; enum {JSON_float_error = 0}; @@ -1523,7 +1547,7 @@ enum {JSON_float_error = 0}; enum {JSON_float_en_main = 1}; -#line 737 "parser.rl" +#line 761 "parser.rl" static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1532,15 +1556,15 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu bool is_float = false; -#line 1536 "parser.c" +#line 1560 "parser.c" { cs = JSON_float_start; } -#line 745 "parser.rl" +#line 769 "parser.rl" json->memo = p; -#line 1544 "parser.c" +#line 1568 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1580,24 +1604,24 @@ case 6: goto st0; goto tr7; tr7: -#line 729 "parser.rl" +#line 753 "parser.rl" { p--; {p++; cs = 7; goto _out;} } goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 1591 "parser.c" +#line 1615 "parser.c" goto st0; tr8: -#line 730 "parser.rl" +#line 754 "parser.rl" { is_float = true; } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1601 "parser.c" +#line 1625 "parser.c" if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; @@ -1616,14 +1640,14 @@ case 8: goto st0; goto tr7; tr9: -#line 730 "parser.rl" +#line 754 "parser.rl" { is_float = true; } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: -#line 1627 "parser.c" +#line 1651 "parser.c" switch( (*p) ) { case 43: goto st5; case 45: goto st5; @@ -1680,7 +1704,7 @@ case 10: _out: {} } -#line 747 "parser.rl" +#line 771 "parser.rl" if (cs >= JSON_float_first_final) { if (!is_float) { @@ -1736,7 +1760,7 @@ case 10: -#line 1740 "parser.c" +#line 1764 "parser.c" enum {JSON_array_start = 1}; enum {JSON_array_first_final = 22}; enum {JSON_array_error = 0}; @@ -1744,7 +1768,7 @@ enum {JSON_array_error = 0}; enum {JSON_array_en_main = 1}; -#line 828 "parser.rl" +#line 861 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1756,17 +1780,19 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul } // speculate that it's a regular array - VALUE ary = rb_ary_new(); + VALUE cache[20]; + unsigned int cache_count = 0; + VALUE ary = 0; -#line 1763 "parser.c" +#line 1789 "parser.c" { cs = JSON_array_start; } -#line 842 "parser.rl" +#line 877 "parser.rl" -#line 1770 "parser.c" +#line 1796 "parser.c" { short _widec; if ( p == pe ) @@ -1806,14 +1832,23 @@ case 2: goto st2; goto st0; tr2: -#line 807 "parser.rl" +#line 831 "parser.rl" { - VALUE v = Qnil; - char *np = JSON_parse_value(json, p, pe, &v, current_nesting, false); + char *np = JSON_parse_value(json, p, pe, &cache[cache_count], current_nesting); if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { - rb_ary_push(ary, v); + cache_count++; + if (cache_count == 20) { + if (!ary) { + ary = rb_ary_new_from_values(cache_count, cache); + cache_count = 0; + } + else { + rb_ary_concat(ary, rb_ary_new_from_values(cache_count, cache)); + cache_count = 0; + } + } {p = (( np))-1;} } } @@ -1822,12 +1857,12 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1826 "parser.c" +#line 1861 "parser.c" _widec = (*p); if ( 44 <= (*p) && (*p) <= 44 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1874,14 +1909,14 @@ case 7: goto st3; goto st7; tr4: -#line 820 "parser.rl" +#line 853 "parser.rl" { p--; {p++; cs = 22; goto _out;} } goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: -#line 1885 "parser.c" +#line 1920 "parser.c" goto st0; st8: if ( ++p == pe ) @@ -1949,13 +1984,13 @@ case 13: if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -1963,19 +1998,19 @@ case 13: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2014,13 +2049,13 @@ case 14: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2039,20 +2074,20 @@ case 15: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 42 ) { if ( 43 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2075,13 +2110,13 @@ case 16: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -2089,19 +2124,19 @@ case 16: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2125,20 +2160,20 @@ case 17: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 10 ) { if ( 11 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 818 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2210,9 +2245,20 @@ case 21: _out: {} } -#line 843 "parser.rl" +#line 878 "parser.rl" if(cs >= JSON_array_first_final) { + if (!ary) { + ary = rb_ary_new_from_values(cache_count, cache); + cache_count = 0; + } + else { + if (cache_count > 0) { + rb_ary_concat(ary, rb_ary_new_from_values(cache_count, cache)); + cache_count = 0; + } + } + if (RB_UNLIKELY(json->array_class)) { VALUE array = rb_class_new_instance(0, 0, json->array_class); long index; @@ -2399,7 +2445,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE } -#line 2403 "parser.c" +#line 2449 "parser.c" enum {JSON_string_start = 1}; enum {JSON_string_first_final = 9}; enum {JSON_string_error = 0}; @@ -2407,7 +2453,7 @@ enum {JSON_string_error = 0}; enum {JSON_string_en_main = 1}; -#line 1061 "parser.rl" +#line 1107 "parser.rl" static int @@ -2428,15 +2474,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu VALUE match_string; -#line 2432 "parser.c" +#line 2478 "parser.c" { cs = JSON_string_start; } -#line 1081 "parser.rl" +#line 1127 "parser.rl" json->memo = p; -#line 2440 "parser.c" +#line 2486 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2461,14 +2507,14 @@ case 2: goto st0; goto st2; tr2: -#line 1043 "parser.rl" +#line 1089 "parser.rl" { *result = json_string_fastpath(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} p--; {p++; cs = 9; goto _out;} } -#line 1036 "parser.rl" +#line 1082 "parser.rl" { *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} @@ -2477,7 +2523,7 @@ case 2: } goto st9; tr6: -#line 1036 "parser.rl" +#line 1082 "parser.rl" { *result = json_string_unescape(json, json->memo + 1, p, json->parsing_name, json->parsing_name || json-> freeze, json->parsing_name && json->symbolize_names); {p = (( p + 1))-1;} @@ -2489,7 +2535,7 @@ case 2: if ( ++p == pe ) goto _test_eof9; case 9: -#line 2493 "parser.c" +#line 2539 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -2577,7 +2623,7 @@ case 8: _out: {} } -#line 1083 "parser.rl" +#line 1129 "parser.rl" if (json->create_additions && RTEST(match_string = json->match_string)) { VALUE klass; @@ -2730,7 +2776,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 2734 "parser.c" +#line 2780 "parser.c" enum {JSON_start = 1}; enum {JSON_first_final = 10}; enum {JSON_error = 0}; @@ -2738,7 +2784,7 @@ enum {JSON_error = 0}; enum {JSON_en_main = 1}; -#line 1249 "parser.rl" +#line 1295 "parser.rl" /* @@ -2755,28 +2801,17 @@ static VALUE cParser_parse(VALUE self) VALUE result = Qnil; GET_PARSER; - char stack_buffer[FBUFFER_STACK_SIZE]; - fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE); - - VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA]; - rvalue_stack stack = { - .type = RVALUE_STACK_STACK_ALLOCATED, - .ptr = rvalue_stack_buffer, - .capa = RVALUE_STACK_INITIAL_CAPA, - }; - json->stack = &stack; - -#line 2771 "parser.c" +#line 2806 "parser.c" { cs = JSON_start; } -#line 1277 "parser.rl" +#line 1312 "parser.rl" p = json->source; pe = p + json->len; -#line 2780 "parser.c" +#line 2815 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2810,9 +2845,9 @@ case 1: cs = 0; goto _out; tr2: -#line 1241 "parser.rl" +#line 1287 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, &result, 0, false); + char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; @@ -2820,7 +2855,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 2824 "parser.c" +#line 2859 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2909,7 +2944,7 @@ case 9: _out: {} } -#line 1280 "parser.rl" +#line 1315 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); @@ -2936,25 +2971,17 @@ static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts) char stack_buffer[FBUFFER_STACK_SIZE]; fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE); - VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA]; - rvalue_stack stack = { - .type = RVALUE_STACK_STACK_ALLOCATED, - .ptr = rvalue_stack_buffer, - .capa = RVALUE_STACK_INITIAL_CAPA, - }; - json->stack = &stack; - -#line 2949 "parser.c" +#line 2976 "parser.c" { cs = JSON_start; } -#line 1315 "parser.rl" +#line 1342 "parser.rl" p = json->source; pe = p + json->len; -#line 2958 "parser.c" +#line 2985 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2988,9 +3015,9 @@ case 1: cs = 0; goto _out; tr2: -#line 1241 "parser.rl" +#line 1287 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, &result, 0, false); + char *np = JSON_parse_value(json, p, pe, &result, 0); if (np == NULL) { p--; {p++; cs = 10; goto _out;} } else {p = (( np))-1;} } goto st10; @@ -2998,7 +3025,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 3002 "parser.c" +#line 3029 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -3087,7 +3114,7 @@ case 9: _out: {} } -#line 1318 "parser.rl" +#line 1345 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); diff --git a/ext/json/ext/parser/parser.rl b/ext/json/ext/parser/parser.rl index bac5e263c..00d13e4c9 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -419,7 +419,7 @@ typedef struct JSON_ParserStruct { static const rb_data_type_t JSON_Parser_type; static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push); +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result); static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting); @@ -481,11 +481,22 @@ static void raise_parse_error(const char *format, const char *start) action parse_value { VALUE val; - char *np = JSON_parse_value(json, fpc, pe, &val, current_nesting, true); + char *np = JSON_parse_value(json, fpc, pe, &cache[cache_count], current_nesting); if (np == NULL) { fhold; fbreak; } else { - rb_hash_aset(hash, key, val); + cache_count++; + if (cache_count == 20) { + if (!hash) { +#ifdef HAVE_RB_HASH_NEW_CAPA + hash = rb_hash_new_capa(20); +#else + hash = rb_hash_new(); +#endif + } + rb_hash_bulk_insert(20, cache, hash); + cache_count = 0; + } fexec np; } } @@ -495,7 +506,8 @@ static void raise_parse_error(const char *format, const char *start) action parse_name { char *np; json->parsing_name = true; - np = JSON_parse_string(json, fpc, pe, &key); + np = JSON_parse_string(json, fpc, pe, &cache[cache_count]); + cache_count++; json->parsing_name = false; if (np == NULL) { fhold; fbreak; } else { fexec np; @@ -526,8 +538,10 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu rb_raise(eNestingError, "nesting of %d is too deep", current_nesting); } + VALUE cache[20]; + unsigned int cache_count = 0; // speculate we are parsing a hash - VALUE hash = rb_hash_new(); + VALUE hash = 0; VALUE key = Qnil; long stack_head = json->stack->head; @@ -538,6 +552,19 @@ static char *JSON_parse_object(JSON_Parser *json, char *p, char *pe, VALUE *resu if (cs >= JSON_object_first_final) { long count = json->stack->head - stack_head; + if (!hash) { +#ifdef HAVE_RB_HASH_NEW_CAPA + hash = rb_hash_new_capa(cache_count); +#else + hash = rb_hash_new(); +#endif + } + + if (cache_count > 0) { + rb_hash_bulk_insert(cache_count, cache, hash); + cache_count = 0; + } + if (RB_UNLIKELY(json->object_class)) { VALUE object = rb_class_new_instance(0, 0, json->object_class); rb_funcall(cParser, rb_intern("convert_hash"), 2, hash, object); @@ -653,7 +680,7 @@ main := ignore* ( ) ignore* %*exit; }%% -static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting, bool push) +static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) { int cs = EVIL; @@ -665,9 +692,6 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul } if (cs >= JSON_value_first_final) { - if (push) { - PUSH(*result); - } return p; } else { return NULL; @@ -805,12 +829,21 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu write data; action parse_value { - VALUE v = Qnil; - char *np = JSON_parse_value(json, fpc, pe, &v, current_nesting, false); + char *np = JSON_parse_value(json, fpc, pe, &cache[cache_count], current_nesting); if (np == NULL) { fhold; fbreak; } else { - rb_ary_push(ary, v); + cache_count++; + if (cache_count == 20) { + if (!ary) { + ary = rb_ary_new_from_values(cache_count, cache); + cache_count = 0; + } + else { + rb_ary_concat(ary, rb_ary_new_from_values(cache_count, cache)); + cache_count = 0; + } + } fexec np; } } @@ -836,12 +869,25 @@ static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *resul } // speculate that it's a regular array - VALUE ary = rb_ary_new(); + VALUE cache[20]; + unsigned int cache_count = 0; + VALUE ary = 0; %% write init; %% write exec; if(cs >= JSON_array_first_final) { + if (!ary) { + ary = rb_ary_new_from_values(cache_count, cache); + cache_count = 0; + } + else { + if (cache_count > 0) { + rb_ary_concat(ary, rb_ary_new_from_values(cache_count, cache)); + cache_count = 0; + } + } + if (RB_UNLIKELY(json->array_class)) { VALUE array = rb_class_new_instance(0, 0, json->array_class); long index; @@ -1239,7 +1285,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) include JSON_common; action parse_value { - char *np = JSON_parse_value(json, fpc, pe, &result, 0, false); + char *np = JSON_parse_value(json, fpc, pe, &result, 0); if (np == NULL) { fhold; fbreak; } else fexec np; } @@ -1262,17 +1308,6 @@ static VALUE cParser_parse(VALUE self) VALUE result = Qnil; GET_PARSER; - char stack_buffer[FBUFFER_STACK_SIZE]; - fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE); - - VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA]; - rvalue_stack stack = { - .type = RVALUE_STACK_STACK_ALLOCATED, - .ptr = rvalue_stack_buffer, - .capa = RVALUE_STACK_INITIAL_CAPA, - }; - json->stack = &stack; - %% write init; p = json->source; pe = p + json->len; @@ -1303,14 +1338,6 @@ static VALUE cParser_m_parse(VALUE klass, VALUE source, VALUE opts) char stack_buffer[FBUFFER_STACK_SIZE]; fbuffer_stack_init(&json->fbuffer, FBUFFER_INITIAL_LENGTH_DEFAULT, stack_buffer, FBUFFER_STACK_SIZE); - VALUE rvalue_stack_buffer[RVALUE_STACK_INITIAL_CAPA]; - rvalue_stack stack = { - .type = RVALUE_STACK_STACK_ALLOCATED, - .ptr = rvalue_stack_buffer, - .capa = RVALUE_STACK_INITIAL_CAPA, - }; - json->stack = &stack; - %% write init; p = json->source; pe = p + json->len;