rb-threadframe 0.36 → 0.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/NEWS CHANGED
@@ -1,4 +1,9 @@
1
- December 25, 2010 (0.35)
1
+ Feb 1, 2011 (0.37)
2
+ - 1.9.2 patches:
3
+ * Mark VM Instruction sequences for no garbage collection if they are
4
+ referred to by a ThreadFrame Object or are in ISEQS__ or ISEQ_SCRIPTS__
5
+
6
+ December 25, 2010 (0.35, 0.36)
2
7
  - 1.9.2 patches:
3
8
  * Add new compile-option flags: save_tree_node and save_compile_opts
4
9
  * Start saving parse tree node. (More cases need to be done.)
@@ -1,12 +1,12 @@
1
1
  /*
2
- * Copyright (C) 2010 Rocky Bernstein
2
+ * Copyright (C) 2010, 2011 Rocky Bernstein
3
3
  *
4
4
  * Access to Ruby's rb_control_frame_t and methods for working with that.
5
5
  * Things like getting a binding for a control frame.
6
6
  */
7
7
 
8
8
  /* What release we got? */
9
- #define THREADFRAME_VERSION "0.36"
9
+ #define THREADFRAME_VERSION "0.37"
10
10
 
11
11
  #include <string.h>
12
12
  #include "../include/vm_core_mini.h" /* Pulls in ruby.h and node.h */
@@ -14,6 +14,51 @@
14
14
  #include "iseq_extra.h"
15
15
  #include "thread_extra.h"
16
16
 
17
+ /* for GC debug */
18
+
19
+ #ifndef RUBY_MARK_FREE_DEBUG
20
+ #define RUBY_MARK_FREE_DEBUG 0
21
+ #endif
22
+
23
+ #if RUBY_MARK_FREE_DEBUG
24
+ extern int ruby_gc_debug_indent;
25
+
26
+ static void
27
+ rb_gc_debug_indent(void)
28
+ {
29
+ printf("%*s", ruby_gc_debug_indent, "");
30
+ }
31
+
32
+ static void
33
+ rb_gc_debug_body(const char *mode, const char *msg, int st, void *ptr)
34
+ {
35
+ if (st == 0) {
36
+ ruby_gc_debug_indent--;
37
+ }
38
+ rb_gc_debug_indent();
39
+ printf("%s: %s %s (%p)\n", mode, st ? "->" : "<-", msg, ptr);
40
+
41
+ if (st) {
42
+ ruby_gc_debug_indent++;
43
+ }
44
+
45
+ fflush(stdout);
46
+ }
47
+
48
+ #define RUBY_MARK_ENTER(msg) rb_gc_debug_body("mark", msg, 1, ptr)
49
+ #define RUBY_MARK_LEAVE(msg) rb_gc_debug_body("mark", msg, 0, ptr)
50
+ #define RUBY_FREE_ENTER(msg) rb_gc_debug_body("free", msg, 1, ptr)
51
+ #define RUBY_FREE_LEAVE(msg) rb_gc_debug_body("free", msg, 0, ptr)
52
+ #define RUBY_GC_INFO rb_gc_debug_indent(); printf
53
+
54
+ #else
55
+ #define RUBY_MARK_ENTER(msg)
56
+ #define RUBY_MARK_LEAVE(msg)
57
+ #define RUBY_FREE_ENTER(msg)
58
+ #define RUBY_FREE_LEAVE(msg)
59
+ #define RUBY_GC_INFO if(0)printf
60
+ #endif
61
+
17
62
  /* Frames can't be detached from the control frame they live in.
18
63
  So we create a structure to contain the pair.
19
64
 
@@ -45,20 +90,51 @@ static int thread_frame_stack_size_internal(rb_control_frame_t *cfp,
45
90
  static VALUE thread_frame_type(VALUE klass);
46
91
 
47
92
 
93
+ extern void iseq_mark(void *ptr); /* in iseq.c */
94
+
95
+ /*
96
+ FIXME: I've never seen the following routine get called.
97
+ Why?
98
+ */
99
+ static void
100
+ thread_frame_mark(void *ptr)
101
+ {
102
+ RUBY_MARK_ENTER("thread_frame");
103
+ if (ptr) {
104
+ thread_frame_t *tf = ptr;
105
+ if (tf && tf->cfp && RUBY_VM_NORMAL_ISEQ_P(tf->cfp->iseq)) {
106
+ iseq_mark(tf->cfp->iseq);
107
+ }
108
+ }
109
+ }
110
+
111
+ static void
112
+ tf_free(void *ptr)
113
+ {
114
+ thread_frame_t *tf;
115
+ if (ptr) {
116
+ tf = ptr;
117
+ if (RUBY_VM_NORMAL_ISEQ_P(tf->cfp->iseq))
118
+ tf->cfp->iseq->in_use--;
119
+ xfree(ptr);
120
+ }
121
+ }
122
+
48
123
  /*
49
124
  Allocate a RubyVM::ThreadFrame used by new. Less common than
50
- thread_frame_t_alloc().
125
+ thread_frame_t_alloc(). The caller is responsible for filling in
126
+ the C struct data. Below we wrap NULL.
51
127
  */
52
128
  static VALUE
53
129
  thread_frame_alloc(VALUE klass)
54
130
  {
55
- return Data_Wrap_Struct(klass, NULL, xfree, 0);
131
+ return Data_Wrap_Struct(klass, thread_frame_mark, tf_free, NULL);
56
132
  }
57
133
 
58
134
  /*
59
135
  Allocate a RubyVM::ThreadFrame and set its threadframe structure.
60
136
  This is the more common allocate routine since one normally doesn't
61
- create a threadframe without <i>first</i> having seomthing to put in it.
137
+ create a threadframe without <i>first</i> having something to put in it.
62
138
  */
63
139
  static thread_frame_t *
64
140
  thread_frame_t_alloc(VALUE tfval)
@@ -69,6 +145,13 @@ thread_frame_t_alloc(VALUE tfval)
69
145
  return tf;
70
146
  }
71
147
 
148
+ /*
149
+ Check to see if tf is valid. +true+ is returned if we can't prove
150
+ the frame is invalide. +nil+ or +false+ is returned if something is not
151
+ right. In those cases where we don't know that we have a valid frame,
152
+ we also NULL out the cfp if that hasn't been done already. This will
153
+ keep garbage collection from marking bad data.
154
+ */
72
155
  static VALUE
73
156
  thread_frame_invalid_internal(thread_frame_t *tf)
74
157
  {
@@ -77,16 +160,24 @@ thread_frame_invalid_internal(thread_frame_t *tf)
77
160
  /* All valid frame types have 0x1 set so we will use this.
78
161
  Warning: this is an undocumented assumption which may someday
79
162
  be wrong. */
80
- if ((tf->cfp->flag & 0x1) == 0) return Qtrue;
163
+ if (!tf->cfp) return Qtrue;
164
+ if ((tf->cfp->flag & 0x1) == 0) {
165
+ tf->cfp = NULL;
166
+ return Qtrue;
167
+ }
81
168
 
82
- if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(tf->th, tf->cfp))
169
+ if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(tf->th, tf->cfp)) {
170
+ tf->cfp = NULL;
83
171
  return Qtrue;
172
+ }
84
173
  if (RUBY_VM_NORMAL_ISEQ_P(tf->cfp->iseq)) {
85
174
  cmp = (0 == memcmp(tf->signature1, &(tf->cfp->iseq),
86
175
  sizeof(tf->signature1)) &&
87
176
  0 == memcmp(tf->signature2, &(tf->cfp->proc),
88
177
  sizeof(tf->signature2)));
89
- return cmp ? Qfalse : Qtrue;
178
+ if (cmp) return Qfalse;
179
+ tf->cfp = NULL;
180
+ return Qtrue;
90
181
  } else {
91
182
  /* FIXME: figure out what to do here. Probably more work is
92
183
  * needed in thread_frame_prev_internal.
@@ -114,6 +205,7 @@ thread_frame_invalid_internal(thread_frame_t *tf)
114
205
  #define SAVE_FRAME(TF, TH) \
115
206
  tf->th = TH; \
116
207
  tf->cfp = thread_control_frame(tf->th); \
208
+ tf->cfp->iseq->in_use++; \
117
209
  COPY_SIGNATURE(tf, tf->cfp); \
118
210
 
119
211
  #define GET_THREAD_PTR \
@@ -134,7 +226,7 @@ thread_frame_threadframe(VALUE thval)
134
226
  GET_THREAD_PTR;
135
227
  memset(tf, 0, sizeof(thread_frame_t));
136
228
  SAVE_FRAME(tf, th) ;
137
- return Data_Wrap_Struct(rb_cThreadFrame, NULL, xfree, tf);
229
+ return Data_Wrap_Struct(rb_cThreadFrame, thread_frame_mark, tf_free, tf);
138
230
  }
139
231
 
140
232
  #define THREAD_FRAME_SETUP \
@@ -714,7 +806,7 @@ thread_frame_s_current(VALUE klass)
714
806
  {
715
807
  thread_frame_t *tf = thread_frame_t_alloc(klass);
716
808
  SAVE_FRAME(tf, ruby_current_thread) ;
717
- return Data_Wrap_Struct(klass, NULL, xfree, tf);
809
+ return Data_Wrap_Struct(klass, thread_frame_mark, tf_free, tf);
718
810
  }
719
811
 
720
812
  /*
@@ -94,13 +94,13 @@ typedef struct rb_iseq_struct {
94
94
  /***************/
95
95
 
96
96
  VALUE type; /* instruction sequence type */
97
- VALUE name; /* String: iseq name */
97
+ VALUE name; /* String: iseq name */
98
98
  VALUE filename; /* file information where this sequence from */
99
99
  VALUE filepath; /* real file path or nil */
100
100
  VALUE *iseq; /* iseq (insn number and operands) */
101
101
  VALUE *iseq_encoded; /* encoded iseq */
102
102
  unsigned long iseq_size;
103
- VALUE mark_ary; /* Array: includes operands which should be GC marked */
103
+ VALUE mark_ary; /* Array: includes operands which should be GC marked */
104
104
  VALUE coverage; /* coverage array */
105
105
  unsigned short line_no;
106
106
 
@@ -108,7 +108,7 @@ typedef struct rb_iseq_struct {
108
108
  struct iseq_insn_info_entry *insn_info_table;
109
109
  size_t insn_info_size;
110
110
 
111
- ID *local_table; /* must free */
111
+ ID *local_table; /* must free */
112
112
  int local_table_size;
113
113
 
114
114
  /* method, class frame: sizeof(vars) + 1, block frame: sizeof(vars) */
@@ -165,7 +165,7 @@ typedef struct rb_iseq_struct {
165
165
  /****************/
166
166
 
167
167
  VALUE self;
168
- VALUE orig; /* non-NULL if its data have origin */
168
+ VALUE orig; /* non-NULL if its data have origin */
169
169
 
170
170
  /* block inlining */
171
171
  /*
@@ -189,13 +189,17 @@ typedef struct rb_iseq_struct {
189
189
 
190
190
  /* If this instruction sequence came from eval, the string of the
191
191
  source as a String. */
192
- VALUE source;
192
+ VALUE eval_source;
193
193
 
194
194
  /* If we are saving tree nodes (a compile option), then tree_node
195
195
  is the internal parse tree node representation for this
196
196
  instruction sequence.
197
197
  */
198
198
  NODE *tree_node;
199
+ int in_use; /* Reference count of number of times and instruction
200
+ sequence is in use such as via thread_frame object
201
+ access or is stored in ISEQS__ or SCRIPT_ISEQS.
202
+ */
199
203
  } rb_iseq_t;
200
204
 
201
205
  enum ruby_special_exceptions {
@@ -234,8 +238,8 @@ typedef struct rb_vm_struct {
234
238
 
235
239
  /* signal */
236
240
  struct {
237
- VALUE cmd;
238
- int safe;
241
+ VALUE cmd;
242
+ int safe;
239
243
  } trap_list[RUBY_NSIG];
240
244
 
241
245
  /* hook */
@@ -308,8 +312,8 @@ typedef struct rb_thread_struct
308
312
  rb_event_flag_t event_flags;
309
313
  int tracing; /* 0 if not tracing. If less than 0, skip that many
310
314
  C call/return pairs */
315
+
311
316
  int exec_event_tracing; /* 0 if not in rb_threadptr_evec_event_hooks. */
312
- int trace_skip_insn_count; /* # of VM instructions to skip */
313
317
 
314
318
  /* misc */
315
319
  int method_missing_reason;
@@ -0,0 +1,60 @@
1
+ require 'test/unit'
2
+
3
+ class TestISeqBrkpt < Test::Unit::TestCase
4
+
5
+ def setup
6
+ @original_compile_option = RubyVM::InstructionSequence.compile_option
7
+ RubyVM::InstructionSequence.compile_option = {
8
+ :trace_instruction => false,
9
+ :specialized_instruction => false
10
+ }
11
+ end
12
+
13
+ def teardown
14
+ set_trace_func(nil)
15
+ RubyVM::InstructionSequence.compile_option = @original_compile_option
16
+ end
17
+
18
+ def test_iseq_brkpt
19
+ iseq = RubyVM::InstructionSequence.compile('x=1; y=2')
20
+ assert iseq
21
+ assert_equal(nil, iseq.brkpts)
22
+ assert_equal(true, iseq.brkpt_alloc)
23
+ assert_equal([], iseq.brkpts)
24
+ assert_equal(false, iseq.brkpt_alloc)
25
+
26
+ assert_equal(true, iseq.brkpt_set(0))
27
+ assert_equal(1, iseq.brkpts.size)
28
+ assert_equal(true, iseq.brkpt_get(0), 'Offset 0 should be set')
29
+ assert_equal(true, iseq.brkpt_unset(0),'Offset 0 should be unset')
30
+ assert_equal(false, iseq.brkpt_get(0), 'Offset 0 should be unset now')
31
+ assert_equal(true, iseq.brkpt_unset(0),
32
+ 'Offset 0 should be unset again')
33
+ assert_raises TypeError do iseq.brkpt_get(100) end
34
+ assert_equal(true, iseq.brkpt_dealloc)
35
+ assert_equal(false, iseq.brkpt_dealloc)
36
+ assert_equal(true, iseq.brkpt_unset(0),
37
+ 'Offset 0 should be unset even when deallocated')
38
+
39
+ assert_raises TypeError do iseq.brkpt_set('a') end
40
+
41
+ iseq.brkpt_set(2)
42
+ iseq.brkpt_set(4)
43
+ events = []
44
+ eval <<-EOF.gsub(/^.*?: /, "")
45
+ 1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
46
+ 2: events << [event, lineno, mid, klass]
47
+ 3: })
48
+ 4: iseq.eval
49
+ 5: set_trace_func(nil)
50
+ EOF
51
+ # puts iseq.disassemble
52
+ brkpt_events = events.select{|item| item[0] == 'brkpt'}
53
+ assert_equal(2, brkpt_events.size,
54
+ "Expecting to see 2 brkpts in #{events}.inspect")
55
+ assert_equal(true, iseq.brkpt_dealloc)
56
+ end
57
+ end
58
+
59
+ # We want to double-check we didn't mess up any pointers somewhere.
60
+ at_exit { GC.start }
@@ -0,0 +1,17 @@
1
+ # Some simple tests of RubyVM::InstructionSequence#disasm, and
2
+ # #disasm_nochildren
3
+ require 'test/unit'
4
+
5
+ class TestDisasmClass < Test::Unit::TestCase
6
+
7
+ def test_basic
8
+ assert_equal(RubyVM::InstructionSequence.compile('1+2').disassemble,
9
+ RubyVM::InstructionSequence.compile('1+2').disasm)
10
+
11
+ p='def five; 5 end; five'
12
+ s1=RubyVM::InstructionSequence.compile(p).disasm
13
+ assert_equal String, s1.class, 'disasm output should be a string'
14
+ s2=RubyVM::InstructionSequence.compile(p).disasm_nochildren
15
+ assert_equal true, s1.size > s2.size
16
+ end
17
+ end
@@ -0,0 +1,50 @@
1
+ # See that setting ISEQS__ and SCRIPT_ISEQS__ saves
2
+ # RubyVM::Instruction_sequenses
3
+ require 'test/unit'
4
+
5
+ class TestIseqAccess < Test::Unit::TestCase
6
+ def setup
7
+ old_verbosity = $VERBOSE
8
+ $VERBOSE = nil
9
+ Kernel.const_set(:ISEQS__, {})
10
+ Kernel.const_set(:SCRIPT_ISEQS__, {})
11
+ $VERBOSE = old_verbosity
12
+ end
13
+
14
+ def teardown
15
+ old_verbosity = $VERBOSE
16
+ $VERBOSE = nil
17
+ Kernel.const_set(:ISEQS__, nil)
18
+ Kernel.const_set(:SCRIPT_ISEQS__, nil)
19
+ $VERBOSE = old_verbosity
20
+ end
21
+
22
+ def test_basic
23
+ sizes=[]
24
+ [ISEQS__, SCRIPT_ISEQS__].each do |iseq_hash|
25
+ sizes << iseq_hash.size
26
+ end
27
+ # defining five should trigger five instruction sequence additions
28
+ # to ISEQS__ and SCRIPT_ISEQS__
29
+ #
30
+ eval 'def five; 5 end'
31
+ assert_equal sizes[0], sizes[1]
32
+ [SCRIPT_ISEQS__, ISEQS__].each do |iseq_hash|
33
+ assert_equal true, iseq_hash.size > sizes.pop
34
+ assert_equal Hash, iseq_hash.class
35
+ a = iseq_hash.first
36
+ assert_equal Array, a.class
37
+ assert_equal RubyVM::InstructionSequence, iseq_hash.values[0][0].class
38
+ end
39
+ end
40
+
41
+ # Check RubyVM::InstructionSequence#arity
42
+ def test_arity
43
+ eval 'def five; 5 end'
44
+ eval 'def add(a,b); a+b end'
45
+ eval 'def splat(*a); 5 end'
46
+ [['five', 0,], ['add', 2], ['splat', -1]].each do |meth, expect|
47
+ assert_equal(expect, ISEQS__[meth][0].arity)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,145 @@
1
+ require 'test/unit'
2
+
3
+ # tests set_trace_func with event bitmasks, clear_trace_func,
4
+ # Newer changes
5
+ class TestSetTraceFuncAdds < Test::Unit::TestCase
6
+
7
+ # Some of the below setup is similar to what is in lib/trace_mod.rb of
8
+ # rb-trace
9
+ @@NO_EVENT_MASK = 0x0000
10
+ @@LINE_EVENT_MASK = 0x0001
11
+ @@CLASS_EVENT_MASK = 0x0002
12
+ @@END_EVENT_MASK = 0x0004
13
+ @@CALL_EVENT_MASK = 0x0008
14
+ @@RETURN_EVENT_MASK = 0x0010
15
+ @@C_CALL_EVENT_MASK = 0x0020
16
+ @@C_RETURN_EVENT_MASK = 0x0040
17
+ @@RAISE_EVENT_MASK = 0x0080
18
+ @@INSN_EVENT_MASK = 0x0100
19
+ @@ALL_EVENTS_MASK = (0xffff & ~@@INSN_EVENT_MASK)
20
+
21
+ @@EVENT2MASK = {
22
+ 'line' => @@LINE_EVENT_MASK,
23
+ 'call' => @@CALL_EVENT_MASK,
24
+ 'return' => @@RETURN_EVENT_MASK,
25
+ 'c-call' => @@C_CALL_EVENT_MASK,
26
+ 'c-return' => @@C_RETURN_EVENT_MASK,
27
+ 'c-raise' => @@RAISE_EVENT_MASK
28
+ }
29
+
30
+ # Convert +events+ into a Fixnum bitmask used internally by Ruby.
31
+ # Parameter +events+ should be Enumerable and each element should
32
+ # either be a Fixnum mask value or something that can be converted
33
+ # to a symbol. If the latter, the case is not important as we'll
34
+ # downcase the string representation.
35
+ def events2bitmask(event_list)
36
+ bitmask = @@NO_EVENT_MASK
37
+ event_list.each do |event|
38
+ bitmask |= @@EVENT2MASK[event]
39
+ end
40
+ return bitmask
41
+ end
42
+
43
+ def setup
44
+ @original_compile_option = RubyVM::InstructionSequence.compile_option
45
+ RubyVM::InstructionSequence.compile_option = {
46
+ :trace_instruction => true,
47
+ :specialized_instruction => false
48
+ }
49
+ @proc_template = 'Proc.new { |event, file, lineno, mid, binding, klass|
50
+ %s << [event, lineno, mid, klass]}'
51
+ end
52
+
53
+ def teardown
54
+ clear_trace_func
55
+ RubyVM::InstructionSequence.compile_option = @original_compile_option
56
+ end
57
+
58
+ def test_eventmask
59
+ returned_tuples =
60
+ [['line', 5, :test_eventmask, self.class],
61
+ ['class', 5, nil, nil],
62
+ ['end', 5, nil, nil],
63
+ ['line', 6, :test_eventmask, self.class],
64
+ ['call', 1, :five, self.class],
65
+ ['line', 1, :five, self.class],
66
+ ['return', 1, :five, self.class],
67
+ ['c-call', 6, :any?, Enumerable],
68
+ ['c-call', 6, :each, Array],
69
+ ['line', 6, :test_eventmask, self.class],
70
+ ['c-return', 6, :each, Array],
71
+ ['c-return', 6, :any?, Enumerable],
72
+ ['line', 7, :test_eventmask, self.class],
73
+ ['c-call', 7, :clear_trace_func, Kernel]]
74
+
75
+ [[], nil,
76
+ %w(line),
77
+ %w(call line),
78
+ %w(c-call c-return line),
79
+ ].each do |event_list|
80
+ tuples = []
81
+ event_mask = if event_list
82
+ events2bitmask(event_list)
83
+ else
84
+ @@ALL_EVENTS_MASK
85
+ end
86
+ cmd = <<-EOF.gsub(/^.*?: /, '')
87
+ 1: def five; 5 end
88
+ 2: p1 = #{@proc_template}
89
+ 3: set_trace_func(p1, #{event_mask})
90
+ 4: class Foo; end
91
+ 5: [1,2,five].any? {|n| n}
92
+ 6: clear_trace_func
93
+ EOF
94
+ eval(cmd % 'tuples')
95
+ expected = if event_list
96
+ returned_tuples.select{|x| !([x[0]] & event_list).empty?}
97
+ else
98
+ returned_tuples
99
+ end
100
+ assert_equal(expected, tuples,
101
+ "Error filtering #{event_list}")
102
+ # p tuples
103
+ end
104
+ end
105
+
106
+ def test_chained_hook
107
+ tuples1 = []
108
+ tuples2 = []
109
+ cmd = <<-EOF.gsub(/^.*?: /, '')
110
+ 1: def five; 5 end
111
+ 2: p1 = #{@proc_template}
112
+ 3: p2 = #{@proc_template}
113
+ 4: add_trace_func(p1, @@LINE_EVENT_MASK)
114
+ 5: add_trace_func(p2, @@CALL_EVENT_MASK)
115
+ 6: class Foo; end
116
+ 7: [1,2,five].any? {|n| n}
117
+ EOF
118
+ eval(cmd % %w(tuples1 tuples2))
119
+ clear_trace_func
120
+ assert_equal([
121
+ ["line", 7, :test_chained_hook, self.class],
122
+ ["line", 8, :test_chained_hook, self.class],
123
+ ["line", 9, :test_chained_hook, self.class],
124
+ ["line", 1, :five, self.class],
125
+ ["line", 9, :test_chained_hook, self.class],
126
+ ], tuples1[0..-2],
127
+ 'line filtering')
128
+ assert_equal([["call", 1, :five, self.class]], tuples2,
129
+ 'call filtering')
130
+ end
131
+
132
+ def test_trace_insn
133
+ tuples = []
134
+ cmd = <<-EOF.gsub(/^.*?: /, '')
135
+ 1: p = #{@proc_template}
136
+ 2: add_trace_func(p, @@INSN_EVENT_MASK)
137
+ 4: x = 1
138
+ 3: y = 2
139
+ EOF
140
+ eval cmd % 'tuples'
141
+ clear_trace_func
142
+ assert_equal true, !tuples.empty?, 'triggered instruction events'
143
+ assert_equal true, tuples.all?{|t| 'vm-insn' == t[0]}, 'instruction events'
144
+ end
145
+ end
@@ -0,0 +1,26 @@
1
+ require 'test/unit'
2
+
3
+ # tests that we a trace hook has access to the runtime exception Object
4
+ # when it is called through a raise event
5
+
6
+ class TestTracefuncRaise < Test::Unit::TestCase
7
+
8
+ def test_basic
9
+ tuples = []
10
+ p = Proc.new {
11
+ |event, file, lineno, mid, binding, klass|
12
+ tuples << klass
13
+ }
14
+ msg = 'this is a message'
15
+ set_trace_func(p, 0x0080)
16
+ begin ; x = 1/0; rescue; end
17
+ begin ; raise RuntimeError, msg; rescue; end
18
+ clear_trace_func
19
+ assert_equal(2, tuples.size,
20
+ "Wrong number of tuples captured #{tuples.inspect}")
21
+ assert_equal msg, tuples[1].message
22
+ assert_equal([ZeroDivisionError, RuntimeError], tuples.map{|t| t.class},
23
+ "Mismatched tuples classes in #{tuples.inspect}")
24
+
25
+ end
26
+ end
metadata CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 36
8
- version: "0.36"
7
+ - 37
8
+ version: "0.37"
9
9
  platform: ruby
10
10
  authors:
11
11
  - R. Bernstein
@@ -13,7 +13,7 @@ autorequire:
13
13
  bindir: bin
14
14
  cert_chain: []
15
15
 
16
- date: 2010-12-25 00:00:00 -05:00
16
+ date: 2011-02-01 00:00:00 -05:00
17
17
  default_executable:
18
18
  dependencies: []
19
19
 
@@ -33,42 +33,46 @@ files:
33
33
  - Makefile
34
34
  - LICENSE
35
35
  - NEWS
36
- - include/thread_pthread.h
37
36
  - include/node.h
38
- - include/method_mini.h
39
37
  - include/ruby19_externs.h
38
+ - include/method_mini.h
39
+ - include/thread_pthread.h
40
40
  - include/vm_core_mini.h
41
- - lib/iseq_extra.rb
42
41
  - lib/thread_frame.rb
42
+ - lib/iseq_extra.rb
43
43
  - ext/iseq_extra.c
44
44
  - ext/thread_frame.c
45
- - ext/proc_extra.c
46
45
  - ext/thread_extra.c
47
- - ext/thread_frame.h
48
- - ext/proc_extra.h
49
- - ext/thread_pthread.h
50
- - ext/node.h
46
+ - ext/proc_extra.c
51
47
  - ext/thread_extra.h
52
- - ext/iseq_extra.h
53
48
  - ext/iseq_mini.h
54
- - test/unit/test-trace.rb
49
+ - ext/iseq_extra.h
50
+ - ext/node.h
51
+ - ext/thread_pthread.h
52
+ - ext/proc_extra.h
53
+ - test/ruby/test_tracefunc_adds.rb
54
+ - test/ruby/test_brkpt.rb
55
+ - test/ruby/test_disasm.rb
56
+ - test/ruby/test_iseq.rb
57
+ - test/ruby/test_tracefunc_raise.rb
58
+ - test/unit/test-sp-size.rb
59
+ - test/unit/test-iseq-brkpt.rb
55
60
  - test/unit/test-iseq-save.rb
61
+ - test/unit/test-binding.rb
56
62
  - test/unit/test-prev.rb
57
- - test/unit/test-source.rb
58
63
  - test/unit/test-lib-iseq.rb
59
64
  - test/unit/test-return-stop.rb
60
- - test/unit/test-proc.rb
61
- - test/unit/test-invalid.rb
62
- - test/unit/test-argc.rb
65
+ - test/unit/test-iseq.rb
63
66
  - test/unit/cfunc-use.rb
64
- - test/unit/test-binding.rb
67
+ - test/unit/test-argc.rb
68
+ - test/unit/test-invalid.rb
65
69
  - test/unit/test-lib-iseq-extra.rb
66
- - test/unit/test-thread.rb
67
- - test/unit/test-iseq-brkpt.rb
68
- - test/unit/test-iseq.rb
69
70
  - test/unit/test-thread-trace-masks.rb
71
+ - test/unit/test-proc.rb
72
+ - test/unit/test-thread.rb
70
73
  - test/unit/test-settracefunc.rb
71
- - test/unit/test-sp-size.rb
74
+ - test/unit/test-trace.rb
75
+ - test/unit/test-source.rb
72
76
  - threadframe.rd
73
77
  - ext/extconf.rb
74
78
  has_rdoc: true
@@ -80,7 +84,7 @@ rdoc_options:
80
84
  - --main
81
85
  - README.md
82
86
  - --title
83
- - ThreadFrame 0.36 Documentation
87
+ - ThreadFrame 0.37 Documentation
84
88
  require_paths:
85
89
  - lib
86
90
  required_ruby_version: !ruby/object:Gem::Requirement
@@ -1,4 +0,0 @@
1
- VALUE thread_frame_sp(VALUE klass, VALUE index) ;
2
- VALUE thread_frame_prev(int argc, VALUE *argv, VALUE klass);
3
-
4
-