Directly mark node objects instead of using a mark array

This patch changes the AST mark function so that it will walk through
nodes in the NODE buffer marking Ruby objects rather than using a mark
array to guarantee liveness.  The reason I want to do this is so that
when compaction happens on major GCs, node objects will have their
references pinned (or possibly we can update them correctly).
This commit is contained in:
Aaron Patterson 2019-08-29 15:22:41 -07:00
Родитель 70d3596a4a
Коммит 581fcde088
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 953170BCB4FFAFC6
2 изменённых файлов: 62 добавлений и 1 удалений

50
node.c
Просмотреть файл

@ -1116,6 +1116,7 @@ rb_node_init(NODE *n, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
typedef struct node_buffer_elem_struct {
struct node_buffer_elem_struct *next;
long len;
NODE buf[FLEX_ARY_LEN];
} node_buffer_elem_t;
@ -1133,6 +1134,7 @@ rb_node_buffer_new(void)
nb->idx = 0;
nb->len = NODE_BUF_DEFAULT_LEN;
nb->head = nb->last = (node_buffer_elem_t*) &nb[1];
nb->head->len = nb->len;
nb->head->next = NULL;
nb->mark_ary = rb_ary_tmp_new(0);
return nb;
@ -1159,6 +1161,7 @@ rb_ast_newnode(rb_ast_t *ast)
long n = nb->len * 2;
node_buffer_elem_t *nbe;
nbe = xmalloc(offsetof(node_buffer_elem_t, buf) + n * sizeof(NODE));
nbe->len = n;
nb->idx = 0;
nb->len = n;
nbe->next = nb->head;
@ -1185,11 +1188,58 @@ rb_ast_new(void)
return ast;
}
typedef void node_itr_t(void *ctx, NODE * node);
static void
iterate_buffer_elements(node_buffer_elem_t *nbe, long len, node_itr_t *func, void *ctx)
{
long cursor;
for (cursor = 0; cursor < len; cursor++) {
func(ctx, &nbe->buf[cursor]);
}
}
static void
iterate_node_values(node_buffer_t *nb, node_itr_t * func, void *ctx)
{
node_buffer_elem_t *nbe = nb->head;
/* iterate over the head first because it's not full */
iterate_buffer_elements(nbe, nb->idx, func, ctx);
nbe = nbe->next;
while (nbe) {
iterate_buffer_elements(nbe, nbe->len, func, ctx);
nbe = nbe->next;
}
}
static void
mark_ast_value(void *ctx, NODE * node)
{
switch (nd_type(node)) {
case NODE_LIT:
case NODE_STR:
case NODE_XSTR:
case NODE_DSTR:
case NODE_DXSTR:
case NODE_DREGX:
case NODE_DSYM:
rb_gc_mark(node->nd_lit);
break;
}
}
void
rb_ast_mark(rb_ast_t *ast)
{
if (ast->node_buffer) rb_gc_mark(ast->node_buffer->mark_ary);
if (ast->body.compile_option) rb_gc_mark(ast->body.compile_option);
if (ast->node_buffer) {
node_buffer_t *nb = ast->node_buffer;
iterate_node_values(nb, mark_ast_value, NULL);
}
}
void

13
parse.y
Просмотреть файл

@ -299,7 +299,7 @@ struct parser_params {
};
#define new_tmpbuf() \
(rb_imemo_tmpbuf_t *)add_mark_object(p, rb_imemo_tmpbuf_auto_free_pointer(NULL))
(rb_imemo_tmpbuf_t *)add_tmpbuf_mark_object(p, rb_imemo_tmpbuf_auto_free_pointer(NULL))
#define intern_cstr(n,l,en) rb_intern3(n,l,en)
@ -337,6 +337,13 @@ rb_discard_node(struct parser_params *p, NODE *n)
{
rb_ast_delete_node(p->ast, n);
}
static inline VALUE
add_tmpbuf_mark_object(struct parser_params *p, VALUE obj)
{
rb_ast_add_mark_object(p->ast, obj);
return obj;
}
#endif
static inline VALUE
@ -347,7 +354,11 @@ add_mark_object(struct parser_params *p, VALUE obj)
&& !RB_TYPE_P(obj, T_NODE) /* Ripper jumbles NODE objects and other objects... */
#endif
) {
#ifdef RIPPER
rb_ast_add_mark_object(p->ast, obj);
#else
RB_OBJ_WRITTEN(p->ast, Qundef, obj);
#endif
}
return obj;
}