class RubyVM::InstructionSequence

Some additions to RubyVM::InstructionSequence

Constants

TYPE2STR

Turns a instruction sequence type field into a string name

Public Instance Methods

find_iseq_with_line(line) click to toggle source

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.

# File lib/iseq_extra.rb, line 123
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
format_args() click to toggle source

Returns a String containing a list of arguments for the RubyVM::InstructionSequence A semicolon separates required arguments from optional ones. For example: for

def evaluate(context, statements, file = __FILE__, line = __LINE__)

we return:

context, statements; file, line
# File lib/iseq_extra.rb, line 15
def format_args
  required_max = arity < 0 ? -arity-1 : arity
  args = 0.upto(required_max-1).map do |i| 
    local_name(i)
  end.join(', ')
  
  last = local_table_size-1
  if last >= required_max
    opt_args = required_max.upto(last).map do |i| 
      local_name(i)
    end.join(', ')
    args += '; ' + opt_args
  else
    args = '?'
  end
end
line2offsets(line_number) click to toggle source

Return An array of VM instruction byte offsets (Fixnums) for a given line_number.

# File lib/iseq_extra.rb, line 47
def line2offsets(line_number)
  offsetlines.select do |offset, lines| 
    lines.member?(line_number) 
  end.keys
end
lineoffsets() click to toggle source

Basically hash.invert but since each offset can represent many lines, we have to double loop. FIXME: Is there a more efficient way?

# File lib/iseq_extra.rb, line 34
def lineoffsets
  result = {}
  offsetlines.each do |offset, lines|
    lines.each do |line|
      result[line] ||= []
      result[line] << offset
    end
  end
  result
end
lines() click to toggle source
# File lib/iseq_extra.rb, line 114
def lines
  offsetlines.values.flatten.uniq
end
locate_line(line) click to toggle source

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
# File lib/iseq_extra.rb, line 71
def locate_line(line)
  offsetlines.each_pair do |offset, val|
    return offset if val.member?(line)
  end
  nil
end
locate_line_with_children(line) click to toggle source

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.
# File lib/iseq_extra.rb, line 88
def locate_line_with_children(line)
  iseq = self
  offset = iseq.locate_line(line)
  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
    current_iseq = iseq
    iseq = iseq.parent
    unless iseq
      # current_iseq is the top-most scope. Search down from here.
      top_iseq.child_iseqs.each do |child_iseq|
        next if child_iseq.equal? current_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
sha1() click to toggle source

Returns a cryptographic checksum (in particluar a SHA1) for the encoded bytes of the instruction sequence.

Example

proc{ 5 }.iseq.sha1 => 'b361a73f9efd7dc4d2c5e86d4e94d40b36141d42'
# File lib/iseq_extra.rb, line 59
def sha1
  Digest::SHA1.hexdigest(encoded)
end