rb-threadframe 0.33 → 0.34

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/Makefile CHANGED
@@ -3,7 +3,6 @@
3
3
  .PHONY: all test
4
4
 
5
5
  all: test
6
- rake $@
7
6
 
8
7
  check:
9
8
  rake test
data/NEWS CHANGED
@@ -1,5 +1,17 @@
1
- October 27 2010 (0.33)
2
- - Revise rvm install script to be more roboust
1
+ December 10, 2010 (0.34) Giant Madagascar Day Release
2
+
3
+ - 1.9.2 patches:
4
+ * Save source string eval types
5
+ * Add RubyVM::OS_ARGV and RubyVM::OS_STARTUP_DIR to allow Ruby
6
+ programs to reliably restart themselves via exec().
7
+ * Save instruction sequence compile options
8
+
9
+ - Add routines for finding instruction sequences and offsets:
10
+ iseq#lines() iseq#find_iseq_with_line(), and
11
+ seq#locate_line_with_children()
12
+
13
+ October 27, 2010 (0.33)
14
+ - Revise rvm install script to be more rooust
3
15
  - Change bug report location so we don't spam Ruby's redmine
4
16
  - Add RubyVM::InstructionSequence#parent and #local_iseq fields
5
17
 
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # rb-threadframe
2
2
 
3
- rb-threadframe gives introspection access for frames of a thread.
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.
4
5
 
5
6
  ## Requirements
6
7
 
data/ext/extconf.rb CHANGED
@@ -4,9 +4,11 @@ fail "You need to install a threadframe-patched Ruby.
4
4
  See http://github.com/rocky/rb-threadframe/wiki/How-to-Install" unless
5
5
  RbConfig::CONFIG.member?('rb-threadframe')
6
6
 
7
- config_file = File.join(File.dirname(__FILE__), 'config_options')
7
+ # Allow use customization of compile options. For example, the
8
+ # following lines could be put in config_options:
9
+ # CONFIG['optflags'] = '' # Or -O3
10
+ # CONFIG['debugflags'] = '-g3 -ggdb'
11
+ config_file = File.join(File.dirname(__FILE__), 'config_options.rb')
8
12
  load config_file if File.exist?(config_file)
9
13
 
10
- # Temporary: to turn off optimization
11
- # $CFLAGS='-fno-strict-aliasing -g -fPIC'
12
14
  create_makefile("thread_frame")
data/ext/iseq_extra.c CHANGED
@@ -10,8 +10,6 @@ VALUE rb_cIseq = rb_define_class_under(rb_cRubyVM, "InstructionSequence",
10
10
  #endif
11
11
 
12
12
  #include "../include/vm_core_mini.h" /* Pulls in ruby.h and node.h */
13
- #ifdef HAVE_COMPILE_OPTIONS
14
- #endif
15
13
  #include "iseq_mini.h" /* Pulls in ruby.h */
16
14
  #include "../include/ruby19_externs.h"
17
15
  #include <string.h> /* For strlen() */
@@ -22,7 +20,10 @@ struct iseq_insn_info_entry {
22
20
  unsigned short sp;
23
21
  };
24
22
 
25
- #ifdef HAVE_COMPILE_OPTIONS
23
+ #define COMPILE_OPTS_BOOL_SET_HASH(FIELD) \
24
+ rb_hash_aset(hash_opts, rb_str_new2(#FIELD), \
25
+ (compile_opts->FIELD) ? Qtrue : Qfalse)
26
+
26
27
  /*
27
28
  * Document-method: RubyVM::InstructionSequence::compile_options
28
29
  *
@@ -43,13 +44,17 @@ iseq_compile_options(VALUE iseqval)
43
44
  GetISeqPtr(iseqval, iseq);
44
45
  if (!iseq->compile_data) return Qnil;
45
46
  compile_opts = iseq->compile_data->option;
46
- rb_hash_aset(hash_opts, rb_str_new2("inline_const_cache"),
47
- (compile_opts->inline_const_cache) ? Qtrue : Qfalse);
47
+ COMPILE_OPTS_BOOL_SET_HASH(inline_const_cache);
48
+ COMPILE_OPTS_BOOL_SET_HASH(peephole_optimization);
49
+ COMPILE_OPTS_BOOL_SET_HASH(tailcall_optimization);
50
+ COMPILE_OPTS_BOOL_SET_HASH(specialized_instruction);
51
+ COMPILE_OPTS_BOOL_SET_HASH(operands_unification);
52
+ COMPILE_OPTS_BOOL_SET_HASH(stack_caching);
53
+ COMPILE_OPTS_BOOL_SET_HASH(trace_instruction);
54
+ COMPILE_OPTS_BOOL_SET_HASH(debug_level);
48
55
  return hash_opts;
49
56
  }
50
-
51
57
  }
52
- #endif
53
58
 
54
59
  /*
55
60
  * Document-method: RubyVM::InstructionSequence::encoded
@@ -410,9 +415,7 @@ Init_iseq_extra(void)
410
415
  rb_define_method(rb_cISeq, "arg_rest", iseq_arg_rest, 0) ;
411
416
  rb_define_method(rb_cISeq, "arg_simple", iseq_arg_simple, 0) ;
412
417
  rb_define_method(rb_cISeq, "argc", iseq_argc, 0) ;
413
- #ifdef HAVE_COMPILE_OPTIONS
414
418
  rb_define_method(rb_cISeq, "compile_options", iseq_compile_options, 0) ;
415
- #endif
416
419
  rb_define_method(rb_cISeq, "equal?", iseq_equal, 1) ;
417
420
  rb_define_method(rb_cISeq, "encoded", iseq_iseq_encoded, 0) ;
418
421
  rb_define_method(rb_cISeq, "iseq_size", iseq_iseq_size, 0) ;
data/ext/thread_frame.c CHANGED
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  /* What release we got? */
9
- #define THREADFRAME_VERSION "0.33"
9
+ #define THREADFRAME_VERSION "0.34"
10
10
 
11
11
  #include <string.h>
12
12
  #include "../include/vm_core_mini.h" /* Pulls in ruby.h and node.h */
data/lib/iseq_extra.rb CHANGED
@@ -60,6 +60,86 @@ class RubyVM::InstructionSequence
60
60
  Digest::SHA1.hexdigest(encoded)
61
61
  end
62
62
 
63
+
64
+ ##
65
+ # Locates the instruction address offset of the first instruction on
66
+ # the specified line or nil if no match for the specified line is
67
+ # found.
68
+ #
69
+ # @return [Fixnum, NilClass] returns
70
+ # nil if nothing is found, else the first offset for the line
71
+ def locate_line(line)
72
+ offsetlines.each_pair do |offset, val|
73
+ return offset if val.member?(line)
74
+ end
75
+ nil
76
+ end
77
+
78
+ # iseq and instruction address offset of the first instruction on
79
+ # the specified line. This method recursively examines child
80
+ # compiled methods until an exact match for the searched line is
81
+ # found. It returns both the matching CompiledMethod and the OFFSET
82
+ # of the first instruction on the requested line, or nil if no match
83
+ # for the specified line is found.
84
+ #
85
+ # @return [(RubyVM::InstructionSequence, Fixnum), NilClass] returns
86
+ # nil if nothing is found, else an array of size 2 containing the method
87
+ # the line was found in and the offset pointing there.
88
+ def locate_line_with_children(line)
89
+ iseq = self
90
+ offset = iseq.locate_line(line)
91
+ p ['++++1', offset, iseq]
92
+ return iseq, offset if offset
93
+
94
+ # Didn't find line in this iseq, so check if a contained
95
+ # InstructionSequence encompasses the line searched for
96
+ until offset
97
+ child_iseq = iseq
98
+ iseq = iseq.parent
99
+ unless iseq
100
+ # child_iseq is the top-most scope. Search down from here.
101
+ top_iseq = child_iseq
102
+ top_iseq.child_iseqs.each do |child_iseq|
103
+ p ['++++2', offset, child_iseq, child_iseq.parent]
104
+ next if child_iseq.equal? top_iseq
105
+ if res = child_iseq.locate_line_with_children(line)
106
+ return res
107
+ end
108
+ end
109
+ # No child method is a match - fail
110
+ return nil
111
+ end
112
+ offset = iseq.locate_line(line)
113
+ end
114
+ return parent_iseq, offset
115
+ end
116
+
117
+ def lines
118
+ offsetlines.values.flatten.uniq
119
+ end
120
+
121
+ # Returns an InstructionSequence for the specified line. We search the
122
+ # current method +meth+ and then up the parent scope. If we hit
123
+ # the top and we can't find +line+ that way, then we
124
+ # reverse the search from the top and search down. This will add
125
+ # all siblings of ancestors of +meth+.
126
+ def find_iseq_with_line(line)
127
+
128
+ lines = self.lines
129
+ iseq = self
130
+ until lines.member?(line) do
131
+ child_iseq = iseq
132
+ iseq = iseq.parent
133
+ unless iseq
134
+ # child is the top-most scope. Search down from here.
135
+ pair = child_iseq.locate_line_with_children(line)
136
+ ## pair = iseq.locate_line(line)
137
+ return pair ? pair[0] : nil
138
+ end
139
+ lines = iseq.lines
140
+ end
141
+ return iseq
142
+ end
63
143
  end
64
144
 
65
145
  if __FILE__ == $0
@@ -85,5 +165,21 @@ if __FILE__ == $0
85
165
  end
86
166
  end
87
167
  show_type
168
+ puts '-' * 40
169
+
170
+ line = __LINE__
171
+ def find_line(line) # :nodoc
172
+ tf = RubyVM::ThreadFrame.current
173
+ puts "find_line has lines: #{tf.iseq.lines}"
174
+ p tf.iseq.find_iseq_with_line(line)
175
+ end
176
+
177
+ tf = RubyVM::ThreadFrame.current
178
+ puts tf.iseq.disassemble
179
+ puts("offset %d above should be at line %d" %
180
+ [tf.iseq.locate_line(line), line])
181
+ find_line(line+2)
182
+ find_line(line)
183
+ p tf.iseq.find_iseq_with_line(line+2)
88
184
  end
89
185
 
@@ -0,0 +1,20 @@
1
+ require 'test/unit'
2
+ require_relative '../../ext/thread_frame'
3
+
4
+ class TestISeqSave < Test::Unit::TestCase
5
+
6
+ def test_ISEQS__
7
+ Object.const_set("ISEQS__", {})
8
+ eval "def five; 5 end"
9
+ iseq = Object.const_get('ISEQS__')['five'][0]
10
+ assert_equal RubyVM::InstructionSequence, iseq.class
11
+ assert_equal Hash, iseq.compile_options.class
12
+ old_verbose = $VERBOSE
13
+ $VERBOSE = nil
14
+ Object.const_set("ISEQS__", nil)
15
+ $VERBOSE = old_verbose
16
+ end
17
+ end
18
+
19
+ # We want to double-check we didn't mess up any pointers somewhere.
20
+ at_exit { GC.start }
@@ -0,0 +1,55 @@
1
+ require 'test/unit'
2
+ require_relative '../../ext/thread_frame'
3
+ require_relative '../../lib/thread_frame'
4
+
5
+ $global_test_line = __LINE__
6
+
7
+ class TestLibISeq < Test::Unit::TestCase
8
+
9
+ TEST_LINE = __LINE__
10
+
11
+ def test_sha1
12
+ iseq1 = RubyVM::ThreadFrame::current.iseq
13
+ iseq2 = RubyVM::ThreadFrame::current.iseq
14
+ assert_equal(iseq1.sha1, iseq2.sha1,
15
+ "SHA1 for same threadframe should match")
16
+ end
17
+
18
+ def test_lines
19
+ line = __LINE__
20
+ iseq = RubyVM::ThreadFrame::current.iseq
21
+ assert_equal((line-1..__LINE__+2).to_a, iseq.lines,
22
+ "lines of test_lines() don't match")
23
+ end
24
+
25
+ def test_locate_line
26
+ line = __LINE__
27
+ iseq = RubyVM::ThreadFrame::current.iseq
28
+ assert iseq.locate_line(line)
29
+ assert_nil iseq.locate_line(line - 2)
30
+ end
31
+
32
+ def test_iseq_with_line
33
+ # FIXME: We get a more stringent test if we test of offset.
34
+ # It is lame how little we can do here.
35
+ line = __LINE__
36
+ def find_line(line) # :nodoc
37
+ tf = RubyVM::ThreadFrame.current
38
+ assert(tf.iseq.find_iseq_with_line(line),
39
+ "should have found line #{line}")
40
+ end
41
+ tf = RubyVM::ThreadFrame.current
42
+ find_line(line+2)
43
+ # line2 = nil
44
+ # 1.times do
45
+ # line2 = __LINE__
46
+ # end
47
+ # find_line(line2)
48
+ # find_line(TEST_LINE)
49
+ # find_line($global_test_line)
50
+ end
51
+
52
+ end
53
+
54
+ # We want to double-check we didn't mess up any pointers somewhere.
55
+ at_exit { GC.start }
metadata CHANGED
@@ -4,8 +4,8 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 33
8
- version: "0.33"
7
+ - 34
8
+ version: "0.34"
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-10-27 00:00:00 -04:00
16
+ date: 2010-12-10 00:00:00 -05:00
17
17
  default_executable:
18
18
  dependencies: []
19
19
 
@@ -52,8 +52,10 @@ files:
52
52
  - ext/iseq_extra.h
53
53
  - ext/iseq_mini.h
54
54
  - test/unit/test-trace.rb
55
+ - test/unit/test-iseq-save.rb
55
56
  - test/unit/test-prev.rb
56
57
  - test/unit/test-source.rb
58
+ - test/unit/test-lib-iseq.rb
57
59
  - test/unit/test-return-stop.rb
58
60
  - test/unit/test-proc.rb
59
61
  - test/unit/test-invalid.rb
@@ -78,19 +80,19 @@ rdoc_options:
78
80
  - --main
79
81
  - README.md
80
82
  - --title
81
- - ThreadFrame 0.33 Documentation
83
+ - ThreadFrame 0.34 Documentation
82
84
  require_paths:
83
85
  - lib
84
86
  required_ruby_version: !ruby/object:Gem::Requirement
85
87
  none: false
86
88
  requirements:
87
- - - "="
89
+ - - ~>
88
90
  - !ruby/object:Gem::Version
89
91
  segments:
90
92
  - 1
91
93
  - 9
92
- - 2
93
- version: 1.9.2
94
+ - 2frame
95
+ version: 1.9.2frame
94
96
  required_rubygems_version: !ruby/object:Gem::Requirement
95
97
  none: false
96
98
  requirements: