lib/iseq_extra.rb in rb-threadframe-0.33 vs lib/iseq_extra.rb in rb-threadframe-0.34
- old
+ new
@@ -58,10 +58,90 @@
# proc{ 5 }.iseq.sha1 => 'b361a73f9efd7dc4d2c5e86d4e94d40b36141d42'
def sha1
Digest::SHA1.hexdigest(encoded)
end
+
+ ##
+ # Locates the instruction address offset of the first instruction on
+ # the specified line or nil if no match for the specified line is
+ # found.
+ #
+ # @return [Fixnum, NilClass] returns
+ # nil if nothing is found, else the first offset for the line
+ def locate_line(line)
+ offsetlines.each_pair do |offset, val|
+ return offset if val.member?(line)
+ end
+ nil
+ end
+
+ # iseq and instruction address offset of the first instruction on
+ # the specified line. This method recursively examines child
+ # compiled methods until an exact match for the searched line is
+ # found. It returns both the matching CompiledMethod and the OFFSET
+ # of the first instruction on the requested line, or nil if no match
+ # for the specified line is found.
+ #
+ # @return [(RubyVM::InstructionSequence, Fixnum), NilClass] returns
+ # nil if nothing is found, else an array of size 2 containing the method
+ # the line was found in and the offset pointing there.
+ def locate_line_with_children(line)
+ iseq = self
+ offset = iseq.locate_line(line)
+ p ['++++1', offset, iseq]
+ return iseq, offset if offset
+
+ # Didn't find line in this iseq, so check if a contained
+ # InstructionSequence encompasses the line searched for
+ until offset
+ child_iseq = iseq
+ iseq = iseq.parent
+ unless iseq
+ # child_iseq is the top-most scope. Search down from here.
+ top_iseq = child_iseq
+ top_iseq.child_iseqs.each do |child_iseq|
+ p ['++++2', offset, child_iseq, child_iseq.parent]
+ next if child_iseq.equal? top_iseq
+ if res = child_iseq.locate_line_with_children(line)
+ return res
+ end
+ end
+ # No child method is a match - fail
+ return nil
+ end
+ offset = iseq.locate_line(line)
+ end
+ return parent_iseq, offset
+ end
+
+ def lines
+ offsetlines.values.flatten.uniq
+ end
+
+ # Returns an InstructionSequence for the specified line. We search the
+ # current method +meth+ and then up the parent scope. If we hit
+ # the top and we can't find +line+ that way, then we
+ # reverse the search from the top and search down. This will add
+ # all siblings of ancestors of +meth+.
+ def find_iseq_with_line(line)
+
+ lines = self.lines
+ iseq = self
+ until lines.member?(line) do
+ child_iseq = iseq
+ iseq = iseq.parent
+ unless iseq
+ # child is the top-most scope. Search down from here.
+ pair = child_iseq.locate_line_with_children(line)
+ ## pair = iseq.locate_line(line)
+ return pair ? pair[0] : nil
+ end
+ lines = iseq.lines
+ end
+ return iseq
+ end
end
if __FILE__ == $0
# Demo it.
iseq = RubyVM::ThreadFrame.current.iseq
@@ -83,7 +163,23 @@
end
tf = tf.prev
end
end
show_type
+ puts '-' * 40
+
+ line = __LINE__
+ def find_line(line) # :nodoc
+ tf = RubyVM::ThreadFrame.current
+ puts "find_line has lines: #{tf.iseq.lines}"
+ p tf.iseq.find_iseq_with_line(line)
+ end
+
+ tf = RubyVM::ThreadFrame.current
+ puts tf.iseq.disassemble
+ puts("offset %d above should be at line %d" %
+ [tf.iseq.locate_line(line), line])
+ find_line(line+2)
+ find_line(line)
+ p tf.iseq.find_iseq_with_line(line+2)
end