[前][次][番号順一覧][スレッド一覧]

ruby-changes:48371

From: mame <ko1@a...>
Date: Sat, 28 Oct 2017 00:59:11 +0900 (JST)
Subject: [ruby-changes:48371] mame:r60485 (trunk): Manage AST NODEs out of GC

mame	2017-10-28 00:59:02 +0900 (Sat, 28 Oct 2017)

  New Revision: 60485

  https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=60485

  Log:
    Manage AST NODEs out of GC
    
    NODEs in AST are no longer objects managed by GC.  This change will
    remove the restriction imposed by the GC.  For example, a NODE can use
    more than five words (this is my primary purpose; we want to store the
    position data for each NODE, for coverage library), or even a NODE can
    have variable length (some kinds of NODEs have unused fields).
    To do this, however, we need more work, since Ripper still uses T_NODE
    objects managed by the GC.
    
    The life time of NODEs is more obvious than other kinds of objects; they
    are created at parsing, and they become disused immediately after
    compilation.  This change releases all NODEs by a few `xfree`s after
    compilation, so performance will be improved a bit.  In extreme example,
    `eval("x=1;" * 10000000)` runs much faster (40 sec. -> 7.8 sec. on my
    machine).
    
    The most important part of this change is `ast_t` struct, which has
    three contents: (1) NODE buffer (malloc'ed memory), (2) a reference to
    the root NODE, and (3) an array that contains objects that must be
    marked during parsing (such as literal objects).  Some functions that
    had received `NODE*` arguments, must now receive `ast_t*`.
    
    * node.c, node.h: defines `ast_t` struct and related operations.
    * gc.c, internal.h: defines `imemo_ast`.
    * parse.y: makes `parser_params` struct have a reference to `ast_t`.
      Instead of `rb_node_newnode`, use `rb_ast_newnode` to create a NODE.
    * iseq.c, load.c, ruby.c, template/prelude.c.tmpl: modifies some
      functions to handle `ast_t*` instead of `NODE*`.
    * test/ruby/test_gc.rb: ad-hoc fix for a failed test.  The test assumes
      GC eden is increased at startup by NODE object creation.  However,
      this change now create no NODE object, so GC eden is not necessarily
      increased.

  Modified files:
    trunk/gc.c
    trunk/internal.h
    trunk/iseq.c
    trunk/load.c
    trunk/node.c
    trunk/node.h
    trunk/parse.y
    trunk/ruby.c
    trunk/template/prelude.c.tmpl
    trunk/test/ruby/test_gc.rb
Index: test/ruby/test_gc.rb
===================================================================
--- test/ruby/test_gc.rb	(revision 60484)
+++ test/ruby/test_gc.rb	(revision 60485)
@@ -290,6 +290,9 @@ class TestGc < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_gc.rb#L290
     base_length = GC.stat[:heap_eden_pages]
     (base_length * 500).times{ 'a' }
     GC.start
+    base_length = GC.stat[:heap_eden_pages]
+    (base_length * 500).times{ 'a' }
+    GC.start
     assert_in_epsilon base_length, (v = GC.stat[:heap_eden_pages]), 1/8r,
            "invalid heap expanding (base_length: #{base_length}, GC.stat[:heap_eden_pages]: #{v})"
 
Index: internal.h
===================================================================
--- internal.h	(revision 60484)
+++ internal.h	(revision 60485)
@@ -844,7 +844,8 @@ enum imemo_type { https://github.com/ruby/ruby/blob/trunk/internal.h#L844
     imemo_memo       = 5,
     imemo_ment       = 6,
     imemo_iseq       = 7,
-    imemo_alloc      = 8
+    imemo_alloc      = 8,
+    imemo_ast        = 9
 };
 #define IMEMO_MASK   0x0f
 
Index: iseq.c
===================================================================
--- iseq.c	(revision 60484)
+++ iseq.c	(revision 60485)
@@ -641,9 +641,9 @@ rb_iseq_compile_with_option(VALUE src, V https://github.com/ruby/ruby/blob/trunk/iseq.c#L641
 #else
 # define INITIALIZED /* volatile */
 #endif
-    NODE *(*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
+    ast_t *(*parse)(VALUE vparser, VALUE fname, VALUE file, int start);
     int ln;
-    NODE *INITIALIZED node;
+    ast_t *INITIALIZED ast;
 
     /* safe results first */
     make_compile_option(&option, opt);
@@ -659,18 +659,20 @@ rb_iseq_compile_with_option(VALUE src, V https://github.com/ruby/ruby/blob/trunk/iseq.c#L659
     {
 	const VALUE parser = rb_parser_new();
 	rb_parser_set_context(parser, base_block, FALSE);
-	node = (*parse)(parser, file, src, ln);
+	ast = (*parse)(parser, file, src, ln);
     }
 
-    if (!node) {
+    if (!ast->root) {
+	rb_ast_dispose(ast);
 	rb_exc_raise(th->ec->errinfo);
     }
     else {
 	INITIALIZED VALUE label = parent ?
 	    parent->body->location.label :
 	    rb_fstring_cstr("<compiled>");
-	iseq = rb_iseq_new_with_opt(node, label, file, realpath, line,
+	iseq = rb_iseq_new_with_opt(ast->root, label, file, realpath, line,
 				    parent, type, &option);
+	rb_ast_dispose(ast);
     }
 
     return iseq;
@@ -851,8 +853,8 @@ static VALUE https://github.com/ruby/ruby/blob/trunk/iseq.c#L853
 iseqw_s_compile_file(int argc, VALUE *argv, VALUE self)
 {
     VALUE file, line = INT2FIX(1), opt = Qnil;
-    VALUE parser, f, exc = Qnil;
-    const NODE *node;
+    VALUE parser, f, exc = Qnil, ret;
+    ast_t *ast;
     rb_compile_option_t option;
     int i;
 
@@ -869,18 +871,23 @@ iseqw_s_compile_file(int argc, VALUE *ar https://github.com/ruby/ruby/blob/trunk/iseq.c#L871
 
     parser = rb_parser_new();
     rb_parser_set_context(parser, NULL, FALSE);
-    node = rb_parser_compile_file_path(parser, file, f, NUM2INT(line));
-    if (!node) exc = GET_EC()->errinfo;
+    ast = rb_parser_compile_file_path(parser, file, f, NUM2INT(line));
+    if (!ast->root) exc = GET_EC()->errinfo;
 
     rb_io_close(f);
-    if (!node) rb_exc_raise(exc);
+    if (!ast->root) {
+	rb_ast_dispose(ast);
+	rb_exc_raise(exc);
+    }
 
     make_compile_option(&option, opt);
 
-    return iseqw_new(rb_iseq_new_with_opt(node, rb_fstring_cstr("<main>"),
-					  file,
-					  rb_realpath_internal(Qnil, file, 1),
-					  line, NULL, ISEQ_TYPE_TOP, &option));
+    ret = iseqw_new(rb_iseq_new_with_opt(ast->root, rb_fstring_cstr("<main>"),
+					 file,
+					 rb_realpath_internal(Qnil, file, 1),
+					 line, NULL, ISEQ_TYPE_TOP, &option));
+    rb_ast_dispose(ast);
+    return ret;
 }
 
 /*
Index: load.c
===================================================================
--- load.c	(revision 60484)
+++ load.c	(revision 60485)
@@ -602,7 +602,7 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L602
     EC_PUSH_TAG(th->ec);
     state = EXEC_TAG();
     if (state == TAG_NONE) {
-	NODE *node;
+	ast_t *ast;
 	const rb_iseq_t *iseq;
 
 	if ((iseq = rb_iseq_load_iseq(fname)) != NULL) {
@@ -611,9 +611,10 @@ rb_load_internal0(rb_thread_t *th, VALUE https://github.com/ruby/ruby/blob/trunk/load.c#L611
 	else {
 	    VALUE parser = rb_parser_new();
 	    rb_parser_set_context(parser, NULL, FALSE);
-	    node = (NODE *)rb_parser_load_file(parser, fname);
-	    iseq = rb_iseq_new_top(node, rb_fstring_cstr("<top (required)>"),
+	    ast = (ast_t *)rb_parser_load_file(parser, fname);
+	    iseq = rb_iseq_new_top(ast->root, rb_fstring_cstr("<top (required)>"),
 			    fname, rb_realpath_internal(Qnil, fname, 1), NULL);
+	    rb_ast_dispose(ast);
 	}
 	rb_iseq_eval(iseq);
     }
Index: gc.c
===================================================================
--- gc.c	(revision 60484)
+++ gc.c	(revision 60485)
@@ -434,6 +434,7 @@ typedef struct RVALUE { https://github.com/ruby/ruby/blob/trunk/gc.c#L434
 	    const rb_iseq_t iseq;
 	    rb_env_t env;
 	    struct rb_imemo_alloc_struct alloc;
+	    ast_t ast;
 	} imemo;
 	struct {
 	    struct RBasic basic;
@@ -2359,6 +2360,9 @@ obj_free(rb_objspace_t *objspace, VALUE https://github.com/ruby/ruby/blob/trunk/gc.c#L2360
 	  case imemo_alloc:
 	    xfree(RANY(obj)->as.imemo.alloc.ptr);
 	    break;
+	  case imemo_ast:
+	    rb_ast_free(&RANY(obj)->as.imemo.ast);
+	    break;
 	  default:
 	    break;
 	}
@@ -4540,6 +4544,9 @@ gc_mark_imemo(rb_objspace_t *objspace, V https://github.com/ruby/ruby/blob/trunk/gc.c#L4544
 	    } while ((m = m->next) != NULL);
 	}
 	return;
+      case imemo_ast:
+	rb_ast_mark(&RANY(obj)->as.imemo.ast);
+	return;
 #if VM_CHECK_MODE > 0
       default:
 	VM_UNREACHABLE(gc_mark_imemo);
Index: template/prelude.c.tmpl
===================================================================
--- template/prelude.c.tmpl	(revision 60484)
+++ template/prelude.c.tmpl	(revision 60485)
@@ -121,10 +121,14 @@ prelude_eval(VALUE code, VALUE name, int https://github.com/ruby/ruby/blob/trunk/template/prelude.c.tmpl#L121
 	FALSE, /* int debug_frozen_string_literal; */
     };
 
-    NODE *node = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
-    if (!node) rb_exc_raise(rb_errinfo());
-    rb_iseq_eval(rb_iseq_new_with_opt(node, name, name, Qnil, INT2FIX(line),
+    ast_t *ast = rb_parser_compile_string_path(rb_parser_new(), name, code, line);
+    if (!ast->root) {
+	rb_ast_dispose(ast);
+	rb_exc_raise(rb_errinfo());
+    }
+    rb_iseq_eval(rb_iseq_new_with_opt(ast->root, name, name, Qnil, INT2FIX(line),
 				      NULL, ISEQ_TYPE_TOP, &optimization));
+    rb_ast_dispose(ast);
 }
 % end
 
Index: ruby.c
===================================================================
--- ruby.c	(revision 60484)
+++ ruby.c	(revision 60485)
@@ -177,7 +177,7 @@ cmdline_options_init(ruby_cmdline_option https://github.com/ruby/ruby/blob/trunk/ruby.c#L177
     return opt;
 }
 
-static NODE *load_file(VALUE parser, VALUE fname, VALUE f, int script,
+static ast_t *load_file(VALUE parser, VALUE fname, VALUE f, int script,
 		       ruby_cmdline_options_t *opt);
 static VALUE open_load_file(VALUE fname_v, int *xflag);
 static void forbid_setid(const char *, const ruby_cmdline_options_t *);
@@ -1461,7 +1461,7 @@ rb_f_chomp(int argc, VALUE *argv) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1461
 static VALUE
 process_options(int argc, char **argv, ruby_cmdline_options_t *opt)
 {
-    NODE *tree = 0;
+    ast_t *ast = 0;
     VALUE parser;
     VALUE script_name;
     const rb_iseq_t *iseq;
@@ -1674,12 +1674,12 @@ process_options(int argc, char **argv, r https://github.com/ruby/ruby/blob/trunk/ruby.c#L1674
         ruby_set_script_name(progname);
 	rb_parser_set_options(parser, opt->do_print, opt->do_loop,
 			      opt->do_line, opt->do_split);
-	tree = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
+	ast = rb_parser_compile_string(parser, opt->script, opt->e_script, 1);
     }
     else {
 	VALUE f;
 	f = open_load_file(script_name, &opt->xflag);
-	tree = load_file(parser, opt->script_name, f, 1, opt);
+	ast = load_file(parser, opt->script_name, f, 1, opt);
     }
     ruby_set_script_name(opt->script_name);
     if (dump & DUMP_BIT(yydebug)) {
@@ -1704,7 +1704,10 @@ process_options(int argc, char **argv, r https://github.com/ruby/ruby/blob/trunk/ruby.c#L1704
 	rb_enc_set_default_internal(Qnil);
     rb_stdio_set_default_encoding();
 
-    if (!tree) return Qfalse;
+    if (!ast->root) {
+	rb_ast_dispose(ast);
+	return Qfalse;
+    }
 
     process_sflag(&opt->sflag);
     opt->xflag = 0;
@@ -1723,10 +1726,13 @@ process_options(int argc, char **argv, r https://github.com/ruby/ruby/blob/trunk/ruby.c#L1726
     }
 
     if (dump & (DUMP_BIT(parsetree)|DUMP_BIT(parsetree_with_comment))) {
-	rb_io_write(rb_stdout, rb_parser_dump_tree(tree, dump & DUMP_BIT(parsetree_with_comment)));
+	rb_io_write(rb_stdout, rb_parser_dump_tree(ast->root, dump & DUMP_BIT(parsetree_with_comment)));
 	rb_io_flush(rb_stdout);
 	dump &= ~DUMP_BIT(parsetree)&~DUMP_BIT(parsetree_with_comment);
-	if (!dump) return Qtrue;
+	if (!dump) {
+	    rb_ast_dispose(ast);
+	    return Qtrue;
+	}
     }
 
     {
@@ -1740,7 +1746,8 @@ process_options(int argc, char **argv, r https://github.com/ruby/ruby/blob/trunk/ruby.c#L1746
 #endif
 	}
 	base_block = toplevel_context(toplevel_binding);
-	iseq = rb_iseq_new_main(tree, opt->script_name, path, vm_block_iseq(base_block));
+	iseq = rb_iseq_new_main(ast->root, opt->script_name, path, vm_block_iseq(base_block));
+	rb_ast_dispose(ast);
     }
 
     if (dump & DUMP_BIT(insns)) {
@@ -1790,7 +1797,7 @@ load_file_internal(VALUE argp_v) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1797
     ruby_cmdline_options_t *opt = argp->opt;
     VALUE f = argp->f;
     int line_start = 1;
-    NODE *tree = 0;
+    ast_t *ast = 0;
     rb_encoding *enc;
     ID set_encoding;
 
@@ -1894,7 +1901,7 @@ load_file_internal(VALUE argp_v) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1901
 	return (VALUE)rb_parser_compile_string_path(parser, orig_fname, f, line_start);
     }
     rb_funcall(f, set_encoding, 2, rb_enc_from_encoding(enc), rb_str_new_cstr("-"));
-    tree = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
+    ast = rb_parser_compile_file_path(parser, orig_fname, f, line_start);
     rb_funcall(f, set_encoding, 1, rb_parser_encoding(parser));
     if (script && rb_parser_end_seen_p(parser)) {
 	/*
@@ -1912,7 +1919,7 @@ load_file_internal(VALUE argp_v) https://github.com/ruby/ruby/blob/trunk/ruby.c#L1919
 	rb_define_global_const("DATA", f);
 	argp->f = Qnil;
     }
-    return (VALUE)tree;
+    return (VALUE)ast;
 }
 
 static VALUE
@@ -2004,7 +2011,7 @@ restore_load_file(VALUE arg) https://github.com/ruby/ruby/blob/trunk/ruby.c#L2011
     return Qnil;
 }
 
-static NODE *
+static ast_t *
 load_file(VALUE parser, VALUE fname, VALUE f, int script, ruby_cmdline_options_t *opt)
 {
     struct load_file_arg arg;
@@ -2013,8 +2020,8 @@ load_file(VALUE parser, VALUE fname, VAL https://github.com/ruby/ruby/blob/trunk/ruby.c#L2020
     arg.script = script;
     arg.opt = opt;
     arg.f = f;
-    return (NODE *)rb_ensure(load_file_internal, (VALUE)&arg,
-			     restore_load_file, (VALUE)&arg);
+    return (ast_t *)rb_ensure(load_file_internal, (VALUE)&arg,
+			      restore_load_file, (VALUE)&arg);
 }
 
 void *
Index: parse.y
===================================================================
--- parse.y	(revision 60484)
+++ parse.y	(revision 60485)
@@ -239,6 +239,7 @@ struct parser_params { https://github.com/ruby/ruby/blob/trunk/parse.y#L239
     unsigned int do_chomp: 1;
     unsigned int do_split: 1;
 
+    ast_t *ast;
     NODE *eval_tree_begin;
     NODE *eval_tree;
     VALUE error_buffer;
@@ -338,15 +339,27 @@ parser_set_line(NODE *n, int l) https://github.com/ruby/ruby/blob/trunk/parse.y#L339
 }
 
 static inline void
-rb_discard_node(NODE *n)
+rb_discard_node_gen(struct parser_params *parser, NODE *n)
 {
+#ifndef RIPPER
+    rb_ast_delete_node(parser->ast, n);
+#else
     rb_gc_force_recycle((VALUE)n);
+#endif
 }
-
-#define add_mark_object(obj) (void)(obj)
+#define rb_discard_node(n) rb_discard_node_gen(parser, (n))
 
 #ifndef RIPPER
 static inline void
+add_mark_object_gen(struct parser_params *parser, VALUE obj)
+{
+    if (!SPECIAL_CONST_P(obj)) {
+	rb_ast_add_mark_object(parser->ast, obj);
+    }
+}
+#define add_mark_object(obj) add_mark_object_gen(parser, (obj))
+
+static inline void
 set_line_body(NODE *body, int line)
 {
     if (!body) return;
@@ -575,6 +588,8 @@ static NODE *parser_heredoc_dedent(struc https://github.com/ruby/ruby/blob/trunk/parse.y#L588
 #else  /* RIPPER */
 #define NODE_RIPPER NODE_CDECL
 
+#define add_mark_object(obj) (void)(obj)
+
 static inline VALUE
 ripper_new_yylval(ID a, VALUE b, VALUE c)
 {
@@ -2850,6 +2865,7 @@ primary		: literal https://github.com/ruby/ruby/blob/trunk/parse.y#L2865
 				break;
 			    }
 			}
+			add_mark_object((VALUE)rb_imemo_alloc_new((VALUE)tbl, 0, 0, 0));
 			scope = NEW_NODE(NODE_SCOPE, tbl, $8, args);
 			nd_set_column(scope, @1.first_column);
 			tbl[0] = 1; tbl[1] = id;
@@ -5573,52 +5589,55 @@ lex_getline(struct parser_params *parser https://github.com/ruby/ruby/blob/trunk/parse.y#L5589
 static const rb_data_type_t parser_data_type;
 
 #ifndef RIPPER
-static NODE*
+static ast_t*
 parser_compile_string(VALUE vparser, VALUE fname, VALUE s, int line)
 {
     struct parser_params *parser;
-    NODE *node;
+    ast_t *ast;
 
     TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, parser);
+    parser->ast = ast = rb_ast_new();
+
     lex_gets = lex_get_str;
     lex_gets_ptr = 0;
     lex_input = rb_str_new_frozen(s);
     lex_pbeg = lex_p = lex_pend = 0;
 
-    node = yycompile(parser, fname, line);
+    ast->root = yycompile(parser, fname, line);
+    parser->ast = 0;
     RB_GC_GUARD(vparser); /* prohibit tail call optimization */
 
-    return node;
+    return ast;
 }
 
-NODE*
+ast_t*
 rb_compile_string(const char *f, VALUE s, int line)
 {
     must_be_ascii_compatible(s);
     return parser_compile_string(rb_parser_new(), rb_filesystem_str_new_cstr(f), s, line);
 }
 
-NODE*
+ast_t*
 rb_parser_compile_string(VALUE vparser, const char *f, VALUE s, int line)
 {
     return rb_parser_compile_string_path(vparser, rb_filesystem_str_new_cstr(f), s, line);
 }
 
-NODE*
+ast_t*
 rb_parser_compile_string_path(VALUE vparser, VALUE f, VALUE s, int line)
 {
     must_be_ascii_compatible(s);
     return parser_compile_string(vparser, f, s, line);
 }
 
-NODE*
+ast_t*
 rb_compile_cstr(const char *f, const char *s, int len, int line)
 {
     VALUE str = rb_str_new(s, len);
     return parser_compile_string(rb_parser_new(), rb_filesystem_str_new_cstr(f), str, line);
 }
 
-NODE*
+ast_t*
 rb_parser_compile_cstr(VALUE vparser, const char *f, const char *s, int len, int line)
 {
     VALUE str = rb_str_new(s, len);
@@ -5633,7 +5652,7 @@ lex_io_gets(struct parser_params *parser https://github.com/ruby/ruby/blob/trunk/parse.y#L5652
     return rb_io_gets_internal(io);
 }
 
-NODE*
+ast_t*
 rb_compile_file(const char *f, VALUE file, int start)
 {
     VALUE vparser = rb_parser_new();
@@ -5641,27 +5660,30 @@ rb_compile_file(const char *f, VALUE fil https://github.com/ruby/ruby/blob/trunk/parse.y#L5660
     return rb_parser_compile_file(vparser, f, file, start);
 }
 
-NODE*
+ast_t*
 rb_parser_compile_file(VALUE vparser, const char *f, VALUE file, int start)
 {
     return rb_parser_compile_file_path(vparser, rb_filesystem_str_new_cstr(f), file, start);
 }
 
-NODE*
+ast_t*
 rb_parser_compile_file_path(VALUE vparser, VALUE fname, VALUE file, int start)
 {
     struct parser_params *parser;
-    NODE *node;
+    ast_t *ast;
 
     TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, parser);
+    parser->ast = ast = rb_ast_new();
+
     lex_gets = lex_io_gets;
     lex_input = file;
     lex_pbeg = lex_p = lex_pend = 0;
 
-    node = yycompile(parser, fname, start);
+    ast->root = yycompile(parser, fname, start);
+    parser->ast = 0;
     RB_GC_GUARD(vparser); /* prohibit tail call optimization */
 
-    return node;
+    return ast;
 }
 #endif  /* !RIPPER */
 
@@ -6160,8 +6182,11 @@ parser_regx_options(struct parser_params https://github.com/ruby/ruby/blob/trunk/parse.y#L6182
 }
 
 static void
-dispose_string(VALUE str)
+dispose_string(struct parser_params *parser, VALUE str)
 {
+#ifndef RIPPER
+    rb_ast_delete_mark_object(parser->ast, str);
+#endif
     rb_str_free(str);
     rb_gc_force_recycle(str);
 }
@@ -6639,7 +6664,7 @@ parser_heredoc_restore(struct parser_par https://github.com/ruby/ruby/blob/trunk/parse.y#L6664
     lex_p = lex_pbeg + here->nd_nth;
     heredoc_end = ruby_sourceline;
     ruby_sourceline = nd_line(here);
-    dispose_string(here->nd_lit);
+    dispose_string(parser, here->nd_lit);
     rb_discard_node(here);
     token_flush(parser);
 }
@@ -6925,7 +6950,7 @@ parser_here_document(struct parser_param https://github.com/ruby/ruby/blob/trunk/parse.y#L6950
 	    }
 	    if (nextc() == -1) {
 		if (str) {
-		    dispose_string(str);
+		    dispose_string(parser, str);
 		    str = 0;
 		}
 		goto error;
@@ -8800,7 +8825,10 @@ yylex(YYSTYPE *lval, YYLTYPE *yylloc, st https://github.com/ruby/ruby/blob/trunk/parse.y#L8825
 static NODE*
 node_newnode(struct parser_params *parser, enum node_type type, VALUE a0, VALUE a1, VALUE a2)
 {
-    NODE *n = (rb_node_newnode)(type, a0, a1, a2);
+    NODE *n = rb_ast_newnode(parser->ast);
+
+    rb_node_init(n, type, a0, a1, a2);
+
     nd_set_line(n, ruby_sourceline);
     /* mark not cared column to -1 */
     nd_set_column(n, -1);
@@ -10590,6 +10618,7 @@ new_args_tail_gen(struct parser_params * https://github.com/ruby/ruby/blob/trunk/parse.y#L10618
     NODE *node;
 
     args = ZALLOC(struct rb_args_info);
+    add_mark_object((VALUE)rb_imemo_alloc_new((VALUE)args, 0, 0, 0));
     node = NEW_NODE(NODE_ARGS, 0, 0, args);
     nd_set_column(node, column);
     if (parser->error_p) return node;
@@ -10959,6 +10988,9 @@ local_tbl_gen(struct parser_params *pars https://github.com/ruby/ruby/blob/trunk/parse.y#L10988
     }
     if (--j < cnt) REALLOC_N(buf, ID, (cnt = j) + 1);
     buf[0] = cnt;
+
+    add_mark_object((VALUE)rb_imemo_alloc_new((VALUE)buf, 0, 0, 0));
+
     return buf;
 }
 #endif
@@ -11350,18 +11382,16 @@ parser_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/parse.y#L11382
 {
     struct parser_params *parser = (struct parser_params*)ptr;
 
-    rb_gc_mark((VALUE)lex_strterm);
     rb_gc_mark(lex_input);
     rb_gc_mark(lex_lastline);
     rb_gc_mark(lex_nextline);
     rb_gc_mark(ruby_sourcefile_string);
 #ifndef RIPPER
-    rb_gc_mark((VALUE)ruby_eval_tree_begin);
-    rb_gc_mark((VALUE)ruby_eval_tree);
     rb_gc_mark(ruby_debug_lines);
     rb_gc_mark(parser->compile_option);
     rb_gc_mark(parser->error_buffer);
 #else
+    rb_gc_mark((VALUE)lex_strterm);
     rb_gc_mark(parser->delayed);
     rb_gc_mark(parser->value);
     rb_gc_mark(parser->result);
Index: node.c
===================================================================
--- node.c	(revision 60484)
+++ node.c	(revision 60485)
@@ -1211,3 +1211,107 @@ rb_gc_mark_node(NODE *obj) https://github.com/ruby/ruby/blob/trunk/node.c#L1211
     }
     return 0;
 }
+
+typedef struct node_buffer_elem_struct {
+    struct node_buffer_elem_struct *next;
+    NODE buf[1];
+} node_buffer_elem_t;
+
+typedef struct node_buffer_struct {
+    long idx, len;
+    node_buffer_elem_t *head;
+    node_buffer_elem_t body;
+} node_buffer_t;
+
+node_buffer_t *
+rb_node_buffer_new()
+{
+    node_buffer_t *nb = xmalloc(sizeof(node_buffer_t) + 16 * sizeof(NODE));
+    nb->idx = 0;
+    nb->len = 16;
+    nb->head = &nb->body;
+    nb->head->next = NULL;
+    return nb;
+}
+
+void
+rb_node_buffer_free(node_buffer_t *nb)
+{
+    node_buffer_elem_t *nbe = nb->he (... truncated)

--
ML: ruby-changes@q...
Info: http://www.atdot.net/~ko1/quickml/

[前][次][番号順一覧][スレッド一覧]