From: nobu.nokada@... Date: 2001-12-21T19:09:26+09:00 Subject: [ruby-talk:29211] Re: Constant loss of memory with Kernel::load in a loop At Fri, 21 Dec 2001 17:34:45 +0900, nobu.nokada@softhome.net wrote: > The only way I could think of is making nd_file a String VALUE > and marking them directly from each NODE's. It prevents leaks > but doesn't make GC notably slow. Though it may be a big > modification. It was exactly big. Index: env.h =================================================================== RCS file: /cvs/ruby/src/ruby/env.h,v retrieving revision 1.7 diff -u -2 -p -r1.7 env.h --- env.h 2001/02/14 05:51:57 1.7 +++ env.h 2001/12/21 09:00:28 @@ -23,5 +23,5 @@ extern struct FRAME { struct FRAME *prev; struct FRAME *tmp; - char *file; + VALUE file; int line; int iter; Index: error.c =================================================================== RCS file: /cvs/ruby/src/ruby/error.c,v retrieving revision 1.35 diff -u -2 -p -r1.35 error.c --- error.c 2001/12/10 07:18:12 1.35 +++ error.c 2001/12/21 09:30:08 @@ -41,13 +41,13 @@ err_snprintf(buf, len, fmt, args) int n; - if (!ruby_sourcefile) { + if (!RTEST(ruby_sourcefile)) { vsnprintf(buf, len, fmt, args); return; } else if (ruby_sourceline == 0) { - n = snprintf(buf, len, "%s: ", ruby_sourcefile); + n = snprintf(buf, len, "%s: ", RSTRING(ruby_sourcefile)->ptr); } else { - n = snprintf(buf, len, "%s:%d: ", ruby_sourcefile, ruby_sourceline); + n = snprintf(buf, len, "%s:%d: ", RSTRING(ruby_sourcefile)->ptr, ruby_sourceline); } if (len > n) { Index: eval.c =================================================================== RCS file: /cvs/ruby/src/ruby/eval.c,v retrieving revision 1.237 diff -u -2 -p -r1.237 eval.c --- eval.c 2001/12/20 18:19:42 1.237 +++ eval.c 2001/12/21 09:57:29 @@ -859,6 +859,6 @@ static void scope_dup _((struct SCOPE *) static VALUE rb_eval _((VALUE,NODE*)); -static VALUE eval _((VALUE,VALUE,VALUE,char*,int)); -static NODE *compile _((VALUE, char*, int)); +static VALUE eval _((VALUE,VALUE,VALUE,VALUE,int)); +static NODE *compile _((VALUE, VALUE, int)); static VALUE rb_yield_0 _((VALUE, VALUE, VALUE, int)); @@ -871,5 +871,5 @@ static void assign _((VALUE,NODE*,VALUE, static VALUE trace_func = 0; static int tracing = 0; -static void call_trace_func _((char*,char*,int,VALUE,ID,VALUE)); +static void call_trace_func _((char*,VALUE,int,VALUE,ID,VALUE)); static void @@ -885,5 +885,5 @@ error_pos() } else { - fprintf(stderr, "%s:%d", ruby_sourcefile, ruby_sourceline); + fprintf(stderr, "%s:%d", RSTRING(ruby_sourcefile)->ptr, ruby_sourceline); } } @@ -925,5 +925,5 @@ error_print() if (NIL_P(errat)){ if (ruby_sourcefile) - fprintf(stderr, "%s:%d", ruby_sourcefile, ruby_sourceline); + fprintf(stderr, "%s:%d", RSTRING(ruby_sourcefile)->ptr, ruby_sourceline); else fprintf(stderr, "%d", ruby_sourceline); @@ -1243,4 +1243,6 @@ compile_error(at) } +extern VALUE rb_source_filename _((const char *)); + VALUE rb_eval_string(str) @@ -1248,7 +1250,7 @@ rb_eval_string(str) { VALUE v; - char *oldsrc = ruby_sourcefile; + VALUE oldsrc = ruby_sourcefile; - ruby_sourcefile = "(eval)"; + ruby_sourcefile = rb_source_filename("(eval)"); v = eval(ruby_top_self, rb_str_new2(str), Qnil, 0, 0); ruby_sourcefile = oldsrc; @@ -1690,5 +1692,5 @@ copy_node_scope(node, rval) argc=n->nd_alen;\ if (argc > 0) {\ - char *file = ruby_sourcefile;\ + VALUE file = ruby_sourcefile;\ int line = ruby_sourceline;\ int i;\ @@ -1709,5 +1711,5 @@ copy_node_scope(node, rval) else {\ VALUE args = rb_eval(self,n);\ - char *file = ruby_sourcefile;\ + VALUE file = ruby_sourcefile;\ int line = ruby_sourceline;\ if (TYPE(args) != T_ARRAY)\ @@ -1984,5 +1986,5 @@ static void call_trace_func(event, file, line, self, id, klass) char *event; - char *file; + VALUE file; int line; VALUE self; @@ -1992,5 +1994,5 @@ call_trace_func(event, file, line, self, int state; struct FRAME *prev; - char *file_save = ruby_sourcefile; + VALUE file_save = ruby_sourcefile; int line_save = ruby_sourceline; VALUE srcfile; @@ -2020,5 +2022,5 @@ call_trace_func(event, file, line, self, PUSH_TAG(PROT_NONE); if ((state = EXEC_TAG()) == 0) { - srcfile = rb_str_new2(ruby_sourcefile?ruby_sourcefile:"(ruby)"); + srcfile = ruby_sourcefile?ruby_sourcefile:rb_source_filename("(ruby)"); proc_invoke(trace_func, rb_ary_new3(6, rb_str_new2(event), srcfile, @@ -2220,5 +2222,5 @@ rb_eval(self, n) call_trace_func("line", tag->nd_file, nd_line(tag), self, ruby_frame->last_func, - ruby_frame->last_class); + ruby_frame->last_class); } ruby_sourcefile = tag->nd_file; @@ -2376,5 +2378,5 @@ rb_eval(self, n) else { VALUE recv; - char *file = ruby_sourcefile; + VALUE file = ruby_sourcefile; int line = ruby_sourceline; @@ -3333,5 +3335,5 @@ module_setup(module, n) struct FRAME frame; VALUE result; /* OK */ - char *file = ruby_sourcefile; + VALUE file = ruby_sourcefile; int line = ruby_sourceline; TMP_PROTECT; @@ -3515,5 +3517,5 @@ rb_longjmp(tag, mesg) fprintf(stderr, "Exception `%s' at %s:%d - %s\n", rb_class2name(CLASS_OF(ruby_errinfo)), - ruby_sourcefile, ruby_sourceline, + RSTRING(ruby_sourcefile)->ptr, ruby_sourceline, RSTRING(e)->ptr); } @@ -4174,5 +4176,5 @@ rb_f_missing(argc, argv, obj) char *format = 0; char *desc = ""; - char *file = ruby_sourcefile; + VALUE file = ruby_sourcefile; int line = ruby_sourceline; @@ -4409,5 +4411,5 @@ rb_call0(klass, recv, id, argc, argv, bo if (trace_func) { int state; - char *file = ruby_frame->prev->file; + VALUE file = ruby_frame->prev->file; int line = ruby_frame->prev->line; if (!file) { @@ -4565,5 +4567,5 @@ rb_call0(klass, recv, id, argc, argv, bo ruby_cref = saved_cref; if (trace_func) { - char *file = ruby_frame->prev->file; + VALUE file = ruby_frame->prev->file; int line = ruby_frame->prev->line; if (!file) { @@ -4776,14 +4778,15 @@ backtrace(lev) ary = rb_ary_new(); if (lev < 0) { + char *file = ruby_sourcefile?RSTRING(ruby_sourcefile)->ptr:NULL; if (frame->last_func) { snprintf(buf, BUFSIZ, "%s:%d:in `%s'", - ruby_sourcefile, ruby_sourceline, + file, ruby_sourceline, rb_id2name(frame->last_func)); } else if (ruby_sourceline == 0) { - snprintf(buf, BUFSIZ, "%s", ruby_sourcefile); + snprintf(buf, BUFSIZ, "%s", file); } else { - snprintf(buf, BUFSIZ, "%s:%d", ruby_sourcefile, ruby_sourceline); + snprintf(buf, BUFSIZ, "%s:%d", file, ruby_sourceline); } rb_ary_push(ary, rb_str_new2(buf)); @@ -4801,9 +4804,9 @@ backtrace(lev) if (frame->prev && frame->prev->last_func) { snprintf(buf, BUFSIZ, "%s:%d:in `%s'", - frame->file, frame->line, + RSTRING(frame->file)->ptr, frame->line, rb_id2name(frame->prev->last_func)); } else { - snprintf(buf, BUFSIZ, "%s:%d", frame->file, frame->line); + snprintf(buf, BUFSIZ, "%s:%d", RSTRING(frame->file)->ptr, frame->line); } rb_ary_push(ary, rb_str_new2(buf)); @@ -4858,5 +4861,5 @@ static NODE* compile(src, file, line) VALUE src; - char *file; + VALUE file; int line; { @@ -4865,5 +4868,5 @@ compile(src, file, line) ruby_nerrs = 0; Check_Type(src, T_STRING); - node = rb_compile_string(file, src, line); + node = rb_compile_string(StringValuePtr(file), src, line); if (ruby_nerrs == 0) return node; @@ -4873,6 +4876,5 @@ compile(src, file, line) static VALUE eval(self, src, scope, file, line) - VALUE self, src, scope; - char *file; + VALUE self, src, scope, file; int line; { @@ -4886,5 +4888,5 @@ eval(self, src, scope, file, line) volatile VALUE old_wrapper; struct FRAME frame; - char *filesave = ruby_sourcefile; + VALUE filesave = ruby_sourcefile; int linesave = ruby_sourceline; volatile int iter = ruby_frame->iter; @@ -4914,5 +4916,5 @@ eval(self, src, scope, file, line) old_wrapper = ruby_wrapper; ruby_wrapper = data->wrapper; - if ((file == 0 || (line == 1 && strcmp(file, "(eval)") == 0)) && + if ((file == 0 || (line == 1 && strcmp(RSTRING(file)->ptr, "(eval)") == 0)) && data->body && data->body->nd_file) { file = data->body->nd_file; @@ -4996,5 +4998,5 @@ eval(self, src, scope, file, line) VALUE errat; - if (strcmp(file, "(eval)") == 0) { + if (strcmp(RSTRING(file)->ptr, "(eval)") == 0) { if (ruby_sourceline > 1) { errat = get_backtrace(ruby_errinfo); @@ -5023,9 +5025,8 @@ rb_f_eval(argc, argv, self) VALUE self; { - VALUE src, scope, vfile, vline; - char *file = "(eval)"; + VALUE src, scope, file, vline; int line = 1; - rb_scan_args(argc, argv, "13", &src, &scope, &vfile, &vline); + rb_scan_args(argc, argv, "13", &src, &scope, &file, &vline); if (ruby_safe_level >= 4) { StringValue(src); @@ -5038,5 +5039,8 @@ rb_f_eval(argc, argv, self) } if (argc >= 3) { - file = StringValuePtr(vfile); + StringValue(file); + } + else { + file = rb_source_filename("(eval)"); } if (argc >= 4) { @@ -5104,5 +5108,5 @@ eval_under_i(args) VALUE *args; { - return eval(args[0], args[1], Qnil, (char*)args[2], (int)args[3]); + return eval(args[0], args[1], Qnil, args[2], (int)args[3]); } @@ -5110,6 +5114,5 @@ eval_under_i(args) static VALUE eval_under(under, self, src, file, line) - VALUE under, self, src; - const char *file; + VALUE under, self, src, file; int line; { @@ -5124,5 +5127,5 @@ eval_under(under, self, src, file, line) args[0] = self; args[1] = src; - args[2] = (VALUE)file; + args[2] = file; args[3] = (VALUE)line; return exec_under(eval_under_i, under, args); @@ -5183,5 +5186,5 @@ specific_eval(argc, argv, klass, self) } else { - char *file = "(eval)"; + VALUE file; int line = 1; @@ -5202,5 +5205,9 @@ specific_eval(argc, argv, klass, self) } if (argc > 1) { - file = StringValuePtr(argv[1]); + file = argv[1]; + StringValue(file); + } + else { + file = rb_source_filename("(eval)"); } if (argc > 2) line = NUM2INT(argv[2]); @@ -7092,5 +7099,5 @@ struct thread { int flags; /* misc. states (vmode/rb_trap_immediate/raised) */ - char *file; + VALUE file; int line; @@ -7213,4 +7220,5 @@ thread_mark(th) rb_gc_mark(th->last_line); rb_gc_mark(th->last_match); + rb_gc_mark(th->file); rb_mark_tbl(th->locals); @@ -7291,5 +7299,5 @@ static VALUE rb_thread_raise _((int, VAL static int th_raise_argc; static VALUE th_raise_argv[2]; -static char *th_raise_file; +static VALUE th_raise_file; static int th_raise_line; static VALUE th_cmd; Index: gc.c =================================================================== RCS file: /cvs/ruby/src/ruby/gc.c,v retrieving revision 1.82 diff -u -2 -p -r1.82 gc.c --- gc.c 2001/12/11 03:48:08 1.82 +++ gc.c 2001/12/21 09:35:57 @@ -430,4 +430,32 @@ init_mark_stack() static void rb_gc_mark_children(VALUE ptr); +static st_table *source_filenames; + +VALUE +rb_source_filename(f) + const char *f; +{ + VALUE name; + + if (!st_lookup(source_filenames, f, (char *)&name)) { + name = rb_str_new2(f); + OBJ_FREEZE(name); + f = RSTRING(name)->ptr; + st_add_direct(source_filenames, f, name); + } + + return name; +} + +static enum st_retval +sweep_source_filename(key, value) + char *key; + char *value; +{ + if (!(RBASIC(value)->flags & FL_MARK)) + return ST_DELETE; + return ST_CONTINUE; +} + static void gc_mark_all() @@ -606,4 +634,5 @@ rb_gc_mark_children(ptr) case T_NODE: + rb_gc_mark(obj->as.node.nd_file); switch (nd_type(obj)) { case NODE_IF: /* 1,2,3 */ @@ -849,4 +878,6 @@ gc_sweep() } + st_foreach(source_filenames, sweep_source_filename, 0); + freelist = 0; final_list = deferred_final_list; @@ -1514,3 +1545,5 @@ Init_GC() rb_gc_unregister_address(&rb_mObSpace); finalizers = rb_ary_new(); + + source_filenames = st_init_strtable(); } Index: intern.h =================================================================== RCS file: /cvs/ruby/src/ruby/intern.h,v retrieving revision 1.74 diff -u -2 -p -r1.74 intern.h --- intern.h 2001/12/17 07:52:34 1.74 +++ intern.h 2001/12/21 08:58:59 @@ -263,5 +263,5 @@ VALUE rb_Array _((VALUE)); /* parse.y */ EXTERN int ruby_sourceline; -EXTERN char *ruby_sourcefile; +EXTERN VALUE ruby_sourcefile; #define yyparse ruby_yyparse #define yylex ruby_yylex Index: node.h =================================================================== RCS file: /cvs/ruby/src/ruby/node.h,v retrieving revision 1.27 diff -u -2 -p -r1.27 node.h --- node.h 2001/06/23 15:14:14 1.27 +++ node.h 2001/12/21 08:58:03 @@ -129,5 +129,5 @@ enum node_type { typedef struct RNode { unsigned long flags; - char *nd_file; + VALUE nd_file; union { struct RNode *node; Index: parse.y =================================================================== RCS file: /cvs/ruby/src/ruby/parse.y,v retrieving revision 1.136 diff -u -2 -p -r1.136 parse.y --- parse.y 2001/12/11 03:48:08 1.136 +++ parse.y 2001/12/21 09:34:31 @@ -44,5 +44,5 @@ NODE *ruby_eval_tree_begin = 0; NODE *ruby_eval_tree = 0; -char *ruby_sourcefile; /* current source file */ +VALUE ruby_sourcefile; /* current source file */ int ruby_sourceline; /* current line no. */ @@ -2111,4 +2111,6 @@ int ruby__end__seen; static VALUE ruby_debug_lines; +extern VALUE rb_source_filename _((const char *)); + static NODE* yycompile(f, line) @@ -2144,5 +2146,5 @@ yycompile(f, line) ruby_eval_tree = 0; heredoc_end = 0; - ruby_sourcefile = f; + ruby_sourcefile = rb_source_filename(f); ruby_in_compile = 1; n = yyparse(); @@ -2229,5 +2231,5 @@ rb_compile_file(f, file, start) ruby_sourceline = start - 1; - return yycompile(strdup(f), start); + return yycompile(f, start); } @@ -4278,7 +4280,5 @@ gettable(id) } else if (id == k__FILE__) { - VALUE f = rb_str_new2(ruby_sourcefile); - OBJ_FREEZE(f); - return NEW_STR(f); + return NEW_STR(ruby_sourcefile); } else if (id == k__LINE__) { @@ -4670,5 +4670,6 @@ static int e_option_supplied() { - if (strcmp(ruby_sourcefile, "-e") == 0) + if (RTEST(ruby_sourcefile) && + strcmp(RSTRING(ruby_sourcefile)->ptr, "-e") == 0) return Qtrue; return Qfalse; Index: ruby.c =================================================================== RCS file: /cvs/ruby/src/ruby/ruby.c,v retrieving revision 1.55 diff -u -2 -p -r1.55 ruby.c --- ruby.c 2001/12/17 07:52:35 1.55 +++ ruby.c 2001/12/21 09:33:42 @@ -311,5 +311,5 @@ require_libraries() extern NODE *ruby_eval_tree; extern NODE *ruby_eval_tree_begin; - char *orig_sourcefile = ruby_sourcefile; + VALUE orig_sourcefile = ruby_sourcefile; NODE *save[2]; struct req_list *list = req_list_head.next; @@ -718,5 +718,5 @@ proc_options(argc, argv) ruby_init_loadpath(); - ruby_sourcefile = argv0; + ruby_sourcefile = rb_source_filename(argv0); if (e_script) { require_libraries(); @@ -825,5 +825,5 @@ load_file(fname, script) execv(path, argv); - ruby_sourcefile = fname; + ruby_sourcefile = rb_source_filename(fname); ruby_sourceline = 1; rb_fatal("Can't exec %s", path); @@ -951,5 +951,5 @@ ruby_script(name) if (name) { rb_progname = rb_tainted_str_new2(name); - ruby_sourcefile = name; + ruby_sourcefile = rb_source_filename(name); } } @@ -990,5 +990,5 @@ ruby_prog_init() init_ids(); - ruby_sourcefile = "ruby"; + ruby_sourcefile = rb_source_filename("ruby"); rb_define_variable("$VERBOSE", &ruby_verbose); rb_define_variable("$-v", &ruby_verbose); Nobu Nakada