summaryrefslogtreecommitdiff
path: root/node.c
diff options
context:
space:
mode:
authorAaron Patterson <tenderlove@ruby-lang.org>2019-08-29 15:22:41 -0700
committerAaron Patterson <tenderlove@ruby-lang.org>2019-09-05 10:13:49 -0700
commit581fcde0884e493206b04b3e6b7a069b941dfe46 (patch)
treef72f598a18bc148909871c1fc1cc64c0a2eb7276 /node.c
parent70d3596a4a2ef023243bf4805ce2a9cd6fdc0487 (diff)
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).
Diffstat (limited to 'node.c')
-rw-r--r--node.c50
1 files changed, 50 insertions, 0 deletions
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