diff --git a/node.c b/node.c index 7cd238a37c..0e1b04bbf4 100644 --- a/node.c +++ b/node.c @@ -1116,30 +1116,45 @@ 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; -struct node_buffer_struct { +typedef struct { long idx, len; node_buffer_elem_t *head; node_buffer_elem_t *last; +} node_buffer_list_t; + +struct node_buffer_struct { + node_buffer_list_t unmarkable; + node_buffer_list_t markable; VALUE mark_ary; }; +static void +init_node_buffer_list(node_buffer_list_t * nb, node_buffer_elem_t *head) +{ + nb->idx = 0; + nb->len = NODE_BUF_DEFAULT_LEN; + nb->head = nb->last = head; + nb->head->len = nb->len; + nb->head->next = NULL; +} + static node_buffer_t * rb_node_buffer_new(void) { - node_buffer_t *nb = xmalloc(sizeof(node_buffer_t) + offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE)); - nb->idx = 0; - nb->len = NODE_BUF_DEFAULT_LEN; - nb->head = nb->last = (node_buffer_elem_t*) &nb[1]; - nb->head->next = NULL; - nb->mark_ary = rb_ary_tmp_new(0); + size_t bucket_size = offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE); + node_buffer_t *nb = xmalloc(sizeof(node_buffer_t) + (bucket_size * 2)); + init_node_buffer_list(&nb->unmarkable, (node_buffer_elem_t*)&nb[1]); + init_node_buffer_list(&nb->markable, (node_buffer_elem_t*)((size_t)nb->unmarkable.head + bucket_size)); + nb->mark_ary = Qnil; return nb; } static void -rb_node_buffer_free(node_buffer_t *nb) +node_buffer_list_free(node_buffer_list_t * nb) { node_buffer_elem_t *nbe = nb->head; @@ -1148,17 +1163,24 @@ rb_node_buffer_free(node_buffer_t *nb) nbe = nbe->next; xfree(buf); } +} + +static void +rb_node_buffer_free(node_buffer_t *nb) +{ + node_buffer_list_free(&nb->unmarkable); + node_buffer_list_free(&nb->markable); xfree(nb); } -NODE * -rb_ast_newnode(rb_ast_t *ast) +static NODE * +ast_newnode_in_bucket(node_buffer_list_t *nb) { - node_buffer_t *nb = ast->node_buffer; if (nb->idx >= nb->len) { 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; @@ -1167,6 +1189,27 @@ rb_ast_newnode(rb_ast_t *ast) return &nb->head->buf[nb->idx++]; } +NODE * +rb_ast_newnode(rb_ast_t *ast, enum node_type type) +{ + node_buffer_t *nb = ast->node_buffer; + switch (type) { + case NODE_LIT: + case NODE_STR: + case NODE_XSTR: + case NODE_DSTR: + case NODE_DXSTR: + case NODE_DREGX: + case NODE_DSYM: + case NODE_ARGS: + case NODE_SCOPE: + case NODE_ARYPTN: + return ast_newnode_in_bucket(&nb->markable); + default: + return ast_newnode_in_bucket(&nb->unmarkable); + } +} + void rb_ast_delete_node(rb_ast_t *ast, NODE *n) { @@ -1179,17 +1222,85 @@ rb_ast_t * rb_ast_new(void) { node_buffer_t *nb = rb_node_buffer_new(); - VALUE mark_ary = nb->mark_ary; rb_ast_t *ast = (rb_ast_t *)rb_imemo_new(imemo_ast, 0, 0, 0, (VALUE)nb); - RB_OBJ_WRITTEN(ast, Qnil, mark_ary); 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_list_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_SCOPE: + { + ID *buf = node->nd_tbl; + if (buf) { + unsigned int size = (unsigned int)*buf; + rb_gc_mark((VALUE)buf[size + 1]); + } + break; + } + case NODE_ARYPTN: + { + struct rb_ary_pattern_info *apinfo = node->nd_apinfo; + rb_gc_mark(apinfo->imemo); + break; + } + case NODE_ARGS: + { + struct rb_args_info *args = node->nd_ainfo; + rb_gc_mark(args->imemo); + break; + } + 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; + default: + rb_bug("unreachable"); + } +} + 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->markable, mark_ast_value, NULL); + } } void @@ -1201,6 +1312,18 @@ rb_ast_free(rb_ast_t *ast) } } +static size_t +buffer_list_size(node_buffer_list_t *nb) +{ + size_t size = 0; + node_buffer_elem_t *nbe = nb->head; + while (nbe != nb->last) { + nbe = nbe->next; + size += offsetof(node_buffer_elem_t, buf) + nb->len * sizeof(NODE); + } + return size; +} + size_t rb_ast_memsize(const rb_ast_t *ast) { @@ -1209,11 +1332,8 @@ rb_ast_memsize(const rb_ast_t *ast) if (nb) { size += sizeof(node_buffer_t) + offsetof(node_buffer_elem_t, buf) + NODE_BUF_DEFAULT_LEN * sizeof(NODE); - node_buffer_elem_t *nbe = nb->head; - while (nbe != nb->last) { - nbe = nbe->next; - size += offsetof(node_buffer_elem_t, buf) + nb->len * sizeof(NODE); - } + size += buffer_list_size(&nb->unmarkable); + size += buffer_list_size(&nb->markable); } return size; } @@ -1227,5 +1347,8 @@ rb_ast_dispose(rb_ast_t *ast) void rb_ast_add_mark_object(rb_ast_t *ast, VALUE obj) { + if (NIL_P(ast->node_buffer->mark_ary)) { + RB_OBJ_WRITE(ast, &ast->node_buffer->mark_ary, rb_ary_tmp_new(0)); + } rb_ary_push(ast->node_buffer->mark_ary, obj); } diff --git a/node.h b/node.h index 22d10a2d58..d39cae86f2 100644 --- a/node.h +++ b/node.h @@ -408,7 +408,7 @@ void rb_ast_dispose(rb_ast_t*); void rb_ast_free(rb_ast_t*); size_t rb_ast_memsize(const rb_ast_t*); void rb_ast_add_mark_object(rb_ast_t*, VALUE); -NODE *rb_ast_newnode(rb_ast_t*); +NODE *rb_ast_newnode(rb_ast_t*, enum node_type type); void rb_ast_delete_node(rb_ast_t*, NODE *n); VALUE rb_parser_new(void); @@ -451,12 +451,14 @@ struct rb_args_info { NODE *opt_args; int no_kwarg; + VALUE imemo; }; struct rb_ary_pattern_info { NODE *pre_args; NODE *rest_arg; NODE *post_args; + VALUE imemo; }; struct parser_params; diff --git a/parse.y b/parse.y index a3b3cd7224..7e2cfe0854 100644 --- a/parse.y +++ b/parse.y @@ -298,9 +298,6 @@ struct parser_params { #endif }; -#define new_tmpbuf() \ - (rb_imemo_tmpbuf_t *)add_mark_object(p, rb_imemo_tmpbuf_auto_free_pointer(NULL)) - #define intern_cstr(n,l,en) rb_intern3(n,l,en) #define STR_NEW(ptr,len) rb_enc_str_new((ptr),(len),p->enc) @@ -347,7 +344,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; } @@ -2786,10 +2787,11 @@ primary : literal ID id = internal_id(p); NODE *m = NEW_ARGS_AUX(0, 0, &NULL_LOC); NODE *args, *scope, *internal_var = NEW_DVAR(id, &@2); - rb_imemo_tmpbuf_t *tmpbuf = new_tmpbuf(); - ID *tbl = ALLOC_N(ID, 2); + ID *tbl = ALLOC_N(ID, 3); + VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer(tbl); + RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf); tbl[0] = 1 /* length of local var table */; tbl[1] = id /* internal id */; - tmpbuf->ptr = (VALUE *)tbl; + tbl[2] = tmpbuf; switch (nd_type($2)) { case NODE_LASGN: @@ -9355,7 +9357,7 @@ yylex(YYSTYPE *lval, YYLTYPE *yylloc, struct parser_params *p) static NODE* node_newnode(struct parser_params *p, enum node_type type, VALUE a0, VALUE a1, VALUE a2, const rb_code_location_t *loc) { - NODE *n = rb_ast_newnode(p->ast); + NODE *n = rb_ast_newnode(p->ast, type); rb_node_init(n, type, a0, a1, a2); @@ -9609,9 +9611,7 @@ literal_concat(struct parser_params *p, NODE *head, NODE *tail, const YYLTYPE *l goto append; } else { - nd_set_type(tail, NODE_LIST); - tail->nd_head = NEW_STR(tail->nd_lit, loc); - list_concat(head, tail); + list_concat(head, NEW_NODE(NODE_LIST, NEW_STR(tail->nd_lit, loc), tail->nd_alen, tail->nd_next, loc)); } break; @@ -11125,10 +11125,11 @@ new_args_tail(struct parser_params *p, NODE *kw_args, ID kw_rest_arg, ID block, int saved_line = p->ruby_sourceline; struct rb_args_info *args; NODE *node; - rb_imemo_tmpbuf_t *tmpbuf = new_tmpbuf(); args = ZALLOC(struct rb_args_info); - tmpbuf->ptr = (VALUE *)args; + VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer(args); + args->imemo = tmpbuf; + RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf); node = NEW_NODE(NODE_ARGS, 0, 0, args, &NULL_LOC); if (p->error_p) return node; @@ -11234,11 +11235,12 @@ new_array_pattern_tail(struct parser_params *p, NODE *pre_args, int has_rest, ID int saved_line = p->ruby_sourceline; struct rb_ary_pattern_info *apinfo; NODE *node; - rb_imemo_tmpbuf_t *tmpbuf = new_tmpbuf(); apinfo = ZALLOC(struct rb_ary_pattern_info); - tmpbuf->ptr = (VALUE *)apinfo; + VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer(apinfo); node = NEW_NODE(NODE_ARYPTN, 0, 0, apinfo, loc); + apinfo->imemo = tmpbuf; + RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf); apinfo->pre_args = pre_args; @@ -11623,11 +11625,9 @@ local_tbl(struct parser_params *p) int cnt = cnt_args + cnt_vars; int i, j; ID *buf; - rb_imemo_tmpbuf_t *tmpbuf = new_tmpbuf(); if (cnt <= 0) return 0; - buf = ALLOC_N(ID, cnt + 1); - tmpbuf->ptr = (void *)buf; + buf = ALLOC_N(ID, cnt + 2); MEMCPY(buf+1, p->lvtbl->args->tbl, ID, cnt_args); /* remove IDs duplicated to warn shadowing */ for (i = 0, j = cnt_args+1; i < cnt_vars; ++i) { @@ -11636,9 +11636,13 @@ local_tbl(struct parser_params *p) buf[j++] = id; } } - if (--j < cnt) tmpbuf->ptr = (void *)REALLOC_N(buf, ID, (cnt = j) + 1); + if (--j < cnt) REALLOC_N(buf, ID, (cnt = j) + 2); buf[0] = cnt; + VALUE tmpbuf = rb_imemo_tmpbuf_auto_free_pointer(buf); + buf[cnt + 1] = (ID)tmpbuf; + RB_OBJ_WRITTEN(p->ast, Qnil, tmpbuf); + return buf; } #endif