summaryrefslogtreecommitdiff
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
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).
-rw-r--r--node.c50
-rw-r--r--parse.y13
2 files changed, 62 insertions, 1 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
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;
}