From 581fcde0884e493206b04b3e6b7a069b941dfe46 Mon Sep 17 00:00:00 2001 From: Aaron Patterson Date: Thu, 29 Aug 2019 15:22:41 -0700 Subject: 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). --- node.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ parse.y | 13 ++++++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/node.c b/node.c index f4df845d2c..61926ad02f 100644 --- a/node.c +++ b/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 diff --git a/parse.y b/parse.y index 63d8f53c1d..3cf485d55a 100644 --- a/parse.y +++ b/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; } -- cgit v1.2.3