Skip to content

Commit a60b1da

Browse files
authored
Merge pull request #372 from msgpack/refactor-stack
Refactor unpacking of recursive types
2 parents b3bcc6b + b265f3c commit a60b1da

File tree

3 files changed

+32
-42
lines changed

3 files changed

+32
-42
lines changed

ext/msgpack/unpacker.c

+21-31
Original file line numberDiff line numberDiff line change
@@ -79,12 +79,9 @@ void msgpack_unpacker_static_destroy(void)
7979

8080
#define HEAD_BYTE_REQUIRED 0xc1
8181

82-
static inline msgpack_unpacker_stack_t* _msgpack_unpacker_new_stack(void) {
83-
msgpack_unpacker_stack_t *stack = ZALLOC(msgpack_unpacker_stack_t);
82+
static inline void _msgpack_unpacker_stack_init(msgpack_unpacker_stack_t *stack) {
8483
stack->capacity = MSGPACK_UNPACKER_STACK_CAPACITY;
8584
stack->data = msgpack_rmem_alloc(&s_stack_rmem);
86-
/*memset(uk->stack, 0, MSGPACK_UNPACKER_STACK_CAPACITY);*/
87-
return stack;
8885
}
8986

9087
void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
@@ -96,45 +93,40 @@ void _msgpack_unpacker_init(msgpack_unpacker_t* uk)
9693
uk->last_object = Qnil;
9794
uk->reading_raw = Qnil;
9895

99-
uk->stack = _msgpack_unpacker_new_stack();
96+
_msgpack_unpacker_stack_init(&uk->stack);
10097
}
10198

10299
static inline void _msgpack_unpacker_free_stack(msgpack_unpacker_stack_t* stack) {
103100
if (!msgpack_rmem_free(&s_stack_rmem, stack->data)) {
104101
rb_bug("Failed to free an rmem pointer, memory leak?");
105102
}
106-
xfree(stack);
103+
stack->data = NULL;
104+
stack->depth = 0;
107105
}
108106

109107
void _msgpack_unpacker_destroy(msgpack_unpacker_t* uk)
110108
{
111-
msgpack_unpacker_stack_t *stack;
112-
while ((stack = uk->stack)) {
113-
uk->stack = stack->parent;
114-
_msgpack_unpacker_free_stack(stack);
115-
}
116-
109+
_msgpack_unpacker_free_stack(&uk->stack);
117110
msgpack_buffer_destroy(UNPACKER_BUFFER_(uk));
118111
}
119112

120113
void msgpack_unpacker_mark_stack(msgpack_unpacker_stack_t* stack)
121114
{
122-
while (stack) {
115+
if (stack->data) {
123116
msgpack_unpacker_stack_entry_t* s = stack->data;
124117
msgpack_unpacker_stack_entry_t* send = stack->data + stack->depth;
125118
for(; s < send; s++) {
126119
rb_gc_mark(s->object);
127120
rb_gc_mark(s->key);
128121
}
129-
stack = stack->parent;
130122
}
131123
}
132124

133125
void msgpack_unpacker_mark(msgpack_unpacker_t* uk)
134126
{
135127
rb_gc_mark(uk->last_object);
136128
rb_gc_mark(uk->reading_raw);
137-
msgpack_unpacker_mark_stack(uk->stack);
129+
msgpack_unpacker_mark_stack(&uk->stack);
138130
/* See MessagePack_Buffer_wrap */
139131
/* msgpack_buffer_mark(UNPACKER_BUFFER_(uk)); */
140132
rb_gc_mark(uk->buffer_ref);
@@ -147,8 +139,8 @@ void _msgpack_unpacker_reset(msgpack_unpacker_t* uk)
147139

148140
uk->head_byte = HEAD_BYTE_REQUIRED;
149141

150-
/*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack->depth);*/
151-
uk->stack->depth = 0;
142+
/*memset(uk->stack, 0, sizeof(msgpack_unpacker_t) * uk->stack.depth);*/
143+
uk->stack.depth = 0;
152144
uk->last_object = Qnil;
153145
uk->reading_raw = Qnil;
154146
uk->reading_raw_remaining = 0;
@@ -232,35 +224,35 @@ static inline int object_complete_ext(msgpack_unpacker_t* uk, int ext_type, VALU
232224
/* stack funcs */
233225
static inline msgpack_unpacker_stack_entry_t* _msgpack_unpacker_stack_entry_top(msgpack_unpacker_t* uk)
234226
{
235-
return &uk->stack->data[uk->stack->depth-1];
227+
return &uk->stack.data[uk->stack.depth-1];
236228
}
237229

238230
static inline int _msgpack_unpacker_stack_push(msgpack_unpacker_t* uk, enum stack_type_t type, size_t count, VALUE object)
239231
{
240232
reset_head_byte(uk);
241233

242-
if(uk->stack->capacity - uk->stack->depth <= 0) {
234+
if(uk->stack.capacity - uk->stack.depth <= 0) {
243235
return PRIMITIVE_STACK_TOO_DEEP;
244236
}
245237

246-
msgpack_unpacker_stack_entry_t* next = &uk->stack->data[uk->stack->depth];
238+
msgpack_unpacker_stack_entry_t* next = &uk->stack.data[uk->stack.depth];
247239
next->count = count;
248240
next->type = type;
249241
next->object = object;
250242
next->key = Qnil;
251243

252-
uk->stack->depth++;
244+
uk->stack.depth++;
253245
return PRIMITIVE_CONTAINER_START;
254246
}
255247

256-
static inline VALUE msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
248+
static inline size_t msgpack_unpacker_stack_pop(msgpack_unpacker_t* uk)
257249
{
258-
return --uk->stack->depth;
250+
return --uk->stack.depth;
259251
}
260252

261253
static inline bool msgpack_unpacker_stack_is_empty(msgpack_unpacker_t* uk)
262254
{
263-
return uk->stack->depth == 0;
255+
return uk->stack.depth == 0;
264256
}
265257

266258
#ifdef USE_CASE_RANGE
@@ -301,7 +293,7 @@ union msgpack_buffer_cast_block_t {
301293

302294
static inline bool is_reading_map_key(msgpack_unpacker_t* uk)
303295
{
304-
if(uk->stack->depth > 0) {
296+
if(uk->stack.depth > 0) {
305297
msgpack_unpacker_stack_entry_t* top = _msgpack_unpacker_stack_entry_top(uk);
306298
if(top->type == STACK_TYPE_MAP_KEY) {
307299
return true;
@@ -356,14 +348,10 @@ static inline int read_raw_body_begin(msgpack_unpacker_t* uk, int raw_type)
356348
reset_head_byte(uk);
357349
uk->reading_raw_remaining = 0;
358350

359-
msgpack_unpacker_stack_t* child_stack = _msgpack_unpacker_new_stack();
360-
child_stack->parent = uk->stack;
361-
uk->stack = child_stack;
362-
351+
_msgpack_unpacker_stack_push(uk, STACK_TYPE_RECURSIVE, 1, Qnil);
363352
int raised;
364353
obj = protected_proc_call(proc, 1, &uk->self, &raised);
365-
uk->stack = child_stack->parent;
366-
_msgpack_unpacker_free_stack(child_stack);
354+
msgpack_unpacker_stack_pop(uk);
367355

368356
if (raised) {
369357
uk->last_object = rb_errinfo();
@@ -796,6 +784,8 @@ int msgpack_unpacker_read(msgpack_unpacker_t* uk, size_t target_stack_depth)
796784
}
797785
top->type = STACK_TYPE_MAP_KEY;
798786
break;
787+
case STACK_TYPE_RECURSIVE:
788+
return PRIMITIVE_OBJECT_COMPLETE;
799789
}
800790
size_t count = --top->count;
801791

ext/msgpack/unpacker.h

+6-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ enum stack_type_t {
3131
STACK_TYPE_ARRAY,
3232
STACK_TYPE_MAP_KEY,
3333
STACK_TYPE_MAP_VALUE,
34+
STACK_TYPE_RECURSIVE,
3435
};
3536

3637
typedef struct {
@@ -44,31 +45,31 @@ struct msgpack_unpacker_stack_t {
4445
size_t depth;
4546
size_t capacity;
4647
msgpack_unpacker_stack_entry_t *data;
47-
msgpack_unpacker_stack_t *parent;
4848
};
4949

5050
struct msgpack_unpacker_t {
5151
msgpack_buffer_t buffer;
52-
msgpack_unpacker_stack_t *stack;
53-
unsigned int head_byte;
52+
msgpack_unpacker_stack_t stack;
5453

5554
VALUE self;
5655
VALUE last_object;
5756

5857
VALUE reading_raw;
5958
size_t reading_raw_remaining;
60-
int reading_raw_type;
6159

6260
VALUE buffer_ref;
6361

6462
msgpack_unpacker_ext_registry_t *ext_registry;
6563

64+
int reading_raw_type;
65+
unsigned int head_byte;
66+
6667
/* options */
68+
int symbol_ext_type;
6769
bool symbolize_keys;
6870
bool freeze;
6971
bool allow_unknown_ext;
7072
bool optimized_symbol_ext_type;
71-
int symbol_ext_type;
7273
};
7374

7475
#define UNPACKER_BUFFER_(uk) (&(uk)->buffer)

ext/msgpack/unpacker_class.c

+5-6
Original file line numberDiff line numberDiff line change
@@ -58,17 +58,16 @@ static void Unpacker_mark(void *ptr)
5858

5959
static size_t Unpacker_memsize(const void *ptr)
6060
{
61+
const msgpack_unpacker_t* uk = ptr;
62+
6163
size_t total_size = sizeof(msgpack_unpacker_t);
6264

63-
const msgpack_unpacker_t* uk = ptr;
6465
if (uk->ext_registry) {
6566
total_size += sizeof(msgpack_unpacker_ext_registry_t) / (uk->ext_registry->borrow_count + 1);
6667
}
6768

68-
msgpack_unpacker_stack_t *stack = uk->stack;
69-
while (stack) {
70-
total_size += (stack->depth + 1) * sizeof(msgpack_unpacker_stack_t);
71-
stack = stack->parent;
69+
if (uk->stack.data) {
70+
total_size += (uk->stack.depth + 1) * sizeof(msgpack_unpacker_stack_t);
7271
}
7372

7473
return total_size + msgpack_buffer_memsize(&uk->buffer);
@@ -162,7 +161,7 @@ static VALUE Unpacker_allow_unknown_ext_p(VALUE self)
162161

163162
NORETURN(static void raise_unpacker_error(msgpack_unpacker_t *uk, int r))
164163
{
165-
uk->stack->depth = 0;
164+
uk->stack.depth = 0;
166165
switch(r) {
167166
case PRIMITIVE_EOF:
168167
rb_raise(rb_eEOFError, "end of buffer reached");

0 commit comments

Comments
 (0)