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

ruby-changes:26918

From: ko1 <ko1@a...>
Date: Tue, 29 Jan 2013 17:25:43 +0900 (JST)
Subject: [ruby-changes:26918] ko1:r38970 (trunk): * vm_backtrace.c: fix issue of rb_debug_inspector_open().

ko1	2013-01-29 17:25:32 +0900 (Tue, 29 Jan 2013)

  New Revision: 38970

  http://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=rev&revision=38970

  Log:
    * vm_backtrace.c: fix issue of rb_debug_inspector_open().
      The order of making binding should be stack (frame) top to bottom.
      [Bug #7635]
      And also fix issue of collecting klass. Collecting klass is same
      as TracePoint#defined_class.
      (previous version, it returns T_ICLASS (internal objects).
    * test/-ext-/debug/test_debug.rb: add a test.
    * ext/-test-/debug/extconf.rb, init.c, inspector.c: ditto.
    * vm_backtrace.c: remove magic number and add enum CALLER_BINDING_*.
    * vm_backtrace.c, include/ruby/debug.h: add new C api (experimental)
      rb_debug_inspector_frame_self_get().
    * vm.c, vm_core.h, vm_trace.c: move decl. of
      rb_vm_control_frame_id_and_class() and constify first parameter.

  Added directories:
    trunk/ext/-test-/debug/
    trunk/test/-ext-/debug/
  Added files:
    trunk/ext/-test-/debug/extconf.rb
    trunk/ext/-test-/debug/init.c
    trunk/ext/-test-/debug/inspector.c
    trunk/test/-ext-/debug/test_debug.rb
  Modified files:
    trunk/ChangeLog
    trunk/include/ruby/debug.h
    trunk/vm.c
    trunk/vm_backtrace.c
    trunk/vm_core.h
    trunk/vm_trace.c

Index: include/ruby/debug.h
===================================================================
--- include/ruby/debug.h	(revision 38969)
+++ include/ruby/debug.h	(revision 38970)
@@ -31,8 +31,9 @@ typedef struct rb_debug_inspector_struct https://github.com/ruby/ruby/blob/trunk/include/ruby/debug.h#L31
 typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *);
 
 VALUE rb_debug_inspector_open(rb_debug_inspector_func_t func, void *data);
-VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index);
+VALUE rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index);
 VALUE rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index);
+VALUE rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index);
 VALUE rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index);
 VALUE rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc);
 
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 38969)
+++ ChangeLog	(revision 38970)
@@ -1,3 +1,24 @@ https://github.com/ruby/ruby/blob/trunk/ChangeLog#L1
+Tue Jan 29 17:03:28 2013  Koichi Sasada  <ko1@a...>
+
+	* vm_backtrace.c: fix issue of rb_debug_inspector_open().
+	  The order of making binding should be stack (frame) top to bottom.
+	  [Bug #7635]
+	  And also fix issue of collecting klass. Collecting klass is same
+	  as TracePoint#defined_class.
+	  (previous version, it returns T_ICLASS (internal objects).
+
+	* test/-ext-/debug/test_debug.rb: add a test.
+
+	* ext/-test-/debug/extconf.rb, init.c, inspector.c: ditto.
+
+	* vm_backtrace.c: remove magic number and add enum CALLER_BINDING_*.
+
+	* vm_backtrace.c, include/ruby/debug.h: add new C api (experimental)
+	  rb_debug_inspector_frame_self_get().
+
+	* vm.c, vm_core.h, vm_trace.c: move decl. of 
+	  rb_vm_control_frame_id_and_class() and constify first parameter.
+
 Tue Jan 29 16:50:58 2013  Nobuyoshi Nakada  <nobu@r...>
 
 	* vm_trace.c (rb_tracepoint_enable, rb_tracepoint_disable): check safe
Index: vm_core.h
===================================================================
--- vm_core.h	(revision 38969)
+++ vm_core.h	(revision 38970)
@@ -847,6 +847,7 @@ int rb_vm_get_sourceline(const rb_contro https://github.com/ruby/ruby/blob/trunk/vm_core.h#L847
 VALUE rb_name_err_mesg_new(VALUE obj, VALUE mesg, VALUE recv, VALUE method);
 void rb_vm_stack_to_heap(rb_thread_t *th);
 void ruby_thread_init_stack(rb_thread_t *th);
+int rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp);
 
 void rb_gc_mark_machine_stack(rb_thread_t *th);
 
Index: vm_backtrace.c
===================================================================
--- vm_backtrace.c	(revision 38969)
+++ vm_backtrace.c	(revision 38970)
@@ -1012,8 +1012,15 @@ struct rb_debug_inspector_struct { https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1012
     long backtrace_size;
 };
 
+enum {
+    CALLER_BINDING_SELF,
+    CALLER_BINDING_CLASS,
+    CALLER_BINDING_BINDING,
+    CALLER_BINDING_ISEQ,
+    CALLER_BINDING_CFP
+};
+
 struct collect_caller_bindings_data {
-    rb_thread_t *th;
     VALUE ary;
 };
 
@@ -1023,37 +1030,82 @@ collect_caller_bindings_init(void *arg, https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1030
     /* */
 }
 
+static VALUE
+get_klass(const rb_control_frame_t *cfp)
+{
+    VALUE klass;
+    if (rb_vm_control_frame_id_and_class(cfp, 0, &klass)) {
+	if (RB_TYPE_P(klass, T_ICLASS)) {
+	    return RBASIC(klass)->klass;
+	}
+	else {
+	    return klass;
+	}
+    }
+    else {
+	return Qnil;
+    }
+}
+
 static void
 collect_caller_bindings_iseq(void *arg, const rb_control_frame_t *cfp)
 {
     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
-    rb_ary_push(data->ary,
-		rb_ary_new3(4,
-			    cfp->klass,
-			    rb_binding_new_with_cfp(data->th, cfp),
-			    cfp->iseq ? cfp->iseq->self : Qnil,
-			    GC_GUARDED_PTR(cfp)));
+    VALUE frame = rb_ary_new2(5);
+
+    rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
+    rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
+    rb_ary_store(frame, CALLER_BINDING_BINDING, GC_GUARDED_PTR(cfp)); /* create later */
+    rb_ary_store(frame, CALLER_BINDING_ISEQ, cfp->iseq ? cfp->iseq->self : Qnil);
+    rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
+
+    rb_ary_push(data->ary, frame);
 }
 
 static void
 collect_caller_bindings_cfunc(void *arg, const rb_control_frame_t *cfp, ID mid)
 {
     struct collect_caller_bindings_data *data = (struct collect_caller_bindings_data *)arg;
-    rb_ary_push(data->ary, rb_ary_new3(2, cfp->klass, Qnil));
+    VALUE frame = rb_ary_new2(5);
+
+    rb_ary_store(frame, CALLER_BINDING_SELF, cfp->self);
+    rb_ary_store(frame, CALLER_BINDING_CLASS, get_klass(cfp));
+    rb_ary_store(frame, CALLER_BINDING_BINDING, Qnil); /* not available */
+    rb_ary_store(frame, CALLER_BINDING_ISEQ, Qnil); /* not available */
+    rb_ary_store(frame, CALLER_BINDING_CFP, GC_GUARDED_PTR(cfp));
+
+    rb_ary_push(data->ary, frame);
 }
 
 static VALUE
 collect_caller_bindings(rb_thread_t *th)
 {
     struct collect_caller_bindings_data data;
+    VALUE result;
+    int i;
+
     data.ary = rb_ary_new();
-    data.th = th;
+
     backtrace_each(th,
 		   collect_caller_bindings_init,
 		   collect_caller_bindings_iseq,
 		   collect_caller_bindings_cfunc,
 		   &data);
-    return rb_ary_reverse(data.ary);
+
+    result = rb_ary_reverse(data.ary);
+
+    /* bindings should be created from top of frame */
+    for (i=0; i<RARRAY_LEN(result); i++) {
+	VALUE entry = rb_ary_entry(result, i);
+	VALUE cfp_val = rb_ary_entry(entry, CALLER_BINDING_BINDING);
+
+	if (!NIL_P(cfp_val)) {
+	    rb_control_frame_t *cfp = GC_GUARDED_PTR_REF(cfp_val);
+	    rb_ary_store(entry, CALLER_BINDING_BINDING, rb_binding_new_with_cfp(th, cfp));
+	}
+    }
+
+    return result;
 }
 
 /*
@@ -1100,24 +1152,31 @@ frame_get(const rb_debug_inspector_t *dc https://github.com/ruby/ruby/blob/trunk/vm_backtrace.c#L1152
 }
 
 VALUE
+rb_debug_inspector_frame_self_get(const rb_debug_inspector_t *dc, long index)
+{
+    VALUE frame = frame_get(dc, index);
+    return rb_ary_entry(frame, CALLER_BINDING_SELF);
+}
+
+VALUE
 rb_debug_inspector_frame_class_get(const rb_debug_inspector_t *dc, long index)
 {
     VALUE frame = frame_get(dc, index);
-    return rb_ary_entry(frame, 0);
+    return rb_ary_entry(frame, CALLER_BINDING_CLASS);
 }
 
 VALUE
 rb_debug_inspector_frame_binding_get(const rb_debug_inspector_t *dc, long index)
 {
     VALUE frame = frame_get(dc, index);
-    return rb_ary_entry(frame, 1);
+    return rb_ary_entry(frame, CALLER_BINDING_BINDING);
 }
 
 VALUE
 rb_debug_inspector_frame_iseq_get(const rb_debug_inspector_t *dc, long index)
 {
     VALUE frame = frame_get(dc, index);
-    return rb_ary_entry(frame, 2);
+    return rb_ary_entry(frame, CALLER_BINDING_ISEQ);
 }
 
 VALUE
Index: ext/-test-/debug/init.c
===================================================================
--- ext/-test-/debug/init.c	(revision 0)
+++ ext/-test-/debug/init.c	(revision 38970)
@@ -0,0 +1,11 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/debug/init.c#L1
+#include "ruby.h"
+
+#define init(n) {void Init_##n(VALUE klass); Init_##n(klass);}
+
+void
+Init_debug(void)
+{
+    VALUE mBug = rb_define_module("Bug");
+    VALUE klass = rb_define_class_under(mBug, "Debug", rb_cModule);
+    TEST_INIT_FUNCS(init);
+}
Index: ext/-test-/debug/inspector.c
===================================================================
--- ext/-test-/debug/inspector.c	(revision 0)
+++ ext/-test-/debug/inspector.c	(revision 38970)
@@ -0,0 +1,32 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/debug/inspector.c#L1
+#include "ruby/ruby.h"
+#include "ruby/debug.h"
+
+static VALUE
+callback(const rb_debug_inspector_t *dbg_context, void *data)
+{
+    VALUE locs = rb_debug_inspector_backtrace_locations(dbg_context);
+    int i, len = RARRAY_LENINT(locs);
+    VALUE binds = rb_ary_new();
+    for (i = 0; i < len; ++i) {
+	VALUE entry = rb_ary_new();
+	rb_ary_push(binds, entry);
+	rb_ary_push(entry, rb_debug_inspector_frame_self_get(dbg_context, i));
+	rb_ary_push(entry, rb_debug_inspector_frame_binding_get(dbg_context, i));
+	rb_ary_push(entry, rb_debug_inspector_frame_class_get(dbg_context, i));
+	rb_ary_push(entry, rb_debug_inspector_frame_iseq_get(dbg_context, i));
+	rb_ary_push(entry, rb_ary_entry(locs, i));
+    }
+    return binds;
+}
+
+static VALUE
+debug_inspector(VALUE self)
+{
+    return rb_debug_inspector_open(callback, NULL);
+}
+
+void
+Init_inspector(VALUE klass)
+{
+    rb_define_module_function(klass, "inspector", debug_inspector, 0);
+}
Index: ext/-test-/debug/extconf.rb
===================================================================
--- ext/-test-/debug/extconf.rb	(revision 0)
+++ ext/-test-/debug/extconf.rb	(revision 38970)
@@ -0,0 +1,6 @@ https://github.com/ruby/ruby/blob/trunk/ext/-test-/debug/extconf.rb#L1
+$srcs = Dir[File.join($srcdir, "*.{#{SRC_EXT.join(%q{,})}}")]
+inits = $srcs.map {|s| File.basename(s, ".*")}
+inits.delete("init")
+inits.map! {|s|"X(#{s})"}
+$defs << "-DTEST_INIT_FUNCS(X)=\"#{inits.join(' ')}\""
+create_makefile("-test-/debug")
Index: vm_trace.c
===================================================================
--- vm_trace.c	(revision 38969)
+++ vm_trace.c	(revision 38970)
@@ -694,8 +694,6 @@ rb_tracearg_event(rb_trace_arg_t *trace_ https://github.com/ruby/ruby/blob/trunk/vm_trace.c#L694
     return ID2SYM(get_event_id(trace_arg->event));
 }
 
-int rb_vm_control_frame_id_and_class(rb_control_frame_t *cfp, ID *idp, VALUE *klassp);
-
 static void
 fill_path_and_lineno(rb_trace_arg_t *trace_arg)
 {
Index: vm.c
===================================================================
--- vm.c	(revision 38969)
+++ vm.c	(revision 38970)
@@ -1414,7 +1414,7 @@ rb_iseq_eval_main(VALUE iseqval) https://github.com/ruby/ruby/blob/trunk/vm.c#L1414
 }
 
 int
-rb_vm_control_frame_id_and_class(rb_control_frame_t *cfp, ID *idp, VALUE *klassp)
+rb_vm_control_frame_id_and_class(const rb_control_frame_t *cfp, ID *idp, VALUE *klassp)
 {
     rb_iseq_t *iseq = cfp->iseq;
     if (!iseq && cfp->me) {
Index: test/-ext-/debug/test_debug.rb
===================================================================
--- test/-ext-/debug/test_debug.rb	(revision 0)
+++ test/-ext-/debug/test_debug.rb	(revision 38970)
@@ -0,0 +1,58 @@ https://github.com/ruby/ruby/blob/trunk/test/-ext-/debug/test_debug.rb#L1
+require 'test/unit'
+require '-test-/debug'
+
+class TestDebug < Test::Unit::TestCase
+
+  def binds_check binds
+    count = Hash.new(0)
+    assert_instance_of(Array, binds)
+    binds.each{|(_self, bind, klass, iseq, loc)|
+      if _self == self
+        count[:self] += 1
+      end
+
+      if bind
+        assert_instance_of(Binding, bind)
+        count[:bind] += 1
+      end
+
+      if klass
+        assert(klass.instance_of?(Module) || klass.instance_of?(Class))
+        count[:class] += 1
+      end
+
+      if iseq
+        count[:iseq] += 1
+        assert_instance_of(RubyVM::InstructionSequence, iseq)
+
+        # check same location
+        assert_equal(loc.path, iseq.path)
+        assert_equal(loc.absolute_path, iseq.absolute_path)
+        assert_equal(loc.label, iseq.label)
+        assert_operator(loc.lineno, :>=, iseq.first_lineno)
+      end
+
+      assert_instance_of(Thread::Backtrace::Location, loc)
+
+    }
+    assert_operator(0, :<, count[:self])
+    assert_operator(0, :<, count[:bind])
+    assert_operator(0, :<, count[:iseq])
+    assert_operator(0, :<, count[:class])
+  end
+
+  def test_inspector_open
+    binds = Bug::Debug.inspector
+    binds_check binds
+  end
+
+  def inspector_in_eval
+    eval("Bug::Debug.inspector")
+  end
+
+  def test_inspector_open_in_eval
+    bug7635 = '[ruby-core:51640]'
+    binds = inspector_in_eval
+    binds_check binds
+  end
+end

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

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