rb-threadframe 0.38 → 0.39

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,3 +1,7 @@
1
+ Oct 27, 2011 (0.39)
2
+ - Revise patch for 1.9.2 revision 33354
3
+ - save return value in one more C_RETURN hook
4
+
1
5
  March 15, 2011 (0.38) Ron Frankel Release
2
6
  - Add RubyVM::ThreadFrame.prev (same as RubyVM::ThreadFrame.current.prev)
3
7
  - Allow access to a C method type
data/README.md CHANGED
@@ -5,6 +5,6 @@ that gives introspection access for method call frames.
5
5
 
6
6
  ## Requirements
7
7
 
8
- A patched version of Ruby 1.9.2 is needed.
8
+ A patched version of YARV Ruby 1.9.2 (and not any other version Ruby) of is needed.
9
9
 
10
10
  See the [wiki](http://github.com/rocky/rb-threadframe/wiki) for more information.
data/Rakefile CHANGED
@@ -4,13 +4,14 @@ require 'rubygems'
4
4
  require 'fileutils'
5
5
 
6
6
  ROOT_DIR = File.dirname(__FILE__)
7
+ Gemspec_filename='rb-threadframe.gemspec'
7
8
 
8
9
  require 'rbconfig'
9
10
  RUBY_PATH = File.join(RbConfig::CONFIG['bindir'],
10
11
  RbConfig::CONFIG['RUBY_INSTALL_NAME'])
11
12
 
12
13
  def gemspec
13
- @gemspec ||= eval(File.read('.gemspec'), binding, '.gemspec')
14
+ @gemspec ||= eval(File.read(Gemspec_filename), binding, Gemspec_filename)
14
15
  end
15
16
 
16
17
  require 'rake/gempackagetask'
@@ -18,7 +19,7 @@ desc "Build the gem"
18
19
  task :package=>:gem
19
20
  task :gem=>:gemspec do
20
21
  Dir.chdir(ROOT_DIR) do
21
- sh "gem build .gemspec"
22
+ sh "gem build #{Gemspec_filename}"
22
23
  FileUtils.mkdir_p 'pkg'
23
24
  FileUtils.mv("#{gemspec.file_name}", "pkg/")
24
25
  end
@@ -50,19 +51,20 @@ task :clean do
50
51
  end
51
52
  end
52
53
 
53
- def run_standalone_ruby_file(directory)
54
- puts ('*' * 10) + ' ' + directory + ' ' + ('*' * 10)
54
+ def run_standalone_ruby_file(directory, opts={})
55
+ puts(('*' * 10) + ' ' + directory + ' ' + ('*' * 10))
55
56
  Dir.chdir(directory) do
56
57
  Dir.glob('*.rb').each do |ruby_file|
57
- puts ('-' * 20) + ' ' + ruby_file + ' ' + ('-' * 20)
58
+ puts(('-' * 20) + ' ' + ruby_file + ' ' + ('-' * 20))
58
59
  system(RUBY_PATH, ruby_file)
60
+ break if $?.exitstatus != 0 && !opts[:continue]
59
61
  end
60
62
  end
61
63
  end
62
64
 
63
- desc "Create a GNU-style ChangeLog via git2cl"
65
+ desc 'Create a GNU-style ChangeLog via git2cl'
64
66
  task :ChangeLog do
65
- system("git log --pretty --numstat --summary | git2cl > ChangeLog")
67
+ system('git log --pretty --numstat --summary | git2cl > ChangeLog')
66
68
  end
67
69
 
68
70
  task :default => [:test]
@@ -109,8 +111,8 @@ end
109
111
 
110
112
  # --------- RDoc Documentation ------
111
113
  require 'rake/rdoctask'
112
- desc 'Generate rdoc documentation'
113
- Rake::RDocTask.new('rdoc') do |rdoc|
114
+ desc "Generate rdoc documentation"
115
+ Rake::RDocTask.new("rdoc") do |rdoc|
114
116
  rdoc.rdoc_dir = 'doc'
115
117
  rdoc.title = 'rb-threadframe'
116
118
  # Make the readme file the start page for the generated html
@@ -128,3 +130,10 @@ end
128
130
  task :clobber_rdoc do
129
131
  FileUtils.rm_rf File.join(ROOT_DIR, 'doc')
130
132
  end
133
+
134
+ task :rm_patch_residue do
135
+ FileUtils.rm_rf FileList['**/*.{rej,orig}'].to_a
136
+ end
137
+
138
+ desc "Remove built files"
139
+ task :clean => [:clobber_package, :clobber_rdoc, :rm_patch_residue]
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  /* What release we got? */
9
- #define THREADFRAME_VERSION "0.38"
9
+ #define THREADFRAME_VERSION "0.39"
10
10
 
11
11
  #include <string.h>
12
12
  #include "../include/vm_core_mini.h" /* Pulls in ruby.h and node.h */
@@ -339,10 +339,8 @@ thread_frame_sp_size_internal(thread_frame_t *tf)
339
339
  if (RUBY_VM_CONTROL_FRAME_STACK_OVERFLOW_P(tf->th, prev_cfp))
340
340
  return Qnil;
341
341
  ret_val = tf->cfp->sp - prev_cfp->sp - 1;
342
- /* FIXME: Why For C Functions we tack on 3? Possibly we're doing
343
- the previous frame and possibly that's where the action is that
344
- we should be looking at.? */
345
- if (RUBYVM_CFUNC_FRAME_P(tf->cfp)) ret_val += 3;
342
+ /* FIXME: Why For C Functions we tack on 2 for this RubyVM::ENV? */
343
+ if (RUBYVM_CFUNC_FRAME_P(tf->cfp)) ret_val += 2;
346
344
  return ret_val;
347
345
  }
348
346
 
@@ -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,151 @@
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
+ ["leave", 5, nil, nil],
64
+ ['line', 6, :test_eventmask, self.class],
65
+ ["send", 6, :test_eventmask, TestSetTraceFuncAdds],
66
+ ['call', 1, :five, self.class],
67
+ ['line', 1, :five, self.class],
68
+ ['return', 1, :five, self.class],
69
+ ["leave", 1, :five, TestSetTraceFuncAdds],
70
+ ["send", 6, :test_eventmask, TestSetTraceFuncAdds],
71
+ ['c-call', 6, :any?, Enumerable],
72
+ ['c-call', 6, :each, Array],
73
+ ['line', 6, :test_eventmask, self.class],
74
+ ["leave", 6, :test_eventmask, TestSetTraceFuncAdds],
75
+ ['c-return', 6, :each, Array],
76
+ ['c-return', 6, :any?, Enumerable],
77
+ ['line', 7, :test_eventmask, self.class],
78
+ ["send", 7, :test_eventmask, TestSetTraceFuncAdds],
79
+ ['c-call', 7, :clear_trace_func, Kernel]]
80
+
81
+ [[], nil,
82
+ %w(line),
83
+ %w(call line),
84
+ %w(c-call c-return line),
85
+ ].each do |event_list|
86
+ tuples = []
87
+ event_mask = if event_list
88
+ events2bitmask(event_list)
89
+ else
90
+ @@ALL_EVENTS_MASK
91
+ end
92
+ cmd = <<-EOF.gsub(/^.*?: /, '')
93
+ 1: def five; 5 end
94
+ 2: p1 = #{@proc_template}
95
+ 3: set_trace_func(p1, #{event_mask})
96
+ 4: class Foo; end
97
+ 5: [1,2,five].any? {|n| n}
98
+ 6: clear_trace_func
99
+ EOF
100
+ eval(cmd % 'tuples')
101
+ expected = if event_list
102
+ returned_tuples.select{|x| !([x[0]] & event_list).empty?}
103
+ else
104
+ returned_tuples
105
+ end
106
+ assert_equal(expected, tuples,
107
+ "Error filtering #{event_list}")
108
+ # p tuples
109
+ end
110
+ end
111
+
112
+ def test_chained_hook
113
+ tuples1 = []
114
+ tuples2 = []
115
+ cmd = <<-EOF.gsub(/^.*?: /, '')
116
+ 1: def five; 5 end
117
+ 2: p1 = #{@proc_template}
118
+ 3: p2 = #{@proc_template}
119
+ 4: add_trace_func(p1, @@LINE_EVENT_MASK)
120
+ 5: add_trace_func(p2, @@CALL_EVENT_MASK)
121
+ 6: class Foo; end
122
+ 7: [1,2,five].any? {|n| n}
123
+ EOF
124
+ eval(cmd % %w(tuples1 tuples2))
125
+ clear_trace_func
126
+ assert_equal([
127
+ ["line", 7, :test_chained_hook, self.class],
128
+ ["line", 8, :test_chained_hook, self.class],
129
+ ["line", 9, :test_chained_hook, self.class],
130
+ ["line", 1, :five, self.class],
131
+ ["line", 9, :test_chained_hook, self.class],
132
+ ], tuples1[0..-2],
133
+ 'line filtering')
134
+ assert_equal([["call", 1, :five, self.class]], tuples2,
135
+ 'call filtering')
136
+ end
137
+
138
+ def test_trace_insn
139
+ tuples = []
140
+ cmd = <<-EOF.gsub(/^.*?: /, '')
141
+ 1: p = #{@proc_template}
142
+ 2: add_trace_func(p, @@INSN_EVENT_MASK)
143
+ 4: x = 1
144
+ 3: y = 2
145
+ EOF
146
+ eval cmd % 'tuples'
147
+ clear_trace_func
148
+ assert_equal true, !tuples.empty?, 'triggered instruction events'
149
+ assert_equal true, tuples.all?{|t| 'vm-insn' == t[0]}, 'instruction events'
150
+ end
151
+ 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
- - 38
8
- version: "0.38"
7
+ - 39
8
+ version: "0.39"
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: 2011-03-15 00:00:00 -04:00
16
+ date: 2011-10-27 00:00:00 -04:00
17
17
  default_executable:
18
18
  dependencies: []
19
19
 
@@ -69,6 +69,11 @@ files:
69
69
  - test/unit/test-thread-trace-masks.rb
70
70
  - test/unit/test-settracefunc.rb
71
71
  - test/unit/test-sp-size.rb
72
+ - test/ruby/test_disasm.rb
73
+ - test/ruby/test_iseq.rb
74
+ - test/ruby/test_brkpt.rb
75
+ - test/ruby/test_tracefunc_adds.rb
76
+ - test/ruby/test_tracefunc_raise.rb
72
77
  - threadframe.rd
73
78
  - ext/extconf.rb
74
79
  has_rdoc: true
@@ -80,7 +85,7 @@ rdoc_options:
80
85
  - --main
81
86
  - README.md
82
87
  - --title
83
- - ThreadFrame 0.38 Documentation
88
+ - ThreadFrame 0.39 Documentation
84
89
  require_paths:
85
90
  - lib
86
91
  required_ruby_version: !ruby/object:Gem::Requirement