ruby-changes:32091
From: ko1 <ko1@a...>
Date: Fri, 13 Dec 2013 13:31:16 +0900 (JST)
Subject: [ruby-changes:32091] ko1:r44170 (trunk): * error.c: add Exception#backtrace_locations.
ko1 2013-12-13 13:31:06 +0900 (Fri, 13 Dec 2013) New Revision: 44170 http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=44170 Log: * error.c: add Exception#backtrace_locations. Now, there are no setter and independent from Exception#backtrace. [Feature #8960] * eval.c (setup_exception): set backtrace locations for `bt_location' special attribute. * vm_backtrace.c (rb_backtrace_to_location_ary): added. * internal.h: ditto. * test/ruby/test_backtrace.rb: add a test for Exception#backtrace_locations. Modified files: trunk/ChangeLog trunk/error.c trunk/eval.c trunk/internal.h trunk/test/ruby/test_backtrace.rb trunk/vm_backtrace.c Index: ChangeLog =================================================================== --- ChangeLog (revision 44169) +++ ChangeLog (revision 44170) @@ -1,3 +1,19 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1 +Fri Dec 13 13:25:30 2013 Koichi Sasada <ko1@a...> + + * error.c: add Exception#backtrace_locations. + Now, there are no setter and independent from Exception#backtrace. + [Feature #8960] + + * eval.c (setup_exception): set backtrace locations for `bt_location' + special attribute. + + * vm_backtrace.c (rb_backtrace_to_location_ary): added. + + * internal.h: ditto. + + * test/ruby/test_backtrace.rb: add a test for + Exception#backtrace_locations. + Fri Dec 13 12:01:07 2013 Koichi Sasada <ko1@a...> * gc.c (garbage_collect_body): use rb_bug() and explicit error message Index: vm_backtrace.c =================================================================== --- vm_backtrace.c (revision 44169) +++ vm_backtrace.c (revision 44170) @@ -372,6 +372,7 @@ typedef struct rb_backtrace_struct { https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L372 rb_backtrace_location_t *backtrace_base; int backtrace_size; VALUE strary; + VALUE locary; } rb_backtrace_t; static void @@ -383,8 +384,9 @@ backtrace_mark(void *ptr) https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L384 for (i=0; i<s; i++) { location_mark_entry(&bt->backtrace[i]); - rb_gc_mark(bt->strary); } + rb_gc_mark(bt->strary); + rb_gc_mark(bt->locary); } } @@ -631,6 +633,18 @@ backtrace_to_location_ary(VALUE self, lo https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L633 return r; } +VALUE +rb_backtrace_to_location_ary(VALUE self) +{ + rb_backtrace_t *bt; + GetCoreDataFromValue(self, rb_backtrace_t, bt); + + if (!bt->locary) { + bt->locary = backtrace_to_location_ary(self, 0, 0); + } + return bt->locary; +} + static VALUE backtrace_dump_data(VALUE self) { Index: eval.c =================================================================== --- eval.c (revision 44169) +++ eval.c (revision 44170) @@ -493,10 +493,12 @@ setup_exception(rb_thread_t *th, int tag https://github.com/ruby/ruby/blob/trunk/eval.c#L493 if (OBJ_FROZEN(mesg)) { mesg = rb_obj_dup(mesg); } + rb_iv_set(mesg, "bt_locations", at); set_backtrace(mesg, at); } } } + if (!NIL_P(mesg)) { th->errinfo = mesg; } Index: error.c =================================================================== --- error.c (revision 44169) +++ error.c (revision 44170) @@ -736,6 +736,30 @@ exc_backtrace(VALUE exc) https://github.com/ruby/ruby/blob/trunk/error.c#L736 return obj; } +/* + * call-seq: + * exception.backtrace_locations -> array + * + * Returns any backtrace associated with the exception. This method is + * similar to Exception#backtrace, but the backtrace is an array of + * Thread::Backtrace::Location. + * + * Now, this method is not affected by Exception#set_backtrace(). + */ +static VALUE +exc_backtrace_locations(VALUE exc) +{ + ID bt_locations; + VALUE obj; + + CONST_ID(bt_locations, "bt_locations"); + obj = rb_attr_get(exc, bt_locations); + if (!NIL_P(obj)) { + obj = rb_backtrace_to_location_ary(obj); + } + return obj; +} + VALUE rb_check_backtrace(VALUE bt) { @@ -1749,6 +1773,7 @@ Init_Exception(void) https://github.com/ruby/ruby/blob/trunk/error.c#L1773 rb_define_method(rb_eException, "message", exc_message, 0); rb_define_method(rb_eException, "inspect", exc_inspect, 0); rb_define_method(rb_eException, "backtrace", exc_backtrace, 0); + rb_define_method(rb_eException, "backtrace_locations", exc_backtrace_locations, 0); rb_define_method(rb_eException, "set_backtrace", exc_set_backtrace, 1); rb_define_method(rb_eException, "cause", exc_cause, 0); Index: internal.h =================================================================== --- internal.h (revision 44169) +++ internal.h (revision 44170) @@ -800,6 +800,7 @@ VALUE rb_make_backtrace(void); https://github.com/ruby/ruby/blob/trunk/internal.h#L800 void rb_backtrace_print_as_bugreport(void); int rb_backtrace_p(VALUE obj); VALUE rb_backtrace_to_str_ary(VALUE obj); +VALUE rb_backtrace_to_location_ary(VALUE obj); void rb_backtrace_print_to(VALUE output); VALUE rb_vm_backtrace_object(void); Index: test/ruby/test_backtrace.rb =================================================================== --- test/ruby/test_backtrace.rb (revision 44169) +++ test/ruby/test_backtrace.rb (revision 44170) @@ -14,6 +14,36 @@ class TestBacktrace < Test::Unit::TestCa https://github.com/ruby/ruby/blob/trunk/test/ruby/test_backtrace.rb#L14 assert_match(/.+:\d+:.+/, bt[0]) end + def helper_test_exception_backtrace_locations + raise + end + + def test_exception_backtrace_locations + bt = Fiber.new{ + begin + raise + rescue => e + e.backtrace_locations + end + }.resume + assert_equal(1, bt.size) + assert_match(/.+:\d+:.+/, bt[0].to_s) + + bt = Fiber.new{ + begin + begin + helper_test_exception_backtrace_locations + rescue + raise + end + rescue => e + e.backtrace_locations + end + }.resume + assert_equal(2, bt.size) + assert_match(/helper_test_exception_backtrace_locations/, bt[0].to_s) + end + def test_caller_lev cs = [] Fiber.new{ -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/