rb-threadframe 0.33 → 0.34
Sign up to get free protection for your applications and to get access to all the features.
- 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:
|