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 +0 -1
- data/NEWS +14 -2
- data/README.md +2 -1
- data/ext/extconf.rb +5 -3
- data/ext/iseq_extra.c +12 -9
- data/ext/thread_frame.c +1 -1
- data/lib/iseq_extra.rb +96 -0
- data/test/unit/test-iseq-save.rb +20 -0
- data/test/unit/test-lib-iseq.rb +55 -0
- metadata +9 -7
data/Makefile
CHANGED
data/NEWS
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
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
|
-
|
|
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
|
-
#
|
|
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
|
-
|
|
47
|
-
|
|
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
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
|
-
-
|
|
8
|
-
version: "0.
|
|
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
|
|
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.
|
|
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
|
-
-
|
|
93
|
-
version: 1.9.
|
|
94
|
+
- 2frame
|
|
95
|
+
version: 1.9.2frame
|
|
94
96
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
97
|
none: false
|
|
96
98
|
requirements:
|