diff --git a/ext/json/ext/parser/parser.c b/ext/json/ext/parser/parser.c index 09ca4f75a..baac2b554 100644 --- a/ext/json/ext/parser/parser.c +++ b/ext/json/ext/parser/parser.c @@ -460,10 +460,12 @@ enum {JSON_object_error = 0}; enum {JSON_object_en_main = 1}; -#line 514 "parser.rl" +#line 527 "parser.rl" #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) { @@ -473,17 +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 = 0; + VALUE key = Qnil; + long stack_head = json->stack->head; -#line 480 "parser.c" +#line 488 "parser.c" { cs = JSON_object_start; } -#line 529 "parser.rl" +#line 550 "parser.rl" -#line 487 "parser.c" +#line 495 "parser.c" { short _widec; if ( p == pe ) @@ -512,14 +520,14 @@ case 2: goto st2; goto st0; tr2: -#line 493 "parser.rl" +#line 506 "parser.rl" { char *np; json->parsing_name = true; - np = JSON_parse_string(json, p, pe, result); + 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 { - PUSH(*result); {p = (( np))-1;} } } @@ -528,7 +536,7 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 532 "parser.c" +#line 540 "parser.c" switch( (*p) ) { case 13: goto st3; case 32: goto st3; @@ -597,10 +605,23 @@ case 8: tr11: #line 482 "parser.rl" { - char *np = JSON_parse_value(json, p, pe, result, current_nesting); + VALUE val; + char *np = JSON_parse_value(json, p, pe, &cache[cache_count], current_nesting); if (np == NULL) { p--; {p++; cs = 9; goto _out;} } else { + 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;} } } @@ -609,20 +630,20 @@ case 8: if ( ++p == pe ) goto _test_eof9; case 9: -#line 613 "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 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -630,26 +651,26 @@ case 9: if ( 32 <= (*p) && (*p) <= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "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 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -670,14 +691,14 @@ case 9: goto st10; goto st0; tr4: -#line 504 "parser.rl" +#line 517 "parser.rl" { p--; {p++; cs = 32; goto _out;} } goto st32; st32: if ( ++p == pe ) goto _test_eof32; case 32: -#line 681 "parser.c" +#line 702 "parser.c" goto st0; st10: if ( ++p == pe ) @@ -779,13 +800,13 @@ case 20: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -804,20 +825,20 @@ case 21: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "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 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -840,13 +861,13 @@ case 22: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -854,19 +875,19 @@ case 22: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -890,20 +911,20 @@ case 23: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "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 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 491 "parser.rl" +#line 504 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1017,32 +1038,31 @@ case 31: _out: {} } -#line 530 "parser.rl" +#line 551 "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 = rvalue_stack_peek(json->stack, count); - while (index < count) { - VALUE name = items[index++]; - VALUE value = items[index++]; - rb_funcall(object, i_aset, 2, name, value); - } - *result = object; - } else { - VALUE hash; + if (!hash) { #ifdef HAVE_RB_HASH_NEW_CAPA - hash = rb_hash_new_capa(count >> 1); + hash = rb_hash_new_capa(cache_count); #else hash = rb_hash_new(); #endif - rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash); + } + + 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); + *result = object; + } else { *result = hash; } - rvalue_stack_pop(json->stack, count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; @@ -1068,7 +1088,7 @@ case 31: } -#line 1072 "parser.c" +#line 1092 "parser.c" enum {JSON_value_start = 1}; enum {JSON_value_first_final = 29}; enum {JSON_value_error = 0}; @@ -1076,7 +1096,7 @@ enum {JSON_value_error = 0}; enum {JSON_value_en_main = 1}; -#line 661 "parser.rl" +#line 681 "parser.rl" static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1084,14 +1104,14 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul int cs = EVIL; -#line 1088 "parser.c" +#line 1108 "parser.c" { cs = JSON_value_start; } -#line 668 "parser.rl" +#line 688 "parser.rl" -#line 1095 "parser.c" +#line 1115 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1125,7 +1145,7 @@ case 1: cs = 0; goto _out; tr2: -#line 608 "parser.rl" +#line 628 "parser.rl" { char *np = JSON_parse_string(json, p, pe, result); if (np == NULL) { @@ -1137,7 +1157,7 @@ cs = 0; } goto st29; tr3: -#line 618 "parser.rl" +#line 638 "parser.rl" { char *np; if(pe > p + 8 && !strncmp(MinusInfinity, p, 9)) { @@ -1157,7 +1177,7 @@ cs = 0; } goto st29; tr7: -#line 636 "parser.rl" +#line 656 "parser.rl" { char *np; np = JSON_parse_array(json, p, pe, result, current_nesting + 1); @@ -1165,7 +1185,7 @@ cs = 0; } goto st29; tr11: -#line 642 "parser.rl" +#line 662 "parser.rl" { char *np; np = JSON_parse_object(json, p, pe, result, current_nesting + 1); @@ -1173,7 +1193,7 @@ cs = 0; } goto st29; tr25: -#line 601 "parser.rl" +#line 621 "parser.rl" { if (json->allow_nan) { *result = CInfinity; @@ -1183,7 +1203,7 @@ cs = 0; } goto st29; tr27: -#line 594 "parser.rl" +#line 614 "parser.rl" { if (json->allow_nan) { *result = CNaN; @@ -1193,19 +1213,19 @@ cs = 0; } goto st29; tr31: -#line 588 "parser.rl" +#line 608 "parser.rl" { *result = Qfalse; } goto st29; tr34: -#line 585 "parser.rl" +#line 605 "parser.rl" { *result = Qnil; } goto st29; tr37: -#line 591 "parser.rl" +#line 611 "parser.rl" { *result = Qtrue; } @@ -1214,9 +1234,9 @@ cs = 0; if ( ++p == pe ) goto _test_eof29; case 29: -#line 648 "parser.rl" +#line 668 "parser.rl" { p--; {p++; cs = 29; goto _out;} } -#line 1220 "parser.c" +#line 1240 "parser.c" switch( (*p) ) { case 13: goto st29; case 32: goto st29; @@ -1457,14 +1477,13 @@ case 28: _out: {} } -#line 669 "parser.rl" +#line 689 "parser.rl" if (json->freeze) { OBJ_FREEZE(*result); } if (cs >= JSON_value_first_final) { - PUSH(*result); return p; } else { return NULL; @@ -1472,7 +1491,7 @@ case 28: } -#line 1476 "parser.c" +#line 1495 "parser.c" enum {JSON_integer_start = 1}; enum {JSON_integer_first_final = 3}; enum {JSON_integer_error = 0}; @@ -1480,7 +1499,7 @@ enum {JSON_integer_error = 0}; enum {JSON_integer_en_main = 1}; -#line 690 "parser.rl" +#line 709 "parser.rl" #define MAX_FAST_INTEGER_SIZE 18 @@ -1520,7 +1539,7 @@ static char *JSON_decode_integer(JSON_Parser *json, char *p, VALUE *result) } -#line 1524 "parser.c" +#line 1543 "parser.c" enum {JSON_float_start = 1}; enum {JSON_float_first_final = 6}; enum {JSON_float_error = 0}; @@ -1528,7 +1547,7 @@ enum {JSON_float_error = 0}; enum {JSON_float_en_main = 1}; -#line 742 "parser.rl" +#line 761 "parser.rl" static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *result) @@ -1537,15 +1556,15 @@ static char *JSON_parse_number(JSON_Parser *json, char *p, char *pe, VALUE *resu bool is_float = false; -#line 1541 "parser.c" +#line 1560 "parser.c" { cs = JSON_float_start; } -#line 750 "parser.rl" +#line 769 "parser.rl" json->memo = p; -#line 1549 "parser.c" +#line 1568 "parser.c" { if ( p == pe ) goto _test_eof; @@ -1585,24 +1604,24 @@ case 6: goto st0; goto tr7; tr7: -#line 734 "parser.rl" +#line 753 "parser.rl" { p--; {p++; cs = 7; goto _out;} } goto st7; st7: if ( ++p == pe ) goto _test_eof7; case 7: -#line 1596 "parser.c" +#line 1615 "parser.c" goto st0; tr8: -#line 735 "parser.rl" +#line 754 "parser.rl" { is_float = true; } goto st3; st3: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1606 "parser.c" +#line 1625 "parser.c" if ( 48 <= (*p) && (*p) <= 57 ) goto st8; goto st0; @@ -1621,14 +1640,14 @@ case 8: goto st0; goto tr7; tr9: -#line 735 "parser.rl" +#line 754 "parser.rl" { is_float = true; } goto st4; st4: if ( ++p == pe ) goto _test_eof4; case 4: -#line 1632 "parser.c" +#line 1651 "parser.c" switch( (*p) ) { case 43: goto st5; case 45: goto st5; @@ -1685,7 +1704,7 @@ case 10: _out: {} } -#line 752 "parser.rl" +#line 771 "parser.rl" if (cs >= JSON_float_first_final) { if (!is_float) { @@ -1741,7 +1760,7 @@ case 10: -#line 1745 "parser.c" +#line 1764 "parser.c" enum {JSON_array_start = 1}; enum {JSON_array_first_final = 22}; enum {JSON_array_error = 0}; @@ -1749,7 +1768,7 @@ enum {JSON_array_error = 0}; enum {JSON_array_en_main = 1}; -#line 832 "parser.rl" +#line 861 "parser.rl" static char *JSON_parse_array(JSON_Parser *json, char *p, char *pe, VALUE *result, int current_nesting) @@ -1759,17 +1778,21 @@ 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 cache[20]; + unsigned int cache_count = 0; + VALUE ary = 0; -#line 1766 "parser.c" +#line 1789 "parser.c" { cs = JSON_array_start; } -#line 844 "parser.rl" +#line 877 "parser.rl" -#line 1773 "parser.c" +#line 1796 "parser.c" { short _widec; if ( p == pe ) @@ -1809,13 +1832,23 @@ case 2: goto st2; goto st0; tr2: -#line 812 "parser.rl" +#line 831 "parser.rl" { - VALUE v = Qnil; - char *np = JSON_parse_value(json, p, pe, &v, current_nesting); + char *np = JSON_parse_value(json, p, pe, &cache[cache_count], current_nesting); if (np == NULL) { p--; {p++; cs = 3; goto _out;} } else { + 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;} } } @@ -1824,12 +1857,12 @@ case 2: if ( ++p == pe ) goto _test_eof3; case 3: -#line 1828 "parser.c" +#line 1861 "parser.c" _widec = (*p); if ( 44 <= (*p) && (*p) <= 44 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -1876,14 +1909,14 @@ case 7: goto st3; goto st7; tr4: -#line 824 "parser.rl" +#line 853 "parser.rl" { p--; {p++; cs = 22; goto _out;} } goto st22; st22: if ( ++p == pe ) goto _test_eof22; case 22: -#line 1887 "parser.c" +#line 1920 "parser.c" goto st0; st8: if ( ++p == pe ) @@ -1951,13 +1984,13 @@ case 13: if ( 10 <= (*p) && (*p) <= 10 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 13 ) { @@ -1965,19 +1998,19 @@ case 13: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 32 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2016,13 +2049,13 @@ case 14: if ( 47 <= (*p) && (*p) <= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2041,20 +2074,20 @@ case 15: if ( (*p) <= 41 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "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 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2077,13 +2110,13 @@ case 16: if ( 42 <= (*p) && (*p) <= 42 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) > 46 ) { @@ -2091,19 +2124,19 @@ case 16: if ( 48 <= (*p) ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else if ( (*p) >= 47 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2127,20 +2160,20 @@ case 17: if ( (*p) <= 9 ) { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "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 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } } else { _widec = (short)(128 + ((*p) - -128)); if ( -#line 822 "parser.rl" +#line 851 "parser.rl" json->allow_trailing_comma ) _widec += 256; } switch( _widec ) { @@ -2212,24 +2245,30 @@ case 21: _out: {} } -#line 845 "parser.rl" +#line 878 "parser.rl" if(cs >= JSON_array_first_final) { - long count = json->stack->head - stack_head; + 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); - VALUE *items = rvalue_stack_peek(json->stack, 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, rvalue_stack_peek(json->stack, count)); - *result = array; + *result = ary; } - rvalue_stack_pop(json->stack, count); return p + 1; } else { @@ -2406,7 +2445,7 @@ static VALUE json_string_unescape(JSON_Parser *json, char *string, char *stringE } -#line 2410 "parser.c" +#line 2449 "parser.c" enum {JSON_string_start = 1}; enum {JSON_string_first_final = 9}; enum {JSON_string_error = 0}; @@ -2414,7 +2453,7 @@ enum {JSON_string_error = 0}; enum {JSON_string_en_main = 1}; -#line 1068 "parser.rl" +#line 1107 "parser.rl" static int @@ -2435,15 +2474,15 @@ static char *JSON_parse_string(JSON_Parser *json, char *p, char *pe, VALUE *resu VALUE match_string; -#line 2439 "parser.c" +#line 2478 "parser.c" { cs = JSON_string_start; } -#line 1088 "parser.rl" +#line 1127 "parser.rl" json->memo = p; -#line 2447 "parser.c" +#line 2486 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2468,14 +2507,14 @@ case 2: goto st0; goto st2; tr2: -#line 1050 "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 1043 "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;} @@ -2484,7 +2523,7 @@ case 2: } goto st9; tr6: -#line 1043 "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;} @@ -2496,7 +2535,7 @@ case 2: if ( ++p == pe ) goto _test_eof9; case 9: -#line 2500 "parser.c" +#line 2539 "parser.c" goto st0; st3: if ( ++p == pe ) @@ -2584,7 +2623,7 @@ case 8: _out: {} } -#line 1090 "parser.rl" +#line 1129 "parser.rl" if (json->create_additions && RTEST(match_string = json->match_string)) { VALUE klass; @@ -2737,7 +2776,7 @@ static VALUE cParser_initialize(int argc, VALUE *argv, VALUE self) } -#line 2741 "parser.c" +#line 2780 "parser.c" enum {JSON_start = 1}; enum {JSON_first_final = 10}; enum {JSON_error = 0}; @@ -2745,7 +2784,7 @@ enum {JSON_error = 0}; enum {JSON_en_main = 1}; -#line 1256 "parser.rl" +#line 1295 "parser.rl" /* @@ -2762,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 2778 "parser.c" +#line 2806 "parser.c" { cs = JSON_start; } -#line 1284 "parser.rl" +#line 1312 "parser.rl" p = json->source; pe = p + json->len; -#line 2787 "parser.c" +#line 2815 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2817,7 +2845,7 @@ case 1: cs = 0; goto _out; tr2: -#line 1248 "parser.rl" +#line 1287 "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 +2855,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 2831 "parser.c" +#line 2859 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -2916,7 +2944,7 @@ case 9: _out: {} } -#line 1287 "parser.rl" +#line 1315 "parser.rl" if (json->stack_handle) { rvalue_stack_eagerly_release(json->stack_handle); @@ -2943,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 2956 "parser.c" +#line 2976 "parser.c" { cs = JSON_start; } -#line 1322 "parser.rl" +#line 1342 "parser.rl" p = json->source; pe = p + json->len; -#line 2965 "parser.c" +#line 2985 "parser.c" { if ( p == pe ) goto _test_eof; @@ -2995,7 +3015,7 @@ case 1: cs = 0; goto _out; tr2: -#line 1248 "parser.rl" +#line 1287 "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 +3025,7 @@ cs = 0; if ( ++p == pe ) goto _test_eof10; case 10: -#line 3009 "parser.c" +#line 3029 "parser.c" switch( (*p) ) { case 13: goto st10; case 32: goto st10; @@ -3094,7 +3114,7 @@ case 9: _out: {} } -#line 1325 "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 9a1f73923..00d13e4c9 100644 --- a/ext/json/ext/parser/parser.rl +++ b/ext/json/ext/parser/parser.rl @@ -480,10 +480,23 @@ 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); + VALUE val; + char *np = JSON_parse_value(json, fpc, pe, &cache[cache_count], current_nesting); if (np == NULL) { fhold; fbreak; } else { + 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; } } @@ -493,10 +506,10 @@ 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, &cache[cache_count]); + cache_count++; json->parsing_name = false; if (np == NULL) { fhold; fbreak; } else { - PUSH(*result); fexec np; } } @@ -514,6 +527,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) { @@ -523,6 +538,12 @@ 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 = 0; + VALUE key = Qnil; + long stack_head = json->stack->head; %% write init; @@ -531,27 +552,26 @@ 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 (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); - while (index < count) { - VALUE name = items[index++]; - VALUE value = items[index++]; - rb_funcall(object, i_aset, 2, name, value); - } - *result = object; - } else { - VALUE hash; + if (!hash) { #ifdef HAVE_RB_HASH_NEW_CAPA - hash = rb_hash_new_capa(count >> 1); + hash = rb_hash_new_capa(cache_count); #else hash = rb_hash_new(); #endif - rb_hash_bulk_insert(count, rvalue_stack_peek(json->stack, count), hash); + } + + 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); + *result = object; + } else { *result = hash; } - rvalue_stack_pop(json->stack, count); if (RB_UNLIKELY(json->create_additions)) { VALUE klassname; @@ -672,7 +692,6 @@ static char *JSON_parse_value(JSON_Parser *json, char *p, char *pe, VALUE *resul } if (cs >= JSON_value_first_final) { - PUSH(*result); return p; } else { return NULL; @@ -810,11 +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); + char *np = JSON_parse_value(json, fpc, pe, &cache[cache_count], current_nesting); if (np == NULL) { fhold; fbreak; } else { + 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; } } @@ -838,27 +867,37 @@ 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 cache[20]; + unsigned int cache_count = 0; + VALUE ary = 0; %% write init; %% write exec; if(cs >= JSON_array_first_final) { - long count = json->stack->head - stack_head; + 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); - VALUE *items = rvalue_stack_peek(json->stack, 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, rvalue_stack_peek(json->stack, count)); - *result = array; + *result = ary; } - rvalue_stack_pop(json->stack, count); return p + 1; } else { @@ -1269,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; @@ -1310,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; 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