rb-threadframe 0.39 → 0.40

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