summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog35
-rw-r--r--benchmark/bm_vm2_raise1.rb18
-rw-r--r--benchmark/bm_vm2_raise2.rb18
-rw-r--r--error.c17
-rw-r--r--eval.c2
-rw-r--r--eval_error.c11
-rw-r--r--internal.h5
-rw-r--r--test/ruby/test_settracefunc.rb4
-rw-r--r--vm.c305
-rw-r--r--vm_eval.c24
-rw-r--r--vm_method.c15
11 files changed, 426 insertions, 28 deletions
diff --git a/ChangeLog b/ChangeLog
index a06b5be2f4..655bac0555 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,38 @@
+Thu May 24 14:30:13 2012 Koichi Sasada <ko1@atdot.net>
+
+ * vm.c: add RubyVM::Backtrace object (btobj).
+ Backtrace information contains an array consists of location
+ information for each frames by string.
+ RubyVM::Backtrace object is lightweight backtrace information,
+ which contains complete information to generate traditional style
+ backtrace (an array of strings) with faster generation.
+ If someone accesses to backtrace information via
+ Exception#backtrace, then convert a RubyVM::Backtrace object to
+ traditonal style backtrace.
+ This change causes incompatibility on marshal dumpped binary
+ of Exception. If you have any trouble on it, please tell us
+ before Ruby 2.0 release.
+ Note that RubyVM::Backtrace object should not expose Ruby level.
+
+ * error.c, eval.c, vm_eval.c: ditto.
+
+ * internal.h: ditto.
+
+ * eval_error.c: fix to skip "set_backtrace" method invocation in
+ creating an exception object if it call a normal set_backtrace
+ method (defined by core).
+
+ * test/ruby/test_settracefunc.rb: fix for above change.
+
+ * vm_method.c (rb_method_defined_by): added. This function
+ checks that the given object responds with the given method
+ by the given cfunc.
+
+ * benchmark/bm_vm2_raise1.rb, benchmark/bm_vm2_raise2.rb:
+ add to measure exception creation speed. raise1 create
+ exception objects from shallow stack frame. raise2 create
+ exception objects from deep stack frame.
+
Thu May 24 12:07:46 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
* io.c (io_strip_bom): check EOF. [Bug #6487][ruby-core:45203]
diff --git a/benchmark/bm_vm2_raise1.rb b/benchmark/bm_vm2_raise1.rb
new file mode 100644
index 0000000000..b3d9c3a8a4
--- /dev/null
+++ b/benchmark/bm_vm2_raise1.rb
@@ -0,0 +1,18 @@
+def rec n
+ if n > 0
+ rec n-1
+ else
+ raise
+ end
+end
+
+i=0
+while i<6_000_000 # benchmark loop 2
+ i+=1
+
+ begin
+ rec 1
+ rescue
+ # ignore
+ end
+end
diff --git a/benchmark/bm_vm2_raise2.rb b/benchmark/bm_vm2_raise2.rb
new file mode 100644
index 0000000000..3f1e8dc1c7
--- /dev/null
+++ b/benchmark/bm_vm2_raise2.rb
@@ -0,0 +1,18 @@
+def rec n
+ if n > 0
+ rec n-1
+ else
+ raise
+ end
+end
+
+i=0
+while i<6_000_000 # benchmark loop 2
+ i+=1
+
+ begin
+ rec 10
+ rescue
+ # ignore
+ end
+end
diff --git a/error.c b/error.c
index 90f04829f9..1be043057a 100644
--- a/error.c
+++ b/error.c
@@ -673,9 +673,17 @@ static VALUE
exc_backtrace(VALUE exc)
{
ID bt;
+ VALUE obj;
CONST_ID(bt, "bt");
- return rb_attr_get(exc, bt);
+ obj = rb_attr_get(exc, bt);
+
+ if (rb_backtrace_p(obj)) {
+ obj = rb_backtrace_to_str_ary(obj);
+ /* rb_iv_set(exc, "bt", obj); */
+ }
+
+ return obj;
}
VALUE
@@ -686,6 +694,7 @@ rb_check_backtrace(VALUE bt)
if (!NIL_P(bt)) {
if (RB_TYPE_P(bt, T_STRING)) return rb_ary_new3(1, bt);
+ if (rb_backtrace_p(bt)) return bt;
if (!RB_TYPE_P(bt, T_ARRAY)) {
rb_raise(rb_eTypeError, err);
}
@@ -708,8 +717,8 @@ rb_check_backtrace(VALUE bt)
*
*/
-static VALUE
-exc_set_backtrace(VALUE exc, VALUE bt)
+VALUE
+rb_exc_set_backtrace(VALUE exc, VALUE bt)
{
return rb_iv_set(exc, "bt", rb_check_backtrace(bt));
}
@@ -1669,7 +1678,7 @@ Init_Exception(void)
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, "set_backtrace", exc_set_backtrace, 1);
+ rb_define_method(rb_eException, "set_backtrace", rb_exc_set_backtrace, 1);
rb_eSystemExit = rb_define_class("SystemExit", rb_eException);
rb_define_method(rb_eSystemExit, "initialize", exit_initialize, -1);
diff --git a/eval.c b/eval.c
index 75dca74be3..298326a556 100644
--- a/eval.c
+++ b/eval.c
@@ -387,7 +387,7 @@ setup_exception(rb_thread_t *th, int tag, volatile VALUE mesg)
else {
at = get_backtrace(mesg);
if (NIL_P(at)) {
- at = rb_make_backtrace();
+ at = rb_vm_backtrace_object();
if (OBJ_FROZEN(mesg)) {
mesg = rb_obj_dup(mesg);
}
diff --git a/eval_error.c b/eval_error.c
index e7eb9cf0fc..a2e95a759f 100644
--- a/eval_error.c
+++ b/eval_error.c
@@ -58,6 +58,17 @@ rb_get_backtrace(VALUE info)
static void
set_backtrace(VALUE info, VALUE bt)
{
+ ID set_backtrace = rb_intern("set_backtrace");
+
+ if (rb_backtrace_p(bt)) {
+ if (rb_method_defined_by(info, set_backtrace, rb_exc_set_backtrace)) {
+ rb_exc_set_backtrace(info, bt);
+ return;
+ }
+ else {
+ bt = rb_backtrace_to_str_ary(bt);
+ }
+ }
rb_funcall(info, rb_intern("set_backtrace"), 1, bt);
}
diff --git a/internal.h b/internal.h
index e5818429ea..6ba8e1f3b0 100644
--- a/internal.h
+++ b/internal.h
@@ -83,6 +83,7 @@ void rb_gc_mark_encodings(void);
NORETURN(PRINTF_ARGS(void rb_compile_bug(const char*, int, const char*, ...), 3, 4));
VALUE rb_check_backtrace(VALUE);
NORETURN(void rb_async_bug_errno(const char *,int));
+VALUE rb_exc_set_backtrace(VALUE exc, VALUE bt);
/* eval_error.c */
void ruby_error_print(void);
@@ -207,6 +208,9 @@ void rb_vm_inc_const_missing_count(void);
void rb_thread_mark(void *th);
const void **rb_vm_get_insns_address_table(void);
VALUE rb_sourcefilename(void);
+int rb_backtrace_p(VALUE obj);
+VALUE rb_backtrace_to_str_ary(VALUE obj);
+VALUE rb_vm_backtrace_object();
/* vm_dump.c */
void rb_vm_bugreport(void);
@@ -217,6 +221,7 @@ VALUE rb_current_realfilepath(void);
/* vm_method.c */
void Init_eval_method(void);
+int rb_method_defined_by(VALUE obj, ID mid, VALUE (*cfunc)(ANYARGS));
/* miniprelude.c, prelude.c */
void Init_prelude(void);
diff --git a/test/ruby/test_settracefunc.rb b/test/ruby/test_settracefunc.rb
index 32be12814b..463923aa26 100644
--- a/test/ruby/test_settracefunc.rb
+++ b/test/ruby/test_settracefunc.rb
@@ -250,10 +250,6 @@ class TestSetTraceFunc < Test::Unit::TestCase
events.shift)
assert_equal(["c-return", 5, :backtrace, Exception],
events.shift)
- assert_equal(["c-call", 5, :set_backtrace, Exception],
- events.shift)
- assert_equal(["c-return", 5, :set_backtrace, Exception],
- events.shift)
assert_equal(["raise", 5, :test_raise, TestSetTraceFunc],
events.shift)
assert_equal(["c-return", 5, :raise, Kernel],
diff --git a/vm.c b/vm.c
index dea51a2911..0898deac92 100644
--- a/vm.c
+++ b/vm.c
@@ -36,14 +36,16 @@ VALUE rb_cRubyVM;
VALUE rb_cThread;
VALUE rb_cEnv;
VALUE rb_mRubyVMFrozenCore;
+VALUE rb_cBacktrace;
+VALUE rb_cFrameInfo;
VALUE ruby_vm_const_missing_count = 0;
-
char ruby_vm_redefined_flag[BOP_LAST_];
-
rb_thread_t *ruby_current_thread = 0;
rb_vm_t *ruby_current_vm = 0;
+extern VALUE ruby_engine_name;
+
static void thread_free(void *ptr);
void vm_analysis_operand(int insn, int n, VALUE op);
@@ -731,6 +733,12 @@ rb_lastline_set(VALUE val)
/* backtrace */
+inline static int
+calc_line_no(const rb_iseq_t *iseq, VALUE *pc)
+{
+ return rb_iseq_line_no(iseq, pc - iseq->iseq_encoded);
+}
+
int
rb_vm_get_sourceline(const rb_control_frame_t *cfp)
{
@@ -738,22 +746,289 @@ rb_vm_get_sourceline(const rb_control_frame_t *cfp)
const rb_iseq_t *iseq = cfp->iseq;
if (RUBY_VM_NORMAL_ISEQ_P(iseq)) {
- size_t pos = cfp->pc - cfp->iseq->iseq_encoded;
- line_no = rb_iseq_line_no(iseq, pos);
+ line_no = calc_line_no(cfp->iseq, cfp->pc);
}
return line_no;
}
+typedef struct rb_frame_info_struct {
+ enum FRAME_INFO_TYPE {
+ FRAME_INFO_TYPE_ISEQ = 1,
+ FRAME_INFO_TYPE_CFUNC,
+ FRAME_INFO_TYPE_IFUNC,
+ } type;
+
+ union {
+ struct {
+ rb_iseq_t *iseq;
+ VALUE *pc;
+ } iseq;
+ struct {
+ ID mid;
+ } cfunc;
+ } body;
+} rb_frame_info_t;
+
+static void
+frame_info_mark(void *ptr)
+{
+ if (ptr) {
+ rb_frame_info_t *fi = (rb_frame_info_t *)ptr;
+
+ switch (fi->type) {
+ case FRAME_INFO_TYPE_ISEQ:
+ rb_gc_mark(fi->body.iseq.iseq->self);
+ break;
+ case FRAME_INFO_TYPE_CFUNC:
+ case FRAME_INFO_TYPE_IFUNC:
+ default:
+ break;
+ }
+ }
+}
+
+static VALUE
+frame_info_format(VALUE file, VALUE line_no, VALUE name)
+{
+ if (line_no != INT2FIX(0)) {
+ return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:%d:in `%s'",
+ RSTRING_PTR(file), FIX2INT(line_no), RSTRING_PTR(name));
+ }
+ else {
+ return rb_enc_sprintf(rb_enc_compatible(file, name), "%s:in `%s'",
+ RSTRING_PTR(file), RSTRING_PTR(name));
+ }
+}
+
+static VALUE
+frame_info_to_str_override(rb_frame_info_t *fi, VALUE *args)
+{
+ switch (fi->type) {
+ case FRAME_INFO_TYPE_ISEQ:
+ args[0] = fi->body.iseq.iseq->location.filename;
+ args[1] = INT2FIX(calc_line_no(fi->body.iseq.iseq, fi->body.iseq.pc));
+ args[2] = fi->body.iseq.iseq->location.name;
+ break;
+ case FRAME_INFO_TYPE_CFUNC:
+ args[2] = rb_id2str(fi->body.cfunc.mid);
+ break;
+ case FRAME_INFO_TYPE_IFUNC:
+ default:
+ rb_bug("frame_info_to_str_overwrite: unreachable");
+ }
+
+ return frame_info_format(args[0], args[1], args[2]);
+}
+
+typedef struct rb_backtrace_struct {
+ rb_frame_info_t *backtrace;
+ int backtrace_size;
+ VALUE str;
+} rb_backtrace_t;
+
+static void
+backtrace_mark(void *ptr)
+{
+ if (ptr) {
+ rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
+ int i, s = bt->backtrace_size;
+
+ for (i=0; i<s; i++) {
+ frame_info_mark(&bt->backtrace[i]);
+ rb_gc_mark(bt->str);
+ }
+ }
+}
+
+static void
+backtrace_free(void *ptr)
+{
+ if (ptr) {
+ rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
+ if (bt->backtrace) ruby_xfree(bt->backtrace);
+ ruby_xfree(bt);
+ }
+}
+
+static size_t
+backtrace_memsize(const void *ptr)
+{
+ rb_backtrace_t *bt = (rb_backtrace_t *)ptr;
+ return sizeof(rb_backtrace_t) + sizeof(rb_frame_info_t) * bt->backtrace_size;
+}
+
+static const rb_data_type_t backtrace_data_type = {
+ "backtrace",
+ {backtrace_mark, backtrace_free, backtrace_memsize,},
+};
+
+int
+rb_backtrace_p(VALUE obj)
+{
+ if (TYPE(obj) == T_DATA && RTYPEDDATA_P(obj) && RTYPEDDATA_TYPE(obj) == &backtrace_data_type) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+
+static VALUE
+backtrace_alloc(VALUE klass)
+{
+ rb_backtrace_t *bt;
+ VALUE obj = TypedData_Make_Struct(klass, rb_backtrace_t, &backtrace_data_type, bt);
+ bt->backtrace = 0;
+ bt->backtrace_size = 0;
+ bt->str = 0;
+ return obj;
+}
+
+static VALUE
+backtrace_object(rb_thread_t *th, int lev, int n)
+{
+ VALUE btobj = backtrace_alloc(rb_cBacktrace);
+ rb_backtrace_t *bt;
+ rb_control_frame_t *last_cfp = th->cfp;
+ rb_control_frame_t *start_cfp = RUBY_VM_END_CONTROL_FRAME(th);
+ rb_control_frame_t *cfp;
+ int size, i, j;
+
+ start_cfp = RUBY_VM_NEXT_CONTROL_FRAME(
+ RUBY_VM_NEXT_CONTROL_FRAME(
+ RUBY_VM_NEXT_CONTROL_FRAME(start_cfp))); /* skip top frames */
+ size = (start_cfp - last_cfp) + 1;
+
+ if (n <= 0) {
+ n = size + n;
+ if (n < 0) {
+ n = 0;
+ }
+ }
+ if (lev < 0) {
+ lev = 0;
+ }
+
+ GetCoreDataFromValue(btobj, rb_backtrace_t, bt);
+ bt->backtrace = ruby_xmalloc(sizeof(rb_frame_info_t) * n);
+ bt->backtrace_size = n;
+
+ for (i=lev, j=0, cfp = start_cfp; i<size && j<n; i++, cfp = RUBY_VM_NEXT_CONTROL_FRAME(cfp)) {
+ rb_frame_info_t *fi = &bt->backtrace[j];
+
+ if (cfp->iseq) {
+ if (cfp->pc) {
+ fi->type = FRAME_INFO_TYPE_ISEQ;
+ fi->body.iseq.iseq = cfp->iseq;
+ fi->body.iseq.pc = cfp->pc;
+ j++;
+ }
+ }
+ else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
+ ID mid = cfp->me->def ? cfp->me->def->original_id : cfp->me->called_id;
+
+ if (mid != ID_ALLOCATOR) {
+ fi->type = FRAME_INFO_TYPE_CFUNC;
+ fi->body.cfunc.mid = mid;
+ j++;
+ }
+ }
+ }
+
+ if (j > 0) {
+ bt->backtrace_size = j; /* TODO: realloc? */
+ return btobj;
+ }
+ else {
+ /* gc will free object */
+ return Qnil;
+ }
+}
+
+static VALUE
+backtreace_collect(rb_backtrace_t *bt, VALUE (*func)(rb_frame_info_t *, VALUE *))
+{
+ VALUE btary;
+ int i;
+ VALUE args[3];
+ rb_thread_t *th = GET_THREAD();
+
+ btary = rb_ary_new2(bt->backtrace_size);
+ rb_ary_store(btary, bt->backtrace_size-1, Qnil); /* create places */
+
+ args[0] = th->vm->progname ? th->vm->progname : ruby_engine_name;;
+ args[1] = INT2FIX(0);
+ args[2] = Qnil;
+
+ for (i=0; i<bt->backtrace_size; i++) {
+ rb_frame_info_t *fi = &bt->backtrace[i];
+ RARRAY_PTR(btary)[bt->backtrace_size - i - 1] = func(fi, args);
+ }
+
+ return btary;
+}
+
+VALUE
+rb_backtrace_to_str_ary(VALUE self)
+{
+ rb_backtrace_t *bt;
+ GetCoreDataFromValue(self, rb_backtrace_t, bt);
+
+ if (bt->str) {
+ return bt->str;
+ }
+ else {
+ bt->str = backtreace_collect(bt, frame_info_to_str_override);
+ return bt->str;
+ }
+}
+
+#if 0
+static VALUE
+rb_backtrace_to_frame_ary(VALUE self)
+{
+ return backtreace_collect(self, frame_info_create);
+}
+
+static VALUE
+vm_backtrace_frame_ary(rb_thread_t *th, int lev, int n)
+{
+ return rb_backtrace_to_frame_ary(vm_backtrace_create(th, lev, n));
+}
+#endif
+
+static VALUE
+backtrace_dump_data(VALUE self)
+{
+ VALUE str = rb_backtrace_to_str_ary(self);
+ return str;
+}
+
+static VALUE
+backtrace_load_data(VALUE self, VALUE str)
+{
+ rb_backtrace_t *bt;
+ GetCoreDataFromValue(self, rb_backtrace_t, bt);
+ bt->str = str;
+ return self;
+}
+
+/* old style backtrace for compatibility */
+
static int
-vm_backtrace_each(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg)
+vm_backtrace_each(rb_thread_t *th, int lev, int n, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg)
{
const rb_control_frame_t *limit_cfp = th->cfp;
const rb_control_frame_t *cfp = (void *)(th->stack + th->stack_size);
VALUE file = Qnil;
int line_no = 0;
+ if (n <= 0) {
+ n = cfp - limit_cfp;
+ }
+
cfp -= 2;
- while (lev-- >= 0) {
+ while (lev-- >= 0 && n > 0) {
if (++limit_cfp > cfp) {
return FALSE;
}
@@ -761,20 +1036,21 @@ vm_backtrace_each(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_i
if (init) (*init)(arg);
limit_cfp = RUBY_VM_NEXT_CONTROL_FRAME(limit_cfp);
if (th->vm->progname) file = th->vm->progname;
- while (cfp > limit_cfp) {
+ while (cfp > limit_cfp && n>0) {
if (cfp->iseq != 0) {
if (cfp->pc != 0) {
rb_iseq_t *iseq = cfp->iseq;
line_no = rb_vm_get_sourceline(cfp);
file = iseq->location.filename;
+ n--;
if ((*iter)(arg, file, line_no, iseq->location.name)) break;
}
}
else if (RUBYVM_CFUNC_FRAME_P(cfp)) {
ID id;
- extern VALUE ruby_engine_name;
+ n--;
if (NIL_P(file)) file = ruby_engine_name;
if (cfp->me->def)
id = cfp->me->def->original_id;
@@ -813,15 +1089,15 @@ vm_backtrace_push(void *arg, VALUE file, int line_no, VALUE name)
return 0;
}
-static inline VALUE
-vm_backtrace(rb_thread_t *th, int lev)
+static VALUE
+vm_backtrace_str_ary(rb_thread_t *th, int lev, int n)
{
VALUE ary = 0;
if (lev < 0) {
ary = rb_ary_new();
}
- vm_backtrace_each(th, lev, vm_backtrace_alloc, vm_backtrace_push, &ary);
+ vm_backtrace_each(th, lev, 0, vm_backtrace_alloc, vm_backtrace_push, &ary);
if (!ary) return Qnil;
return rb_ary_reverse(ary);
}
@@ -2172,6 +2448,13 @@ Init_VM(void)
rb_cThread = rb_define_class("Thread", rb_cObject);
rb_undef_alloc_func(rb_cThread);
+ /* ::RubyVM::Backtrace */
+ rb_cBacktrace = rb_define_class_under(rb_cRubyVM, "Backtrace", rb_cObject);
+ rb_define_alloc_func(rb_cBacktrace, backtrace_alloc);
+ rb_undef_method(CLASS_OF(rb_cFrameInfo), "new");
+ rb_define_method(rb_cBacktrace, "_dump_data", backtrace_dump_data, 0);
+ rb_define_method(rb_cBacktrace, "_load_data", backtrace_load_data, 1);
+
/* ::RubyVM::USAGE_ANALYSIS_* */
rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_INSN", rb_hash_new());
rb_define_const(rb_cRubyVM, "USAGE_ANALYSIS_REGS", rb_hash_new());
diff --git a/vm_eval.c b/vm_eval.c
index 8d6c91a158..340abfc610 100644
--- a/vm_eval.c
+++ b/vm_eval.c
@@ -15,13 +15,15 @@ static inline VALUE method_missing(VALUE obj, ID id, int argc, const VALUE *argv
static inline VALUE rb_vm_set_finish_env(rb_thread_t * th);
static inline VALUE vm_yield_with_cref(rb_thread_t *th, int argc, const VALUE *argv, const NODE *cref);
static inline VALUE vm_yield(rb_thread_t *th, int argc, const VALUE *argv);
-static inline VALUE vm_backtrace(rb_thread_t *th, int lev);
-static int vm_backtrace_each(rb_thread_t *th, int lev, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg);
static NODE *vm_cref_push(rb_thread_t *th, VALUE klass, int noex, rb_block_t *blockptr);
static VALUE vm_exec(rb_thread_t *th);
static void vm_set_eval_stack(rb_thread_t * th, VALUE iseqval, const NODE *cref);
static int vm_collect_local_variables_in_heap(rb_thread_t *th, VALUE *dfp, VALUE ary);
+static int vm_backtrace_each(rb_thread_t *th, int lev, int n, void (*init)(void *), rb_backtrace_iter_func *iter, void *arg);
+static VALUE backtrace_object(rb_thread_t *th, int lev, int n);
+static VALUE vm_backtrace_str_ary(rb_thread_t *th, int lev, int n);
+
typedef enum call_type {
CALL_PUBLIC,
CALL_FCALL,
@@ -1085,7 +1087,7 @@ eval_string_with_cref(VALUE self, VALUE src, VALUE scope, NODE *cref, const char
errat = rb_get_backtrace(errinfo);
mesg = rb_attr_get(errinfo, id_mesg);
if (!NIL_P(errat) && RB_TYPE_P(errat, T_ARRAY) &&
- (bt2 = vm_backtrace(th, -2), RARRAY_LEN(bt2) > 0)) {
+ (bt2 = vm_backtrace_str_ary(th, -2, 0), RARRAY_LEN(bt2) > 0)) {
if (!NIL_P(mesg) && RB_TYPE_P(mesg, T_STRING) && !RSTRING_LEN(mesg)) {
if (OBJ_FROZEN(mesg)) {
VALUE m = rb_str_cat(rb_str_dup(RARRAY_PTR(errat)[0]), ": ", 2);
@@ -1620,7 +1622,7 @@ rb_f_caller(int argc, VALUE *argv)
if (lev < 0)
rb_raise(rb_eArgError, "negative level (%d)", lev);
- return vm_backtrace(GET_THREAD(), lev);
+ return vm_backtrace_str_ary(GET_THREAD(), lev, 0);
}
static int
@@ -1642,13 +1644,19 @@ print_backtrace(void *arg, VALUE file, int line, VALUE method)
void
rb_backtrace(void)
{
- vm_backtrace_each(GET_THREAD(), -1, NULL, print_backtrace, stderr);
+ vm_backtrace_each(GET_THREAD(), -1, 0, NULL, print_backtrace, stderr);
}
VALUE
rb_make_backtrace(void)
{
- return vm_backtrace(GET_THREAD(), -1);
+ return vm_backtrace_str_ary(GET_THREAD(), -1, 0);
+}
+
+VALUE
+rb_vm_backtrace_object()
+{
+ return backtrace_object(GET_THREAD(), -1, 0);
}
VALUE
@@ -1667,13 +1675,13 @@ rb_thread_backtrace(VALUE thval)
return Qnil;
}
- return vm_backtrace(th, 0);
+ return vm_backtrace_str_ary(th, 0, 0);
}
int
rb_backtrace_each(rb_backtrace_iter_func *iter, void *arg)
{
- return vm_backtrace_each(GET_THREAD(), -1, NULL, iter, arg);
+ return vm_backtrace_each(GET_THREAD(), -1, 0, NULL, iter, arg);
}
/*
diff --git a/vm_method.c b/vm_method.c
index f3da623347..8c606d410c 100644
--- a/vm_method.c
+++ b/vm_method.c
@@ -1402,3 +1402,18 @@ Init_eval_method(void)
}
}
+int
+rb_method_defined_by(VALUE obj, ID mid, VALUE (*cfunc)(ANYARGS))
+{
+ rb_method_entry_t *me = search_method(CLASS_OF(obj), mid);
+
+ if (me && me->def &&
+ me->def->type == VM_METHOD_TYPE_CFUNC &&
+ me->def->body.cfunc.func == cfunc) {
+ return 1;
+ }
+ else {
+ return 0;
+ }
+}
+