1 require 'kernel/core/iseq' unless defined? RUBY_ENGINE and RUBY_ENGINE == 'rbx'
\r
4 # Like String#unpack('N'), but returns a Fixnum, rather than an array containing a string
\r
6 def unpack_int(endian = ?b)
\r
8 # Int is encoded big-endian
\r
9 i = (self[3] | (self[2] << 8) | (self[1] << 16) | (self[0] << 24))
\r
11 # Int is encoded little-endian
\r
12 i = (self[0] | (self[1] << 8) | (self[2] << 16) | (self[3] << 24))
\r
20 class MarshalEmitter
\r
21 def initialize(ver, str, start=0)
\r
25 @decoder = InstructionSequence::Encoder.new
\r
28 attr_reader :rbc_version
\r
40 ?I => :instructions,
\r
49 NoBody = [:nil, :true, :false]
\r
51 def self.process_rbc(file)
\r
52 # Binary mode needs to be specified on Win
\r
54 File.open(file, 'rb') do |f|
\r
57 raise "Not a Rubinius compiled file" unless 'RBIX' == str[0..3]
\r
58 ver = str[4..7].unpack_int
\r
60 return new(ver, str, 28)
\r
64 tag = @string[@index]
\r
67 name = TagNames[tag]
\r
68 raise "Unrecognised tag '" << (tag || '\0') << "' at #{@index} (#{sprintf('%#x', @index)})" unless name
\r
70 if NoBody.include? name
\r
73 body = __send__ "process_#{name}"
\r
83 body = @string[@index, 5]
\r
86 int = body[1..-1].unpack_int
\r
94 sz = @string[@index,4].unpack_int
\r
96 body = @string[@index, sz]
\r
102 body = process_string
\r
103 @index += 1 # Discard trailing \0
\r
107 alias :process_float :process_num
\r
108 alias :process_bignum :process_num
\r
109 alias :process_symbol :process_string
\r
110 alias :process_bytes :process_string
\r
111 alias :process_send_site :process_string
\r
114 sz = @string[@index,4].unpack_int
\r
124 alias :process_method :process_tuple
\r
125 alias :process_object :process_tuple
\r
127 # Support for version 2 of compiled method, which replaces size with a version number
\r
128 def process_method2
\r
129 ver = @string[@index,4].unpack_int
\r
132 sz = 16 if 1 == ver
\r
133 raise "Unsupported version (#{ver}) of CompiledMethod" unless sz
\r
142 def process_instructions
\r
143 endian = @string[@index]
\r
145 body = process_string()
\r
146 body = @decoder.decode_iseq(body)
\r
147 body.map! {|i| [i.first.opcode].concat i[1..-1]}
\r
152 # If file is run, dump content of .rbc to STDOUT
\r
156 while rbc = ARGV.shift
\r
157 emit = MarshalEmitter.process_rbc(rbc)
\r
158 STDOUT.puts "\nContent of #{rbc}:"
\r
162 STDOUT.puts "Usage: #{__FILE__} <rbc_file> [<rbc_file> ...]"
\r