2828
2929static int RAW_TYPE_STRING = 256 ;
3030static int RAW_TYPE_BINARY = 257 ;
31- static int16_t INITIAL_BUFFER_CAPACITY_MAX = SHRT_MAX ;
3231
3332static msgpack_rmem_t s_stack_rmem ;
3433
@@ -39,9 +38,106 @@ static inline VALUE rb_hash_new_capa(long capa)
3938}
4039#endif
4140
42- static inline int16_t initial_buffer_size (long size )
41+ #ifndef HAVE_RB_HASH_BULK_INSERT
42+ void rb_hash_bulk_insert (long count , const VALUE * pairs , VALUE hash )
4343{
44- return (size > INITIAL_BUFFER_CAPACITY_MAX ) ? INITIAL_BUFFER_CAPACITY_MAX : size ;
44+ long index = 0 ;
45+ while (index < count ) {
46+ VALUE name = pairs [index ++ ];
47+ VALUE value = pairs [index ++ ];
48+ rb_hash_aset (hash , name , value );
49+ }
50+ RB_GC_GUARD (hash );
51+ }
52+ #endif
53+
54+ /* rvalue_stack functions */
55+
56+ static inline void _msgpack_unpacker_rvalue_stack_free (msgpack_rvalue_stack_t * value_stack ) {
57+ switch (value_stack -> type ) {
58+ case STACK_TYPE_UNALLOCATED :
59+ break ;
60+ case STACK_TYPE_RMEM :
61+ if (!msgpack_rmem_free (& s_stack_rmem , value_stack -> data )) {
62+ rb_bug ("Failed to free an rmem pointer, memory leak?" );
63+ }
64+ break ;
65+ case STACK_TYPE_HEAP :
66+ xfree (value_stack -> data );
67+ break ;
68+ }
69+ memset (value_stack , 0 , sizeof (msgpack_rvalue_stack_t ));
70+ }
71+
72+ static void _msgpack_unpacker_rvalue_stack_grow (msgpack_rvalue_stack_t * value_stack ) {
73+ switch (value_stack -> type ) {
74+ case STACK_TYPE_UNALLOCATED : {
75+ value_stack -> data = msgpack_rmem_alloc (& s_stack_rmem );
76+ value_stack -> capacity = MSGPACK_RMEM_PAGE_SIZE / sizeof (VALUE );
77+ value_stack -> type = STACK_TYPE_RMEM ;
78+ break ;
79+ }
80+ case STACK_TYPE_RMEM : {
81+ size_t new_capacity = value_stack -> capacity * 2 ;
82+ VALUE * new_ptr = ALLOC_N (VALUE , new_capacity );
83+ MEMCPY (new_ptr , value_stack -> data , VALUE , value_stack -> depth );
84+ if (!msgpack_rmem_free (& s_stack_rmem , value_stack -> data )) {
85+ rb_bug ("Failed to free an rmem pointer, memory leak?" );
86+ }
87+ value_stack -> type = STACK_TYPE_HEAP ;
88+ value_stack -> data = new_ptr ;
89+ value_stack -> capacity = new_capacity ;
90+ break ;
91+ }
92+ case STACK_TYPE_HEAP : {
93+ size_t new_capacity = value_stack -> capacity * 2 ;
94+ REALLOC_N (value_stack -> data , VALUE , new_capacity );
95+ value_stack -> capacity = new_capacity ;
96+ break ;
97+ }
98+ }
99+ }
100+
101+ static inline void _msgpack_unpacker_rvalue_stack_push (msgpack_unpacker_t * uk , VALUE value ) {
102+ size_t free_slots = uk -> value_stack .capacity - uk -> value_stack .depth ;
103+
104+ if (RB_UNLIKELY (free_slots == 0 )) {
105+ _msgpack_unpacker_rvalue_stack_grow (& uk -> value_stack );
106+ free_slots = uk -> value_stack .capacity - uk -> value_stack .depth ;
107+ }
108+
109+ RB_OBJ_WRITE (uk -> self , & uk -> value_stack .data [uk -> value_stack .depth ++ ], value );
110+ }
111+
112+ static inline VALUE _msgpack_unpacker_rvalue_stack_create_array (msgpack_unpacker_t * uk , size_t length ) {
113+ VALUE * data = & uk -> value_stack .data [uk -> value_stack .depth - length ];
114+
115+ VALUE array = rb_ary_new_from_values (length , data );
116+
117+ RB_OBJ_WRITE (uk -> self , data , array );
118+ uk -> value_stack .depth -= (length - 1 );
119+
120+ return RB_GC_GUARD (array );
121+ }
122+
123+ static inline VALUE _msgpack_unpacker_rvalue_stack_create_hash (msgpack_unpacker_t * uk , size_t items_count ) {
124+ size_t length = items_count / 2 ;
125+ VALUE * data = & uk -> value_stack .data [uk -> value_stack .depth - items_count ];
126+
127+ VALUE hash = rb_hash_new_capa (length );
128+ rb_hash_bulk_insert (items_count , data , hash );
129+
130+ RB_OBJ_WRITE (uk -> self , data , hash );
131+ uk -> value_stack .depth -= (items_count - 1 );
132+
133+ return RB_GC_GUARD (hash );
134+ }
135+
136+ void msgpack_unpacker_mark_rvalue_stack (msgpack_rvalue_stack_t * value_stack )
137+ {
138+ if (value_stack -> data ) {
139+ rb_gc_mark_locations (value_stack -> data , value_stack -> data + value_stack -> depth );
140+ }
45141}
46142
47143void msgpack_unpacker_static_init (void )
@@ -88,27 +184,15 @@ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack)
88184void _msgpack_unpacker_destroy (msgpack_unpacker_t * uk )
89185{
90186 _msgpack_unpacker_free_stack (uk -> stack );
187+ _msgpack_unpacker_rvalue_stack_free (& uk -> value_stack );
91188 msgpack_buffer_destroy (UNPACKER_BUFFER_ (uk ));
92189}
93190
94- void msgpack_unpacker_mark_stack (msgpack_unpacker_stack_t * stack )
95- {
96- while (stack ) {
97- msgpack_unpacker_stack_entry_t * s = stack -> data ;
98- msgpack_unpacker_stack_entry_t * send = stack -> data + stack -> depth ;
99- for (; s < send ; s ++ ) {
100- rb_gc_mark (s -> object );
101- rb_gc_mark (s -> key );
102- }
103- stack = stack -> parent ;
104- }
105- }
106-
107191void msgpack_unpacker_mark (msgpack_unpacker_t * uk )
108192{
109193 rb_gc_mark (uk -> last_object );
110194 rb_gc_mark (uk -> reading_raw );
111- msgpack_unpacker_mark_stack ( uk -> stack );
195+ msgpack_unpacker_mark_rvalue_stack ( & uk -> value_stack );
112196 /* See MessagePack_Buffer_wrap */
113197 /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
114198 rb_gc_mark (uk -> buffer_ref );
@@ -160,13 +244,15 @@ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
160244 }
161245
162246 uk -> last_object = object ;
247+ _msgpack_unpacker_rvalue_stack_push (uk , object );
163248 reset_head_byte (uk );
164249 return PRIMITIVE_OBJECT_COMPLETE ;
165250}
166251
167252static inline int object_complete_symbol (msgpack_unpacker_t * uk , VALUE object )
168253{
169254 uk -> last_object = object ;
255+ _msgpack_unpacker_rvalue_stack_push (uk , object );
170256 reset_head_byte (uk );
171257 return PRIMITIVE_OBJECT_COMPLETE ;
172258}
@@ -204,7 +290,7 @@ static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(
204290 return & uk -> stack -> data [uk -> stack -> depth - 1 ];
205291}
206292
207- static inline int _msgpack_unpacker_stack_push (msgpack_unpacker_t * uk , enum stack_type_t type , size_t count , VALUE object )
293+ static inline int _msgpack_unpacker_stack_push (msgpack_unpacker_t * uk , enum stack_type_t type , size_t count )
208294{
209295 reset_head_byte (uk );
210296
@@ -214,22 +300,20 @@ static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stac
214300
215301 msgpack_unpacker_stack_entry_t * next = & uk -> stack -> data [uk -> stack -> depth ];
216302 next -> count = count ;
303+ next -> size = count ;
217304 next -> type = type ;
218- next -> object = object ;
219- next -> key = Qnil ;
220-
221305 uk -> stack -> depth ++ ;
222306 return PRIMITIVE_CONTAINER_START ;
223307}
224308
225- static inline VALUE msgpack_unpacker_stack_pop (msgpack_unpacker_t * uk )
309+ static inline size_t msgpack_unpacker_stack_pop (msgpack_unpacker_t * uk )
226310{
227311 return -- uk -> stack -> depth ;
228312}
229313
230314static inline bool msgpack_unpacker_stack_is_empty (msgpack_unpacker_t * uk )
231315{
232- return uk -> stack -> depth == 0 ;
316+ return uk -> stack -> depth == 0 || _msgpack_unpacker_stack_entry_top ( uk ) -> type == STACK_TYPE_RECURSIVE ;
233317}
234318
235319#ifdef USE_CASE_RANGE
@@ -259,9 +343,7 @@ static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
259343{
260344 if (uk -> stack -> depth > 0 ) {
261345 msgpack_unpacker_stack_entry_t * top = _msgpack_unpacker_stack_entry_top (uk );
262- if (top -> type == STACK_TYPE_MAP_KEY ) {
263- return true;
264- }
346+ return top -> type == STACK_TYPE_MAP && (top -> count % 2 == 0 );
265347 }
266348 return false;
267349}
@@ -312,14 +394,9 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
312394 reset_head_byte (uk );
313395 uk -> reading_raw_remaining = 0 ;
314396
315- msgpack_unpacker_stack_t * child_stack = _msgpack_unpacker_new_stack ();
316- child_stack -> parent = uk -> stack ;
317- uk -> stack = child_stack ;
318-
397+ _msgpack_unpacker_stack_push (uk , STACK_TYPE_RECURSIVE , 1 );
319398 obj = rb_proc_call_with_block (proc , 1 , & uk -> self , Qnil );
320-
321- uk -> stack = child_stack -> parent ;
322- _msgpack_unpacker_free_stack (child_stack );
399+ msgpack_unpacker_stack_pop (uk );
323400
324401 return object_complete (uk , obj );
325402 }
@@ -382,14 +459,14 @@ static int read_primitive(msgpack_unpacker_t* uk)
382459 if (count == 0 ) {
383460 return object_complete (uk , rb_ary_new ());
384461 }
385- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count , rb_ary_new2 ( initial_buffer_size ( count )) );
462+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count );
386463
387464 SWITCH_RANGE (b , 0x80 , 0x8f ) // FixMap
388465 int count = b & 0x0f ;
389466 if (count == 0 ) {
390467 return object_complete (uk , rb_hash_new ());
391468 }
392- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP_KEY , count * 2 , rb_hash_new_capa ( initial_buffer_size ( count )) );
469+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP , count * 2 );
393470
394471 SWITCH_RANGE (b , 0xc0 , 0xdf ) // Variable
395472 switch (b ) {
@@ -612,7 +689,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
612689 if (count == 0 ) {
613690 return object_complete (uk , rb_ary_new ());
614691 }
615- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count , rb_ary_new2 ( initial_buffer_size ( count )) );
692+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count );
616693 }
617694
618695 case 0xdd : // array 32
@@ -622,7 +699,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
622699 if (count == 0 ) {
623700 return object_complete (uk , rb_ary_new ());
624701 }
625- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count , rb_ary_new2 ( initial_buffer_size ( count )) );
702+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count );
626703 }
627704
628705 case 0xde : // map 16
@@ -632,7 +709,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
632709 if (count == 0 ) {
633710 return object_complete (uk , rb_hash_new ());
634711 }
635- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP_KEY , count * 2 , rb_hash_new_capa ( initial_buffer_size ( count )) );
712+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP , count * 2 );
636713 }
637714
638715 case 0xdf : // map 32
@@ -642,7 +719,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
642719 if (count == 0 ) {
643720 return object_complete (uk , rb_hash_new ());
644721 }
645- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP_KEY , count * 2 , rb_hash_new_capa ( initial_buffer_size ( count )) );
722+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP , count * 2 );
646723 }
647724
648725 default :
@@ -730,28 +807,23 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
730807 container_completed :
731808 {
732809 msgpack_unpacker_stack_entry_t * top = _msgpack_unpacker_stack_entry_top (uk );
733- switch (top -> type ) {
734- case STACK_TYPE_ARRAY :
735- rb_ary_push (top -> object , uk -> last_object );
736- break ;
737- case STACK_TYPE_MAP_KEY :
738- top -> key = uk -> last_object ;
739- top -> type = STACK_TYPE_MAP_VALUE ;
740- break ;
741- case STACK_TYPE_MAP_VALUE :
742- if (uk -> symbolize_keys && rb_type (top -> key ) == T_STRING ) {
743- /* here uses rb_str_intern instead of rb_intern so that Ruby VM can GC unused symbols */
744- rb_hash_aset (top -> object , rb_str_intern (top -> key ), uk -> last_object );
745- } else {
746- rb_hash_aset (top -> object , top -> key , uk -> last_object );
747- }
748- top -> type = STACK_TYPE_MAP_KEY ;
749- break ;
750- }
751810 size_t count = -- top -> count ;
752811
753812 if (count == 0 ) {
754- object_complete (uk , top -> object );
813+ switch (top -> type ) {
814+ case STACK_TYPE_ARRAY :
815+ _msgpack_unpacker_rvalue_stack_create_array (uk , top -> size );
816+ break ;
817+ case STACK_TYPE_MAP :
818+ _msgpack_unpacker_rvalue_stack_create_hash (uk , top -> size );
819+ break ;
820+ case STACK_TYPE_RECURSIVE :
821+ object_complete (uk , _msgpack_unpacker_rvalue_stack_pop (uk ));
822+ return PRIMITIVE_OBJECT_COMPLETE ;
823+ break ;
824+ }
825+
826+ object_complete (uk , _msgpack_unpacker_rvalue_stack_pop (uk ));
755827 if (msgpack_unpacker_stack_pop (uk ) <= target_stack_depth ) {
756828 return PRIMITIVE_OBJECT_COMPLETE ;
757829 }
0 commit comments