@@ -49,7 +49,6 @@ static VALUE protected_proc_call(VALUE proc, int argc, VALUE *argv, int *raised)
4949
5050static int RAW_TYPE_STRING = 256 ;
5151static int RAW_TYPE_BINARY = 257 ;
52- static int16_t INITIAL_BUFFER_CAPACITY_MAX = SHRT_MAX ;
5352
5453static msgpack_rmem_t s_stack_rmem ;
5554
@@ -60,9 +59,106 @@ static inline VALUE rb_hash_new_capa(long capa)
6059}
6160#endif
6261
63- static inline int16_t initial_buffer_size (long size )
62+ #ifndef HAVE_RB_HASH_BULK_INSERT
63+ void rb_hash_bulk_insert (long count , const VALUE * pairs , VALUE hash )
6464{
65- return (size > INITIAL_BUFFER_CAPACITY_MAX ) ? INITIAL_BUFFER_CAPACITY_MAX : size ;
65+ long index = 0 ;
66+ while (index < count ) {
67+ VALUE name = pairs [index ++ ];
68+ VALUE value = pairs [index ++ ];
69+ rb_hash_aset (hash , name , value );
70+ }
71+ RB_GC_GUARD (hash );
72+ }
73+ #endif
74+
75+ /* rvalue_stack functions */
76+
77+ static inline void _msgpack_unpacker_rvalue_stack_free (msgpack_rvalue_stack_t * value_stack ) {
78+ switch (value_stack -> type ) {
79+ case STACK_TYPE_UNALLOCATED :
80+ break ;
81+ case STACK_TYPE_RMEM :
82+ if (!msgpack_rmem_free (& s_stack_rmem , value_stack -> data )) {
83+ rb_bug ("Failed to free an rmem pointer, memory leak?" );
84+ }
85+ break ;
86+ case STACK_TYPE_HEAP :
87+ xfree (value_stack -> data );
88+ break ;
89+ }
90+ memset (value_stack , 0 , sizeof (msgpack_rvalue_stack_t ));
91+ }
92+
93+ static void _msgpack_unpacker_rvalue_stack_grow (msgpack_rvalue_stack_t * value_stack ) {
94+ switch (value_stack -> type ) {
95+ case STACK_TYPE_UNALLOCATED : {
96+ value_stack -> data = msgpack_rmem_alloc (& s_stack_rmem );
97+ value_stack -> capacity = MSGPACK_RMEM_PAGE_SIZE / sizeof (VALUE );
98+ value_stack -> type = STACK_TYPE_RMEM ;
99+ break ;
100+ }
101+ case STACK_TYPE_RMEM : {
102+ size_t new_capacity = value_stack -> capacity * 2 ;
103+ VALUE * new_ptr = ALLOC_N (VALUE , new_capacity );
104+ MEMCPY (new_ptr , value_stack -> data , VALUE , value_stack -> depth );
105+ if (!msgpack_rmem_free (& s_stack_rmem , value_stack -> data )) {
106+ rb_bug ("Failed to free an rmem pointer, memory leak?" );
107+ }
108+ value_stack -> type = STACK_TYPE_HEAP ;
109+ value_stack -> data = new_ptr ;
110+ value_stack -> capacity = new_capacity ;
111+ break ;
112+ }
113+ case STACK_TYPE_HEAP : {
114+ size_t new_capacity = value_stack -> capacity * 2 ;
115+ REALLOC_N (value_stack -> data , VALUE , new_capacity );
116+ value_stack -> capacity = new_capacity ;
117+ break ;
118+ }
119+ }
120+ }
121+
122+ static inline void _msgpack_unpacker_rvalue_stack_push (msgpack_unpacker_t * uk , VALUE value ) {
123+ size_t free_slots = uk -> value_stack .capacity - uk -> value_stack .depth ;
124+
125+ if (RB_UNLIKELY (free_slots == 0 )) {
126+ _msgpack_unpacker_rvalue_stack_grow (& uk -> value_stack );
127+ free_slots = uk -> value_stack .capacity - uk -> value_stack .depth ;
128+ }
129+
130+ RB_OBJ_WRITE (uk -> self , & uk -> value_stack .data [uk -> value_stack .depth ++ ], value );
131+ }
132+
133+ static inline VALUE _msgpack_unpacker_rvalue_stack_create_array (msgpack_unpacker_t * uk , size_t length ) {
134+ VALUE * data = & uk -> value_stack .data [uk -> value_stack .depth - length ];
135+
136+ VALUE array = rb_ary_new_from_values (length , data );
137+
138+ RB_OBJ_WRITE (uk -> self , data , array );
139+ uk -> value_stack .depth -= (length - 1 );
140+
141+ return RB_GC_GUARD (array );
142+ }
143+
144+ static inline VALUE _msgpack_unpacker_rvalue_stack_create_hash (msgpack_unpacker_t * uk , size_t items_count ) {
145+ size_t length = items_count / 2 ;
146+ VALUE * data = & uk -> value_stack .data [uk -> value_stack .depth - items_count ];
147+
148+ VALUE hash = rb_hash_new_capa (length );
149+ rb_hash_bulk_insert (items_count , data , hash );
150+
151+ RB_OBJ_WRITE (uk -> self , data , hash );
152+ uk -> value_stack .depth -= (items_count - 1 );
153+
154+ return RB_GC_GUARD (hash );
155+ }
156+
157+ void msgpack_unpacker_mark_rvalue_stack (msgpack_rvalue_stack_t * value_stack )
158+ {
159+ if (value_stack -> data ) {
160+ rb_gc_mark_locations (value_stack -> data , value_stack -> data + value_stack -> depth );
161+ }
66162}
67163
68164void msgpack_unpacker_static_init (void )
@@ -108,33 +204,16 @@ static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack)
108204
109205void _msgpack_unpacker_destroy (msgpack_unpacker_t * uk )
110206{
111- msgpack_unpacker_stack_t * stack = uk -> stack ;
112- while (stack ) {
113- _msgpack_unpacker_free_stack (stack );
114- stack = stack -> parent ;
115- }
116-
207+ _msgpack_unpacker_free_stack (uk -> stack );
208+ _msgpack_unpacker_rvalue_stack_free (& uk -> value_stack );
117209 msgpack_buffer_destroy (UNPACKER_BUFFER_ (uk ));
118210}
119211
120- void msgpack_unpacker_mark_stack (msgpack_unpacker_stack_t * stack )
121- {
122- while (stack ) {
123- msgpack_unpacker_stack_entry_t * s = stack -> data ;
124- msgpack_unpacker_stack_entry_t * send = stack -> data + stack -> depth ;
125- for (; s < send ; s ++ ) {
126- rb_gc_mark (s -> object );
127- rb_gc_mark (s -> key );
128- }
129- stack = stack -> parent ;
130- }
131- }
132-
133212void msgpack_unpacker_mark (msgpack_unpacker_t * uk )
134213{
135214 rb_gc_mark (uk -> last_object );
136215 rb_gc_mark (uk -> reading_raw );
137- msgpack_unpacker_mark_stack ( uk -> stack );
216+ msgpack_unpacker_mark_rvalue_stack ( & uk -> value_stack );
138217 /* See MessagePack_Buffer_wrap */
139218 /* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
140219 rb_gc_mark (uk -> buffer_ref );
@@ -149,6 +228,7 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
149228
150229 /*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
151230 uk -> stack -> depth = 0 ;
231+ uk -> value_stack .depth = 0 ;
152232 uk -> last_object = Qnil ;
153233 uk -> reading_raw = Qnil ;
154234 uk -> reading_raw_remaining = 0 ;
@@ -186,13 +266,15 @@ static inline int object_complete(msgpack_unpacker_t* uk, VALUE object)
186266 }
187267
188268 uk -> last_object = object ;
269+ _msgpack_unpacker_rvalue_stack_push (uk , object );
189270 reset_head_byte (uk );
190271 return PRIMITIVE_OBJECT_COMPLETE ;
191272}
192273
193274static inline int object_complete_symbol (msgpack_unpacker_t * uk , VALUE object )
194275{
195276 uk -> last_object = object ;
277+ _msgpack_unpacker_rvalue_stack_push (uk , object );
196278 reset_head_byte (uk );
197279 return PRIMITIVE_OBJECT_COMPLETE ;
198280}
@@ -212,12 +294,14 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
212294 if (proc != Qnil ) {
213295 VALUE obj ;
214296 VALUE arg = (str == Qnil ? rb_str_buf_new (0 ) : str );
297+
215298 int raised ;
216299 obj = protected_proc_call (proc , 1 , & arg , & raised );
217300 if (raised ) {
218301 uk -> last_object = rb_errinfo ();
219302 return PRIMITIVE_RECURSIVE_RAISED ;
220303 }
304+
221305 return object_complete (uk , obj );
222306 }
223307
@@ -235,7 +319,7 @@ static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(
235319 return & uk -> stack -> data [uk -> stack -> depth - 1 ];
236320}
237321
238- static inline int _msgpack_unpacker_stack_push (msgpack_unpacker_t * uk , enum stack_type_t type , size_t count , VALUE object )
322+ static inline int _msgpack_unpacker_stack_push (msgpack_unpacker_t * uk , enum stack_type_t type , size_t count )
239323{
240324 reset_head_byte (uk );
241325
@@ -245,22 +329,20 @@ static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stac
245329
246330 msgpack_unpacker_stack_entry_t * next = & uk -> stack -> data [uk -> stack -> depth ];
247331 next -> count = count ;
332+ next -> size = count ;
248333 next -> type = type ;
249- next -> object = object ;
250- next -> key = Qnil ;
251-
252334 uk -> stack -> depth ++ ;
253335 return PRIMITIVE_CONTAINER_START ;
254336}
255337
256- static inline VALUE msgpack_unpacker_stack_pop (msgpack_unpacker_t * uk )
338+ static inline size_t msgpack_unpacker_stack_pop (msgpack_unpacker_t * uk )
257339{
258340 return -- uk -> stack -> depth ;
259341}
260342
261343static inline bool msgpack_unpacker_stack_is_empty (msgpack_unpacker_t * uk )
262344{
263- return uk -> stack -> depth == 0 ;
345+ return uk -> stack -> depth == 0 || _msgpack_unpacker_stack_entry_top ( uk ) -> type == STACK_TYPE_RECURSIVE ;
264346}
265347
266348#ifdef USE_CASE_RANGE
@@ -290,9 +372,7 @@ static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
290372{
291373 if (uk -> stack -> depth > 0 ) {
292374 msgpack_unpacker_stack_entry_t * top = _msgpack_unpacker_stack_entry_top (uk );
293- if (top -> type == STACK_TYPE_MAP_KEY ) {
294- return true;
295- }
375+ return top -> type == STACK_TYPE_MAP && (top -> count % 2 == 0 );
296376 }
297377 return false;
298378}
@@ -343,17 +423,17 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
343423 reset_head_byte (uk );
344424 uk -> reading_raw_remaining = 0 ;
345425
346- msgpack_unpacker_stack_t * child_stack = _msgpack_unpacker_new_stack ();
347- child_stack -> parent = uk -> stack ;
348- uk -> stack = child_stack ;
349426
427+ _msgpack_unpacker_stack_push (uk , STACK_TYPE_RECURSIVE , 1 );
428+ size_t value_stack_depth = uk -> value_stack .depth ;
350429 int raised ;
351430 obj = protected_proc_call (proc , 1 , & uk -> self , & raised );
352- uk -> stack = child_stack -> parent ;
353- _msgpack_unpacker_free_stack ( child_stack );
431+ uk -> value_stack . depth = value_stack_depth ;
432+ msgpack_unpacker_stack_pop ( uk );
354433
355434 if (raised ) {
356435 uk -> last_object = rb_errinfo ();
436+ _msgpack_unpacker_rvalue_stack_push (uk , Qnil );
357437 return PRIMITIVE_RECURSIVE_RAISED ;
358438 }
359439
@@ -418,14 +498,14 @@ static int read_primitive(msgpack_unpacker_t* uk)
418498 if (count == 0 ) {
419499 return object_complete (uk , rb_ary_new ());
420500 }
421- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count , rb_ary_new2 ( initial_buffer_size ( count )) );
501+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count );
422502
423503 SWITCH_RANGE (b , 0x80 , 0x8f ) // FixMap
424504 int count = b & 0x0f ;
425505 if (count == 0 ) {
426506 return object_complete (uk , rb_hash_new ());
427507 }
428- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP_KEY , count * 2 , rb_hash_new_capa ( initial_buffer_size ( count )) );
508+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP , count * 2 );
429509
430510 SWITCH_RANGE (b , 0xc0 , 0xdf ) // Variable
431511 switch (b ) {
@@ -648,7 +728,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
648728 if (count == 0 ) {
649729 return object_complete (uk , rb_ary_new ());
650730 }
651- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count , rb_ary_new2 ( initial_buffer_size ( count )) );
731+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count );
652732 }
653733
654734 case 0xdd : // array 32
@@ -658,7 +738,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
658738 if (count == 0 ) {
659739 return object_complete (uk , rb_ary_new ());
660740 }
661- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count , rb_ary_new2 ( initial_buffer_size ( count )) );
741+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_ARRAY , count );
662742 }
663743
664744 case 0xde : // map 16
@@ -668,7 +748,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
668748 if (count == 0 ) {
669749 return object_complete (uk , rb_hash_new ());
670750 }
671- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP_KEY , count * 2 , rb_hash_new_capa ( initial_buffer_size ( count )) );
751+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP , count * 2 );
672752 }
673753
674754 case 0xdf : // map 32
@@ -678,7 +758,7 @@ static int read_primitive(msgpack_unpacker_t* uk)
678758 if (count == 0 ) {
679759 return object_complete (uk , rb_hash_new ());
680760 }
681- return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP_KEY , count * 2 , rb_hash_new_capa ( initial_buffer_size ( count )) );
761+ return _msgpack_unpacker_stack_push (uk , STACK_TYPE_MAP , count * 2 );
682762 }
683763
684764 default :
@@ -766,28 +846,23 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
766846 container_completed :
767847 {
768848 msgpack_unpacker_stack_entry_t * top = _msgpack_unpacker_stack_entry_top (uk );
769- switch (top -> type ) {
770- case STACK_TYPE_ARRAY :
771- rb_ary_push (top -> object , uk -> last_object );
772- break ;
773- case STACK_TYPE_MAP_KEY :
774- top -> key = uk -> last_object ;
775- top -> type = STACK_TYPE_MAP_VALUE ;
776- break ;
777- case STACK_TYPE_MAP_VALUE :
778- if (uk -> symbolize_keys && rb_type (top -> key ) == T_STRING ) {
779- /* here uses rb_str_intern instead of rb_intern so that Ruby VM can GC unused symbols */
780- rb_hash_aset (top -> object , rb_str_intern (top -> key ), uk -> last_object );
781- } else {
782- rb_hash_aset (top -> object , top -> key , uk -> last_object );
783- }
784- top -> type = STACK_TYPE_MAP_KEY ;
785- break ;
786- }
787849 size_t count = -- top -> count ;
788850
789851 if (count == 0 ) {
790- object_complete (uk , top -> object );
852+ switch (top -> type ) {
853+ case STACK_TYPE_ARRAY :
854+ _msgpack_unpacker_rvalue_stack_create_array (uk , top -> size );
855+ break ;
856+ case STACK_TYPE_MAP :
857+ _msgpack_unpacker_rvalue_stack_create_hash (uk , top -> size );
858+ break ;
859+ case STACK_TYPE_RECURSIVE :
860+ object_complete (uk , _msgpack_unpacker_rvalue_stack_pop (uk ));
861+ return PRIMITIVE_OBJECT_COMPLETE ;
862+ break ;
863+ }
864+
865+ object_complete (uk , _msgpack_unpacker_rvalue_stack_pop (uk ));
791866 if (msgpack_unpacker_stack_pop (uk ) <= target_stack_depth ) {
792867 return PRIMITIVE_OBJECT_COMPLETE ;
793868 }
0 commit comments