ext/thread_frame.c in rb-threadframe-0.37 vs ext/thread_frame.c in rb-threadframe-0.38
- old
+ new
@@ -4,11 +4,11 @@
* Access to Ruby's rb_control_frame_t and methods for working with that.
* Things like getting a binding for a control frame.
*/
/* What release we got? */
-#define THREADFRAME_VERSION "0.37"
+#define THREADFRAME_VERSION "0.38"
#include <string.h>
#include "../include/vm_core_mini.h" /* Pulls in ruby.h and node.h */
#include "proc_extra.h"
#include "iseq_extra.h"
@@ -112,11 +112,15 @@
tf_free(void *ptr)
{
thread_frame_t *tf;
if (ptr) {
tf = ptr;
- if (RUBY_VM_NORMAL_ISEQ_P(tf->cfp->iseq))
+ /* All valid frame types have 0x1 set so we will use this.
+ Warning: this is an undocumented assumption which may someday
+ be wrong. */
+ if (tf->cfp && ((tf->cfp->flag & 0x1) == 0) &&
+ RUBY_VM_NORMAL_ISEQ_P(tf->cfp->iseq))
tf->cfp->iseq->in_use--;
xfree(ptr);
}
}
@@ -810,47 +814,96 @@
}
/*
* call-seq:
* RubyVM::ThreadFrame::prev(thread) -> threadframe_object
- * RubyVM::ThreadFrame::prev(thread, n) -> threadframe_object
+ * RubyVM::ThreadFrame::prev(thread, n) -> threadframe_object
+ * RubyVM::ThreadFrame::prev -> threadframe_object
+ * RubyVM::ThreadFrame::prev(n) -> threadframe_object
*
- * Returns a RubyVM::ThreadFrame for the frame prior to the
- * Thread object passed or nil if there is none. The default value for n
- * is 1. 0 just returns the object passed.
- * Negative counts or counts exceeding the stack will return nil.
+ * In the first form, we return a RubyVM::ThreadFrame prior to the
+ * Thread object passed. That is we go back one frame from the
+ * current frfame.
+ *
+ * In the second form we try to go back that many thread frames.
+ *
+ * In the the third form, the current thread is assumed, and like the
+ * first form we go back one frame.
+ *
+ * The fourth form, like the third form, we assume the current
+ * thread. And like the first form we go back we try to back a
+ * FixNum number of entries.
+ *
+ * When count +n+ is given 1 is synonymous with the previous frame
+ * and 0 is invalid. If the +n+ is negative, we count from the bottom
+ * of the frame stack.
+ *
+ * In all cases we return a RubyVM::ThreadFrame or nil if we can't
+ * go back (or forward for a negative +n+) that many frames.
+ *
*/
static VALUE
thread_frame_s_prev(int argc, VALUE *argv, VALUE klass)
{
- VALUE thval;
- VALUE nv;
- int n;
-
- rb_scan_args(argc, argv, "11", &thval, &nv);
+ VALUE first_val;
+ VALUE second_val;
+ VALUE thval = Qnil;
+ int prev_count = 0;
+ rb_thread_t *th = NULL;
- if (Qfalse == rb_obj_is_kind_of(thval, rb_cThread))
- rb_raise(rb_eTypeError,
- "ThreadFrame object needed for first argument");
-
- GET_THREAD_PTR ;
+ /* Such complicated options processing. But we do want this
+ routine to be convenient. */
+ rb_scan_args(argc, argv, "02", &first_val, &second_val);
+ switch (argc) {
+ case 0:
+ th = ruby_current_thread;
+ /* Do'nt count the RubyVM::ThreadFrame.prev call */
+ prev_count = 2;
+ break;
+ case 1:
+ if (FIXNUM_P(first_val)) {
+ prev_count = FIX2INT(first_val);
+ if (prev_count > 0) prev_count++ ;
+ th = ruby_current_thread;
+ } else
+ if (Qtrue == rb_obj_is_kind_of(first_val, rb_cThread)) {
+ GetThreadPtr(first_val, th);
+ /* Don't count the RubyVM::ThreadFrame.prev call */
+ prev_count = 1;
+ } else {
+ rb_raise(rb_eTypeError,
+ "FixNum or ThreadFrame object expected for first argument");
+ }
+ break;
+ case 2:
+ if (Qtrue == rb_obj_is_kind_of(first_val, rb_cThread)) {
+ GetThreadPtr(first_val, th);
+ } else {
+ rb_raise(rb_eTypeError,
+ "ThreadFrame object expected for first argument");
+ }
+ if (FIXNUM_P(second_val)) {
+ prev_count = FIX2INT(second_val);
+ } else
+ rb_raise(rb_eTypeError,
+ "FixNum previous count expected for second argument");
+ break;
+ default:
+ rb_raise(rb_eArgError, "wrong number of arguments (%d for 1..2)", argc);
+ }
- if (Qnil == nv)
- n = 1;
- else if (!FIXNUM_P(nv)) {
- rb_raise(rb_eTypeError, "Fixnum needed for second argument");
- } else
- n = FIX2INT(nv);
+ if (0 == prev_count) {
+ rb_raise(rb_eArgError,
+ "previous count can not be 0. Use current instead of prev");
+ }
- if (n == 0) {
- return thread_frame_s_current(klass);
- } else if (n < 0) {
+ if (0 > prev_count) {
int stack_size = thread_frame_stack_size_internal(th->cfp, th);
- if (-n > stack_size) return Qnil;
- n = stack_size + n;
+ if (-prev_count > stack_size) return Qnil;
+ prev_count = stack_size + prev_count;
}
- return thread_frame_prev_internal(th->cfp, th, n);
+ return thread_frame_prev_internal(th->cfp, th, prev_count);
}
/*
* call-seq:
* RubyVM::ThreadFrame#source_container() -> [Type, String]