rb-threadframe 0.36 → 0.37

Sign up to get free protection for your applications and to get access to all the features.
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
-