summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog26
-rw-r--r--include/ruby/debug.h11
-rw-r--r--iseq.c2
-rw-r--r--vm_backtrace.c87
4 files changed, 124 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 688c6b2..8dd1843 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,31 @@
+Mon Oct 7 16:12:36 2013 Koichi Sasada <ko1@atdot.net>
+
+ * include/ruby/debug.h: add backtrace collecting APIs for profiler.
+ * int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
+ Collect information of frame information.
+
+ * VALUE rb_profile_frame_path(VALUE frame);
+ * VALUE rb_profile_frame_absolute_path(VALUE frame);
+ * VALUE rb_profile_frame_label(VALUE frame);
+ * VALUE rb_profile_frame_base_label(VALUE frame);
+ * VALUE rb_profile_frame_first_lineno(VALUE frame);
+ * VALUE rb_profile_frame_classpath(VALUE frame);
+ * VALUE rb_profile_frame_singleton_method_p(VALUE frame);
+ Get information about each frame.
+
+ These APIs are designed for profilers, for example, no objectallocation,
+ and enough information for profilers.
+ In this version, this API collects only collect Ruby level frames.
+ This issue will be fixed after Ruby 2.1.
+
+ * vm_backtrace.c: implement above APIs.
+
+ * iseq.c (rb_iseq_klass): return local_iseq's class.
+
Mon Oct 7 14:26:01 2013 Koichi Sasada <ko1@atdot.net>
* proc.c: catch up last commit.
- Type of return value of rb_iseq_first_lineno() is now VALUE.
+ Type of return value of rb_iseq_first_lioneno() is now VALUE.
* vm_insnhelper.c (argument_error): ditto.
diff --git a/include/ruby/debug.h b/include/ruby/debug.h
index dca0f10..2ef99d4 100644
--- a/include/ruby/debug.h
+++ b/include/ruby/debug.h
@@ -24,6 +24,17 @@ RUBY_SYMBOL_EXPORT_BEGIN
/* Note: This file contains experimental APIs. */
/* APIs can be replaced at Ruby 2.0.1 or later */
+
+/* profile frames APIs */
+int rb_profile_frames(int start, int limit, VALUE *buff, int *lines);
+VALUE rb_profile_frame_path(VALUE frame);
+VALUE rb_profile_frame_absolute_path(VALUE frame);
+VALUE rb_profile_frame_label(VALUE frame);
+VALUE rb_profile_frame_base_label(VALUE frame);
+VALUE rb_profile_frame_first_lineno(VALUE frame);
+VALUE rb_profile_frame_classpath(VALUE frame);
+VALUE rb_profile_frame_singleton_method_p(VALUE frame);
+
/* debug inspector APIs */
typedef struct rb_debug_inspector_struct rb_debug_inspector_t;
typedef VALUE (*rb_debug_inspector_func_t)(const rb_debug_inspector_t *, void *);
diff --git a/iseq.c b/iseq.c
index 6336489..a06a0a9 100644
--- a/iseq.c
+++ b/iseq.c
@@ -956,7 +956,7 @@ rb_iseq_klass(VALUE self)
{
rb_iseq_t *iseq;
GetISeqPtr(self, iseq);
- return iseq->klass;
+ return iseq->local_iseq->klass;
}
static
diff --git a/vm_backtrace.c b/vm_backtrace.c
index 3945993..b4f16f6 100644
--- a/vm_backtrace.c
+++ b/vm_backtrace.c
@@ -1200,3 +1200,90 @@ rb_debug_inspector_backtrace_locations(const rb_debug_inspector_t *dc)
return dc->backtrace;
}
+int
+rb_profile_frames(int start, int limit, VALUE *buff, int *lines)
+{
+ int i;
+ rb_thread_t *th = GET_THREAD();
+ rb_control_frame_t *cfp = th->cfp, *end_cfp = RUBY_VM_END_CONTROL_FRAME(th);
+
+ for (i=0; i<limit && cfp != end_cfp;) {
+ if (cfp->iseq && cfp->pc) { /* should be NORMAL_ISEQ */
+ if (start > 0) {
+ start--;
+ continue;
+ }
+
+ /* record frame info */
+ buff[i] = cfp->iseq->self;
+ if (lines) lines[i] = calc_lineno(cfp->iseq, cfp->pc);
+ i++;
+ }
+ cfp = RUBY_VM_PREVIOUS_CONTROL_FRAME(cfp);
+ }
+
+ return i;
+}
+
+#define frame2iseq(frame) frame
+
+VALUE
+rb_profile_frame_path(VALUE frame)
+{
+ return rb_iseq_path(frame2iseq(frame));
+}
+
+VALUE
+rb_profile_frame_absolute_path(VALUE frame)
+{
+ return rb_iseq_absolute_path(frame2iseq(frame));
+}
+
+VALUE
+rb_profile_frame_label(VALUE frame)
+{
+ return rb_iseq_label(frame2iseq(frame));
+}
+
+VALUE
+rb_profile_frame_base_label(VALUE frame)
+{
+ return rb_iseq_base_label(frame2iseq(frame));
+}
+
+VALUE
+rb_profile_frame_first_lineno(VALUE frame)
+{
+ return rb_iseq_first_lineno(frame2iseq(frame));
+}
+
+VALUE
+rb_profile_frame_classpath(VALUE frame)
+{
+ VALUE klass = rb_iseq_klass(frame2iseq(frame));
+
+ if (klass && !NIL_P(klass)) {
+ if (RB_TYPE_P(klass, T_ICLASS)) {
+ klass = RBASIC(klass)->klass;
+ }
+ else if (FL_TEST(klass, FL_SINGLETON)) {
+ klass = rb_ivar_get(klass, id__attached__);
+ }
+ return rb_class_path(klass);
+ }
+ else {
+ return Qnil;
+ }
+}
+
+VALUE
+rb_profile_frame_singleton_method_p(VALUE frame)
+{
+ VALUE klass = rb_iseq_klass(frame2iseq(frame));
+ if (klass && !NIL_P(klass) && FL_TEST(klass, FL_SINGLETON)) {
+ return Qtrue;
+ }
+ else {
+ return Qfalse;
+ }
+}