rb-threadframe 0.38 → 0.39

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