rb-threadframe 0.39 → 0.40

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,9 @@
1
+ Nov 25, 2012 (0.40)
2
+ - Redone for Ruby 1.9.3 p327
3
+ - RubyVM::ThreadFrame is now RubyVM::Frame. RubyVM::ThreadFrame is still
4
+ there for compatibility
5
+ - Some small administrative and bug fixes
6
+
1
7
  Oct 27, 2011 (0.39)
2
8
  - Revise patch for 1.9.2 revision 33354
3
9
  - save return value in one more C_RETURN hook
data/README.md CHANGED
@@ -1,10 +1,13 @@
1
1
  # rb-threadframe
2
2
 
3
- rb-threadframe is a set of patches to Ruby 1.9.2 and a C extension
4
- that gives introspection access for method call frames.
3
+ rb-threadframe is a set of patches to Ruby MRI 1.9.2 and 1.9.3 that
4
+ adds introspection of call frames and adds other run-time support for debuggers and run-time introspection.
5
+
6
+ For MRI 1.9.2, there are additional routines are in a C extension. For MRI 1.9.3, everthing is in a patched Ruby. Necessary patches and some simple patch code are found in this repository though.
5
7
 
6
8
  ## Requirements
7
9
 
8
- A patched version of YARV Ruby 1.9.2 (and not any other version Ruby) of is needed.
10
+ Source for Ruby MRI version 1.9.2 or 1.9.3 p327. Patches are provided
11
+ for these two versions only.
9
12
 
10
13
  See the [wiki](http://github.com/rocky/rb-threadframe/wiki) for more information.
data/Rakefile CHANGED
@@ -14,7 +14,7 @@ def gemspec
14
14
  @gemspec ||= eval(File.read(Gemspec_filename), binding, Gemspec_filename)
15
15
  end
16
16
 
17
- require 'rake/gempackagetask'
17
+ require 'rubygems/package_task'
18
18
  desc "Build the gem"
19
19
  task :package=>:gem
20
20
  task :gem=>:gemspec do
@@ -32,11 +32,11 @@ task :install => :gem do
32
32
  end
33
33
  end
34
34
 
35
- desc 'Create the core thread-frame shared library extension'
35
+ desc 'Create the thread-frame shared library extension'
36
36
  task :ext do
37
37
  Dir.chdir('ext') do
38
38
  system("#{Gem.ruby} extconf.rb && make")
39
- end
39
+ end if '1.9.2' == RUBY_VERSION
40
40
  end
41
41
 
42
42
  desc 'Remove built files'
@@ -110,7 +110,7 @@ task :gemspec do
110
110
  end
111
111
 
112
112
  # --------- RDoc Documentation ------
113
- require 'rake/rdoctask'
113
+ require 'rdoc/task'
114
114
  desc "Generate rdoc documentation"
115
115
  Rake::RDocTask.new("rdoc") do |rdoc|
116
116
  rdoc.rdoc_dir = 'doc'
@@ -0,0 +1,22 @@
1
+ /* Ruby 1.9.3 doesn't need a C extension while 1.9.2 does. I can't figure
2
+ out a way build a gem so that it loads the C extension conditionally.
3
+ So instead we have a simple stupid stub extension.
4
+
5
+ This as it is not elegant.
6
+ */
7
+
8
+ #include <ruby.h>
9
+ #include <ruby/version.h>
10
+ #include <string.h>
11
+ void
12
+ Init_thread_frame(void)
13
+ {
14
+ if (0 == strncmp("1.9.2", ruby_version, sizeof("1.9.2")))
15
+ {
16
+ rb_raise(rb_eLoadError,
17
+ "Gem installed under Ruby 1.9.3 but this Ruby 1.9.2. Please reinstall 'rb-threadframe' gem under 1.9.2.");
18
+ } else if (0 == strncmp("1.9.3", ruby_version, sizeof("1.9.3"))) {
19
+ rb_raise(rb_eLoadError,
20
+ "Under Ruby 1.9.3 there is no reason to load this thread_frame C extension.");
21
+ }
22
+ }
data/ext/extconf.rb CHANGED
@@ -1,4 +1,4 @@
1
- require "mkmf"
1
+ require 'mkmf'
2
2
 
3
3
  fail "You need to install a threadframe-patched Ruby.
4
4
  See http://github.com/rocky/rb-threadframe/wiki/How-to-Install" unless
@@ -11,4 +11,4 @@ See http://github.com/rocky/rb-threadframe/wiki/How-to-Install" unless
11
11
  config_file = File.join(File.dirname(__FILE__), 'config_options.rb')
12
12
  load config_file if File.exist?(config_file)
13
13
 
14
- create_makefile("thread_frame")
14
+ create_makefile("thread_frame", RUBY_VERSION)
data/ext/version.h ADDED
@@ -0,0 +1 @@
1
+ #define THREADFRAME_VERSION "0.40"
data/lib/iseq_extra.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'digest/sha1'
2
- require_relative '../ext/thread_frame'
2
+ require_relative '../ext/thread_frame' if '1.9.2' == RUBY_VERSION
3
3
  # Some additions to RubyVM::InstructionSequence
4
4
  class RubyVM::InstructionSequence
5
5
 
@@ -141,8 +141,9 @@ end
141
141
 
142
142
  if __FILE__ == $0
143
143
  # Demo it.
144
- iseq = RubyVM::ThreadFrame.current.iseq
145
- puts iseq.format_args
144
+ iseq = RubyVM::Frame.current.iseq
145
+ ## FIXME
146
+ ## puts iseq.format_args
146
147
  puts iseq.disassemble
147
148
  puts iseq.lineoffsets
148
149
  puts iseq.sha1
@@ -150,7 +151,7 @@ if __FILE__ == $0
150
151
  p iseq.line2offsets(__LINE__+100)
151
152
 
152
153
  def show_type # :nodoc:
153
- tf = RubyVM::ThreadFrame.current
154
+ tf = RubyVM::Frame.current
154
155
  while tf do
155
156
  is = tf.iseq
156
157
  if is
@@ -166,12 +167,12 @@ if __FILE__ == $0
166
167
 
167
168
  line = __LINE__
168
169
  def find_line(line) # :nodoc
169
- tf = RubyVM::ThreadFrame.current
170
+ tf = RubyVM::Frame.current
170
171
  puts "find_line has lines: #{tf.iseq.lines}"
171
172
  p tf.iseq.find_iseq_with_line(line)
172
173
  end
173
174
 
174
- tf = RubyVM::ThreadFrame.current
175
+ tf = RubyVM::Frame.current
175
176
  puts tf.iseq.disassemble
176
177
  puts("offset %d above should be at line %d" %
177
178
  [tf.iseq.locate_line(line), line])
data/lib/thread_frame.rb CHANGED
@@ -1,3 +1,11 @@
1
1
  # Boilerplate to pull shared object and helper routines.
2
- require_relative '../ext/thread_frame'
2
+ if RUBY_VERSION == '1.9.2'
3
+ require_relative '../ext/thread_frame'
4
+ end
3
5
  require_relative 'iseq_extra'
6
+
7
+ RubyVM::ThreadFrame = RubyVM::Frame
8
+ class Thread
9
+ # For compatibility with old stuff
10
+ alias tracing tracing?
11
+ end
@@ -2,7 +2,7 @@ def cfunc_loc
2
2
  ftype, file = [nil, nil]
3
3
  1.times do
4
4
  1.times do
5
- f = RubyVM::ThreadFrame::current.prev
5
+ f = RubyVM::Frame::current.prev
6
6
  ftype = f.type
7
7
  file = f.source_container[1]
8
8
  end
@@ -1,5 +1,6 @@
1
1
  require 'test/unit'
2
- require_relative '../../ext/thread_frame'
2
+
3
+ require_relative '../../ext/thread_frame' if '1.9.2' == RUBY_VERSION
3
4
 
4
5
  class TestARGC < Test::Unit::TestCase
5
6
 
@@ -23,7 +24,7 @@ class TestARGC < Test::Unit::TestCase
23
24
  all_events = []
24
25
  eval <<-EOF.gsub(/^.*?: /, "")
25
26
  1: set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
26
- 2: tf = RubyVM::ThreadFrame.prev
27
+ 2: tf = RubyVM::Frame.prev
27
28
  3: all_events << [tf.argc, tf.arity, tf.type, mid]
28
29
  4: if :basename == mid
29
30
  5: events << [tf.argc, tf.arity, tf.type, mid]
@@ -1,8 +1,8 @@
1
1
  require 'test/unit'
2
- require_relative '../../ext/thread_frame'
2
+ require_relative '../../ext/thread_frame' if '1.9.2' == RUBY_VERSION
3
3
 
4
4
  def outside(a)
5
- return eval('a', RubyVM::ThreadFrame.new(Thread::current).binding)
5
+ return eval('a', RubyVM::Frame.new(Thread::current).binding)
6
6
  end
7
7
 
8
8
  $a = 10
@@ -12,13 +12,13 @@ class TestBinding < Test::Unit::TestCase
12
12
  a = 1
13
13
  c = 0
14
14
  assert_equal(5, outside(5))
15
- tf = RubyVM::ThreadFrame.new(Thread::current)
15
+ tf = RubyVM::Frame.new(Thread::current)
16
16
  b = tf.binding
17
17
  assert_equal(1, eval('a', b))
18
18
  assert_equal(10, eval('$a', b))
19
19
  assert_equal(self, tf.self)
20
20
  1.times do |i;a|
21
- tf2 = Thread::current.threadframe()
21
+ tf2 = Thread::current.frame()
22
22
  b2 = tf2.binding
23
23
  a = 2
24
24
  assert_equal(2, eval('a', b2))
@@ -29,7 +29,7 @@ class TestBinding < Test::Unit::TestCase
29
29
  assert_equal(1, eval('a', tf2.prev(2).binding))
30
30
  end
31
31
  def inner(a)
32
- tf3 = Thread::current.threadframe()
32
+ tf3 = Thread::current.frame()
33
33
  b3 = tf3.binding
34
34
  if a == 4
35
35
  assert_equal(4, eval('a', b3))
@@ -1,17 +1,17 @@
1
1
  require 'test/unit'
2
- require_relative '../../ext/thread_frame'
2
+ require_relative '../../ext/thread_frame' if '1.9.2' == RUBY_VERSION
3
3
 
4
4
  class TestThread < Test::Unit::TestCase
5
5
  def test_basic
6
- assert_equal(RubyVM::ThreadFrame.new(Thread::current).thread,
7
- RubyVM::ThreadFrame::current.thread)
8
- assert_equal(RubyVM::ThreadFrame.new(Thread::current).thread,
6
+ assert_equal(RubyVM::Frame.new(Thread::current).thread,
7
+ RubyVM::Frame::current.thread)
8
+ assert_equal(RubyVM::Frame.new(Thread::current).thread,
9
9
  Thread::current)
10
- assert_equal(Thread::current.threadframe.thread, Thread::current)
10
+ assert_equal(Thread::current.frame.thread, Thread::current)
11
11
  end
12
12
 
13
13
  def test_pc_offset
14
- tf = RubyVM::ThreadFrame::current
14
+ tf = RubyVM::Frame::current
15
15
  offset_1 = tf.pc_offset
16
16
  assert_equal(true, offset_1 > 0,
17
17
  "Expecting a positive integer pc offset, got %s" % offset_1)
@@ -24,11 +24,10 @@ class TestThread < Test::Unit::TestCase
24
24
  end
25
25
 
26
26
  def test_sp
27
- tf = RubyVM::ThreadFrame::current.prev
27
+ tf = RubyVM::Frame.prev
28
28
  assert tf.sp(1)
29
29
  tf.sp_set(1, 5)
30
- assert_equal(5, tf.sp(1),
31
- 'chcking value of recently-set sp(1)')
30
+ assert_equal(5, tf.sp(1), 'checking value of recently-set sp(1)')
32
31
  end
33
32
 
34
33
  def test_source_container
@@ -38,7 +37,7 @@ class TestThread < Test::Unit::TestCase
38
37
  assert_equal(['CFUNC', cfunc_filebase], [type, File.basename(loc, '.rb')],
39
38
  'CFUNCs should get their file location from frame.prev*')
40
39
  cont = 'file'
41
- eval '1.times{cont = RubyVM::ThreadFrame.current.source_container[0]}'
40
+ eval '1.times{cont = RubyVM::Frame.current.source_container[0]}'
42
41
  assert_equal('string', cont,
43
42
  'source container[0] of an eval(...) should be "string"')
44
43
  end
@@ -51,8 +50,9 @@ class TestThread < Test::Unit::TestCase
51
50
  # because the location is reported on a traceback
52
51
  # and that probably can't happen at PC 0.
53
52
  def bug_when_zero_pc
53
+ skip "pc_offset= not implemented on 1.9.3" if '1.9.3' == RUBY_VERSION
54
54
  @not_first = true
55
- tf = RubyVM::ThreadFrame::current.prev
55
+ tf = RubyVM::Frame::current.prev
56
56
  pc_save = tf.pc_offset
57
57
  tf.pc_offset = 0
58
58
  loc = tf.source_location
@@ -65,23 +65,23 @@ class TestThread < Test::Unit::TestCase
65
65
 
66
66
 
67
67
  def test_thread_tracing
68
- assert_equal(false, Thread.current.tracing)
68
+ assert_equal(false, Thread.current.tracing?)
69
69
  Thread.current.tracing = true
70
- assert_equal(true, Thread.current.tracing)
70
+ assert_equal(true, Thread.current.tracing?)
71
71
  Thread.current.tracing = false
72
- assert_equal(false, Thread.current.tracing)
72
+ assert_equal(false, Thread.current.tracing?)
73
73
  end
74
74
 
75
75
  def test_thread_exec_event_tracing
76
- assert_equal(false, Thread.current.exec_event_tracing)
76
+ assert_equal(false, Thread.current.exec_event_tracing?)
77
77
  Thread.current.exec_event_tracing = true
78
- assert_equal(true, Thread.current.exec_event_tracing)
78
+ assert_equal(true, Thread.current.exec_event_tracing?)
79
79
  Thread.current.exec_event_tracing = false
80
- assert_equal(false, Thread.current.exec_event_tracing)
80
+ assert_equal(false, Thread.current.exec_event_tracing?)
81
81
  end
82
82
 
83
83
  def test_fields(notused=nil)
84
- tf = RubyVM::ThreadFrame::current
84
+ tf = RubyVM::Frame::current
85
85
  pc1 = tf.pc_offset
86
86
  assert(pc1 > 0, 'Should be able to get a valid PC offset')
87
87
  # pc_offset is dynamic - it changes constantly
@@ -91,12 +91,13 @@ class TestThread < Test::Unit::TestCase
91
91
  assert_equal(self, tf.self)
92
92
  assert_equal(0, tf.arity)
93
93
  assert_equal(0, tf.argc)
94
- assert tf.dfp(0)
95
- assert tf.lfp(0)
94
+ ## FIXME: Should we allow this?
95
+ ## assert tf.dfp(0)
96
+ ## assert tf.lfp(0)
96
97
 
97
- assert_raises IndexError do
98
- x = tf.lfp(tf.iseq.local_size+1)
99
- end
98
+ # assert_raises IndexError do
99
+ # x = tf.lfp(tf.iseq.local_size+1)
100
+ # end
100
101
 
101
102
 
102
103
  tf_prev = tf.prev
@@ -107,10 +108,10 @@ class TestThread < Test::Unit::TestCase
107
108
 
108
109
  # 1.times creates a C frame.
109
110
  1.times do
110
- tf = RubyVM::ThreadFrame::current
111
+ tf = RubyVM::Frame::current
111
112
  tup = tf.source_container
112
113
  tup[1] = File.basename(tup[1])
113
- assert_equal(['file', 'test-thread.rb'], tup)
114
+ assert_equal(['file', 'test-frame.rb'], tup)
114
115
  assert_equal('block in test_fields', tf.method)
115
116
  assert_equal('CFUNC', tf.prev.type)
116
117
  assert_equal('times', tf.prev.method)
@@ -124,24 +125,26 @@ class TestThread < Test::Unit::TestCase
124
125
 
125
126
  # 1.upto also creates a C frame.
126
127
  1.upto(1) do
127
- tf = RubyVM::ThreadFrame::current.prev
128
+ # We could use ".prev" below instead of '.current.prev", but we
129
+ # may as well test current.prev.
130
+ tf = RubyVM::Frame::current.prev
128
131
  assert_equal('CFUNC', tf.type)
129
132
  assert_equal(1, tf.arity, 'C arity should work nowadays' )
130
133
  assert_equal(1, tf.argc)
131
134
  end
132
135
 
133
136
  x = lambda do |x,y|
134
- frame = RubyVM::ThreadFrame::current
137
+ frame = RubyVM::Frame::current
135
138
  assert_equal('block in test_fields', frame.method)
136
139
  assert_equal('LAMBDA', frame.type)
137
140
  assert_equal(x, tf.self)
138
- assert_equal(2, frame.arity)
139
- assert_equal(2, frame.argc)
141
+ assert_equal(2, frame.arity)
142
+ assert_equal(2, frame.argc)
140
143
  end
141
144
  x.call(x,2)
142
145
 
143
146
  x = Proc.new do |x, y|
144
- frame = RubyVM::ThreadFrame::current
147
+ frame = RubyVM::Frame::current
145
148
  assert_equal('block in test_fields', frame.method)
146
149
  assert_equal(x, tf.self)
147
150
  assert_equal('BLOCK', frame.type)
@@ -150,9 +153,9 @@ class TestThread < Test::Unit::TestCase
150
153
 
151
154
  end
152
155
 
153
- def test_threadframe_equal
154
- tf = RubyVM::ThreadFrame.current
155
- tf2 = RubyVM::ThreadFrame.current
156
+ def test_frame_equal
157
+ tf = RubyVM::Frame.current
158
+ tf2 = RubyVM::Frame.current
156
159
  assert_equal(true, tf.equal?(tf))
157
160
  assert_equal(true, tf.equal?(tf2))
158
161
  tf2 = tf2.prev
@@ -1,17 +1,18 @@
1
1
  require 'test/unit'
2
- require_relative '../../ext/thread_frame'
3
2
 
4
- class TestProc < Test::Unit::TestCase
3
+ require_relative '../../ext/thread_frame' if '1.9.2' == RUBY_VERSION
4
+
5
+ class TestInvalid < Test::Unit::TestCase
5
6
  def test_basic
6
- @tf = RubyVM::ThreadFrame::current
7
+ @tf = RubyVM::Frame::current
7
8
  assert_equal(false, @tf.invalid?,
8
- 'Frame should be valid right after ThreadFrame::current')
9
+ 'Frame should be valid right after RubyVM::Frame::current')
9
10
  def notgood(test_tf=nil)
10
11
  # FIXME
11
12
  # if test_tf
12
13
  # assert_equal(test_tf != @tf, test_tf.invalid?)
13
14
  # end
14
- return RubyVM::ThreadFrame::current
15
+ return RubyVM::Frame::current
15
16
  end
16
17
 
17
18
  def inner_fn(tf)
@@ -1,10 +1,10 @@
1
1
  require 'test/unit'
2
- require_relative '../../ext/thread_frame'
2
+ require_relative '../../ext/thread_frame' if '1.9.2' == RUBY_VERSION
3
3
 
4
4
  class TestISeqBrkpt < Test::Unit::TestCase
5
5
 
6
6
  def test_iseq_brkpt
7
- iseq = RubyVM::ThreadFrame.current.iseq
7
+ iseq = RubyVM::Frame.current.iseq
8
8
  assert iseq
9
9
  assert_equal(nil, iseq.brkpts)
10
10
  assert_equal(true, iseq.brkpt_alloc)
@@ -41,14 +41,14 @@ class TestISeqBrkpt < Test::Unit::TestCase
41
41
  end
42
42
 
43
43
  def test_iseq_brkpt_set
44
- add_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
44
+ set_trace_func(Proc.new { |event, file, lineno, mid, binding, klass|
45
45
  if 'brkpt' == event
46
46
  $saw_brkpt = true
47
47
  end
48
48
  })
49
49
 
50
50
  $saw_brkpt = false
51
- tf = RubyVM::ThreadFrame.current
51
+ tf = RubyVM::Frame.current
52
52
  tf.iseq.offsetlines.keys.each do |offset|
53
53
  tf.iseq.brkpt_set(offset)
54
54
  end
@@ -1,5 +1,5 @@
1
1
  require 'test/unit'
2
- require_relative '../../ext/thread_frame'
2
+ require_relative '../../ext/thread_frame' if '1.9.2' == RUBY_VERSION
3
3
 
4
4
  class TestISeqSave < Test::Unit::TestCase
5
5