Hi, At Sat, 1 Dec 2007 04:14:33 +0900, Florian Frank wrote in [ruby-core:13839]: > B. Tommy Jensen wrote: > > Does anyone know whether this is a deliberate design choice in 1.9, or > > is it a mistake that should be corrected? > This seems to be the same problem I reported in ruby-core:13824. ko1 > considered this to be a bug and wanted to correct it. Accurately, they are different.
Index: proc.c =================================================================== --- proc.c (revision 14061) +++ proc.c (working copy) @@ -305,7 +305,10 @@ proc_new(VALUE klass, int is_lambda) static VALUE -rb_proc_s_new(VALUE klass) +rb_proc_s_new(int argc, VALUE *argv, VALUE klass) { - return proc_new(klass, Qfalse); + VALUE block = proc_new(klass, Qfalse); + + rb_obj_call_init(block, argc, argv); + return block; } @@ -472,4 +475,49 @@ rb_proc_arity(VALUE proc) } +static rb_iseq_t * +get_proc_iseq(VALUE self) +{ + rb_proc_t *proc; + rb_iseq_t *iseq; + + GetProcPtr(self, proc); + iseq = proc->block.iseq; + if (!RUBY_VM_NORMAL_ISEQ_P(iseq)) + rb_raise(rb_eTypeError, "(Native?) Proc has no Ruby source"); + return iseq; +} + +/* + * call-seq: + * prc.__file__ => String + * + * returns the ruby source filename containing this proc + * raises TypeError if this proc was not defined in ruby (i.e. native) + */ + +VALUE +rb_proc_filename(VALUE self) +{ + return get_proc_iseq(self)->filename; +} + +/* + * call-seq: + * prc.__line__ => Fixnum + * + * returns the starting ruby source lineno of this proc or nil if none known + * raises TypeError if this proc was not defined in ruby (i.e. native) + */ + +VALUE +rb_proc_lineno(VALUE self) +{ + rb_iseq_t *iseq = get_proc_iseq(self); + + if (!iseq->insn_info_table) + return Qnil; + return INT2FIX(iseq->insn_info_table[0].line_no); +} + /* * call-seq: @@ -1258,4 +1306,55 @@ rb_obj_method_arity(VALUE obj, ID id) } +static rb_iseq_t * +get_method_iseq(VALUE method) +{ + struct METHOD *data; + NODE *body; + rb_iseq_t *iseq; + + Data_Get_Struct(method, struct METHOD, data); + body = data->body; + switch (nd_type(body)) { + case RUBY_VM_METHOD_NODE: + GetISeqPtr((VALUE)body->nd_body, iseq); + if (RUBY_VM_NORMAL_ISEQ_P(iseq)) break; + default: + rb_raise(rb_eTypeError, "(Native?) Method has no Ruby source"); + } + return iseq; +} + +/* + * call-seq: + * meth.__file__ => String + * + * returns the ruby source filename containing this method's definition + * raises TypeError if this method was not defined in ruby (i.e. native) + */ + +static VALUE +method_filename(VALUE method) +{ + return get_method_iseq(method)->filename; +} + +/* + * call-seq: + * meth.__line__ => Fixnum + * + * returns the starting ruby source lineno of this method of nil if unknown + * raises TypeError if this method was not defined in ruby (i.e. native) + */ + +static VALUE +method_lineno(VALUE method) +{ + rb_iseq_t *iseq = get_method_iseq(method); + + if (!iseq->insn_info_table) + return Qnil; + return INT2FIX(iseq->insn_info_table[0].line_no); +} + /* * call-seq: @@ -1439,5 +1538,5 @@ Init_Proc(void) rb_cProc = rb_define_class("Proc", rb_cObject); rb_undef_alloc_func(rb_cProc); - rb_define_singleton_method(rb_cProc, "new", rb_proc_s_new, 0); + rb_define_singleton_method(rb_cProc, "new", rb_proc_s_new, -1); rb_define_method(rb_cProc, "call", proc_call, -1); rb_define_method(rb_cProc, "[]", proc_call, -1); @@ -1452,4 +1551,6 @@ Init_Proc(void) rb_define_method(rb_cProc, "to_s", proc_to_s, 0); rb_define_method(rb_cProc, "lambda?", proc_lambda_p, 0); + rb_define_method(rb_cProc, "__file__", rb_proc_filename, 0); + rb_define_method(rb_cProc, "__line__", rb_proc_lineno, 0); /* Exceptions */ @@ -1486,4 +1587,6 @@ Init_Proc(void) rb_define_method(rb_cMethod, "unbind", method_unbind, 0); rb_define_method(rb_mKernel, "method", rb_obj_method, 1); + rb_define_method(rb_cMethod, "__file__", method_filename, 0); + rb_define_method(rb_cMethod, "__line__", method_lineno, 0); /* UnboundMethod */ @@ -1501,4 +1604,6 @@ Init_Proc(void) rb_define_method(rb_cUnboundMethod, "owner", method_owner, 0); rb_define_method(rb_cUnboundMethod, "bind", umethod_bind, 1); + rb_define_method(rb_cUnboundMethod, "__file__", method_filename, 0); + rb_define_method(rb_cUnboundMethod, "__line__", method_lineno, 0); /* Module#*_method */ Index: thread.c =================================================================== --- thread.c (revision 14061) +++ thread.c (working copy) @@ -374,11 +374,8 @@ thread_start_func_2(rb_thread_t *th, VAL static VALUE -thread_create_core(VALUE klass, VALUE args, VALUE (*fn)(ANYARGS)) +thread_create_core(VALUE thval, VALUE args, VALUE (*fn)(ANYARGS)) { rb_thread_t *th; - VALUE thval; - /* create thread object */ - thval = rb_thread_alloc(klass); GetThreadPtr(thval, th); @@ -408,7 +405,47 @@ thread_create_core(VALUE klass, VALUE ar static VALUE -thread_s_new(VALUE klass, VALUE args) +thread_s_new(int argc, VALUE *argv, VALUE klass) { - return thread_create_core(klass, args, 0); + rb_thread_t *th; + VALUE thread = rb_thread_alloc(klass); + rb_obj_call_init(thread, argc, argv); + GetThreadPtr(thread, th); + if (!th->first_args) { + rb_raise(rb_eThreadError, "uninitialized thread - check `%s#initialize'", + rb_class2name(klass)); + } + return thread; +} + +static VALUE +thread_start(VALUE klass, VALUE args) +{ + return thread_create_core(rb_thread_alloc(klass), args, 0); +} + +static VALUE +thread_initialize(VALUE thread, VALUE args) +{ + rb_thread_t *th; + if (!rb_block_given_p()) { + rb_raise(rb_eThreadError, "must be called with a block"); + } + GetThreadPtr(thread, th); + if (th->first_args) { + VALUE rb_proc_filename(VALUE self); + VALUE rb_proc_lineno(VALUE self); + VALUE proc = th->first_proc, file, line; + const char *fn; + if (!proc || !RTEST(file = rb_proc_filename(proc))) { + rb_raise(rb_eThreadError, "already initialized thread"); + } + fn = StringValueCStr(file); + if (NIL_P(line = rb_proc_lineno(proc))) { + rb_raise(rb_eThreadError, "already initialized thread - %s", fn); + } + rb_raise(rb_eThreadError, "already initialized thread - %s:%d", + fn, NUM2INT(line)); + } + return thread_create_core(thread, args, 0); } @@ -416,5 +453,5 @@ VALUE rb_thread_create(VALUE (*fn)(ANYARGS), void *arg) { - return thread_create_core(rb_cThread, (VALUE)arg, fn); + return thread_create_core(rb_thread_alloc(rb_cThread), (VALUE)arg, fn); } @@ -2987,7 +3024,7 @@ Init_Thread(void) VALUE cThGroup; - rb_define_singleton_method(rb_cThread, "new", thread_s_new, -2); - rb_define_singleton_method(rb_cThread, "start", thread_s_new, -2); - rb_define_singleton_method(rb_cThread, "fork", thread_s_new, -2); + rb_define_singleton_method(rb_cThread, "new", thread_s_new, -1); + rb_define_singleton_method(rb_cThread, "start", thread_start, -2); + rb_define_singleton_method(rb_cThread, "fork", thread_start, -2); rb_define_singleton_method(rb_cThread, "main", rb_thread_s_main, 0); rb_define_singleton_method(rb_cThread, "current", thread_s_current, 0); @@ -3006,4 +3043,5 @@ Init_Thread(void) #endif + rb_define_method(rb_cThread, "initialize", thread_initialize, -2); rb_define_method(rb_cThread, "raise", thread_raise_m, -1); rb_define_method(rb_cThread, "join", thread_join_m, -1); Index: vm.c =================================================================== --- vm.c (revision 14061) +++ vm.c (working copy) @@ -1665,9 +1665,12 @@ thread_alloc(VALUE klass) { VALUE volatile obj; - //rb_thread_t *th = thread_recycle_struct(); - //obj = Data_Wrap_Struct(klass, rb_thread_mark, thread_free, th); +#ifdef USE_THREAD_RECYCLE + rb_thread_t *th = thread_recycle_struct(); + obj = Data_Wrap_Struct(klass, rb_thread_mark, thread_free, th); +#else rb_thread_t *th; obj = Data_Make_Struct(klass, rb_thread_t, rb_thread_mark, thread_free, th); +#endif return obj; }
-- Nobu Nakada