C0 code coverage information
Generated on Wed Aug 01 14:04:28 -0300 2007 with rcov 0.8.0
Code reported as executed by Ruby looks like this...
and this: this line is also marked as covered.
Lines considered as run by rcov, but not reported by Ruby, look like this,
and this: these lines were inferred by rcov (using simple heuristics).
Finally, here's a line marked as not executed.
1 module YAJD
2
3 module Visitor
4
5 module Javap
6
7 class CodeInfoVisitor < Visitor::Base
8 @@opcodes = nil
9
10 def accept(visitor)
def accept(visitor)
248 lib/visitor/javap/method_info.rb:58 in 'YAJD::Visitor::Javap::MethodInfoVisitor#dump_attributes'
11 result = []
12
13 dump_code(result)
dump_code(result)
248 YAJD::Visitor::Javap::CodeInfoVisitor#dump_code at lib/visitor/javap/code_info.rb:323
14 dump_exception_table(result)
dump_exception_table(result)
248 YAJD::Visitor::Javap::CodeInfoVisitor#dump_exception_table at lib/visitor/javap/code_info.rb:302
15 dump_line_numbers(result)
dump_line_numbers(result)
248 YAJD::Visitor::Javap::CodeInfoVisitor#dump_line_numbers at lib/visitor/javap/code_info.rb:291
16
17 result
18 end
19
20 protected
21 INVOKE_SPECIAL = 183
22 IFNONNULL = 199
23 NEW = 187
24 LDC = 18
25 ANEWARRAY = 189
26 BIPUSH = 16
27 GETSTATIC = 178
28 INVOKEVIRTUAL = 182
29 NEWARRAY = 188
30 GETFIELD = 180
31 PUTFIELD = 181
32 IFEQ = 153
33 IFNE = 154
34 IFLT = 155
35 IFGE = 156
36 IFGT = 157
37 IFLE = 158
38 GOTO = 167
39 CHECKCAST = 192
40 INSTANCEOF = 193
41 IF_ICMPEQ = 159
42 IF_ICMPNE = 160
43 IF_ICMPLT = 161
44 IF_ICMPGE = 162
45 IF_ICMPGT = 163
46 IF_ICMPLE = 164
47 INVOKESTATIC = 184
48 LDC_W = 19
49 PUTSTATIC = 179
50 IF_ACMPEQ = 165
51 IF_ACMPNE = 166
52 IFNULL = 198
53 ALOAD = 25
54 IINC = 132
55 ASTORE = 58
56 INVOKEINTERFACE = 185
57 NOP = 0
58 ILOAD = 21
59 ISTORE = 54
60 SIPUSH = 17
61 TABLE_SWITCH = 0xAA
62 LDC2_W = 20
63 LSTORE = 55
64 LLOAD = 22
65 DLOAD = 24
66 DSTORE = 57
67 FLOAD = 23
68 FSTORE = 56
69 LOOKUP_SWITCH = 0xAB
70 # TODO this method will replace @@opcodes. change the name after is finished.
71 #TODO this method is a huge chunk of code, refactor.
72 def refactor_me(pc, opcode)
def refactor_me(pc, opcode)
4130 lib/visitor/javap/code_info.rb:341 in 'YAJD::Visitor::Javap::CodeInfoVisitor#dump_code'
73 pc += 1
74 case opcode
75 when INVOKEINTERFACE
76 method_index, method = object_ref(pc)
method_index, method = object_ref(pc)
184 YAJD::Visitor::Javap::CodeInfoVisitor#object_ref at lib/visitor/javap/code_info.rb:235
77 count = @object.code[pc + 2]
78 method_name = method.name_and_type.name.bytes
method_name = method.name_and_type.name.bytes
184 YAJD::ConstantPool::CommonAttrs#name_and_type at (eval):2
184 YAJD::ConstantPool::CNameType#name at (eval):2
79 #TODO the check should be using eql? or something similar.. 'same_class?'
80 unless method.class_index == @object.parent.klass.this_class
81 method_sig = "#{method.klass.full_name}."
method_sig = "#{method.klass.full_name}."
184 YAJD::ConstantPool::CommonAttrs#klass at (eval):2
184 YAJD::ConstantPool::CClass#full_name at lib/constant_pool/cpinfo.rb:93
82 else
83 method_sig = ''
84 end
85 method_sig += "#{method_name}:#{method.name_and_type.descriptor.bytes}"
method_sig += "#{method_name}:#{method.name_and_type.descriptor.bytes}"
184 YAJD::ConstantPool::CommonAttrs#name_and_type at (eval):2
184 YAJD::ConstantPool::CNameType#descriptor at (eval):2
86
87 #TODO check what happens when count > 9 and if it's necessary to do a sprintf "%2d". If this needs to be done, then it must be checked all other output
88 [ pc + 3, "\t##{method_index}, #{count}; //InterfaceMethod " + method_sig ]
89 when INVOKE_SPECIAL, INVOKEVIRTUAL, INVOKESTATIC
90 method_index, method = object_ref(pc)
method_index, method = object_ref(pc)
741 YAJD::Visitor::Javap::CodeInfoVisitor#object_ref at lib/visitor/javap/code_info.rb:235
91 method_name = method.name_and_type.name.bytes
method_name = method.name_and_type.name.bytes
741 YAJD::ConstantPool::CommonAttrs#name_and_type at (eval):2
741 YAJD::ConstantPool::CNameType#name at (eval):2
92 if opcode == INVOKE_SPECIAL && Util::Java.is_init?(method_name)
if opcode == INVOKE_SPECIAL && Util::Java.is_init?(method_name)
164 #<Class:YAJD::Util::Java>#is_init? at lib/utils.rb:50
93 method_name = "\"#{method_name}\""
94 end
95 unless method.class_index == @object.parent.klass.this_class
96 method_sig = "#{method.klass.full_name}."
method_sig = "#{method.klass.full_name}."
376 YAJD::ConstantPool::CommonAttrs#klass at (eval):2
376 YAJD::ConstantPool::CClass#full_name at lib/constant_pool/cpinfo.rb:93
97 else
98 method_sig = ''
99 end
100 method_sig += "#{method_name}:#{method.name_and_type.descriptor.bytes}"
method_sig += "#{method_name}:#{method.name_and_type.descriptor.bytes}"
741 YAJD::ConstantPool::CommonAttrs#name_and_type at (eval):2
741 YAJD::ConstantPool::CNameType#descriptor at (eval):2
101
102 [ pc + 2, "\t##{method_index}; //Method " + method_sig ]
103 when NEW
104 klass_index, klass = object_ref(pc)
klass_index, klass = object_ref(pc)
87 YAJD::Visitor::Javap::CodeInfoVisitor#object_ref at lib/visitor/javap/code_info.rb:235
105 [ pc + 2, "\t\##{klass_index}; //class #{klass.full_name}" ]
[ pc + 2, "\t\##{klass_index}; //class #{klass.full_name}" ]
87 YAJD::ConstantPool::CClass#full_name at lib/constant_pool/cpinfo.rb:93
106 when LDC
107 index = @object.code[pc]
108 obj = @object.pool.at(index)
obj = @object.pool.at(index)
48 YAJD::ConstantPool::Pool#at at lib/constant_pool.rb:42
109 what = {
110 ConstantPool::CString => 'String',
111 ConstantPool::CInteger => 'int',
112 ConstantPool::CFloat => 'float',
113 }
114 value = obj.value
value = obj.value
48 YAJD::ConstantPool::CString#value at lib/constant_pool/strings.rb:28
115 if obj.is_a?(ConstantPool::CString)
116 value = Util::Java::quote(obj.value)
value = Util::Java::quote(obj.value)
48 YAJD::ConstantPool::CString#value at lib/constant_pool/strings.rb:28
48 #<Class:YAJD::Util::Java>#quote at lib/utils.rb:34
117 end
118 [ pc + 1, "\t\##{index}; //#{what[obj.class]} #{value}" ]
119 when LDC_W, LDC2_W
120 index = YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])
index = YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])
29 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
121 obj = @object.pool.at(index)
obj = @object.pool.at(index)
29 YAJD::ConstantPool::Pool#at at lib/constant_pool.rb:42
122 if opcode == LDC_W
123 if obj.is_a?(YAJD::ConstantPool::CString)
124 what = 'String'
125 value = Util::Java::quote(obj.value)
value = Util::Java::quote(obj.value)
29 YAJD::ConstantPool::CString#value at lib/constant_pool/strings.rb:28
29 #<Class:YAJD::Util::Java>#quote at lib/utils.rb:34
126 #TODO I think the use of ldc_w for classes was added in 5.0. check that.
127 elsif obj.is_a?(YAJD::ConstantPool::CClass)
128 what = 'class'
129 value = obj.full_name
130 value = "\"#{value}\"" if YAJD::Util::Java::is_array?(value)
131 else
132 what = '?'
133 value = obj.value
134 end
135 elsif opcode == LDC2_W
136 value = obj.value
137 if obj.is_a?(YAJD::ConstantPool::CLong)
138 what = 'long'
139 else
140 what = 'double'
141 end
142 value = "#{value}#{what[0].chr}"
143 end
144
145 [ pc + 2, "\t\##{index}; //#{what} #{value}" ]
146 when ANEWARRAY, CHECKCAST, INSTANCEOF
147 index, obj = object_ref(pc)
index, obj = object_ref(pc)
36 YAJD::Visitor::Javap::CodeInfoVisitor#object_ref at lib/visitor/javap/code_info.rb:235
148 name = obj.full_name
name = obj.full_name
36 YAJD::ConstantPool::CClass#full_name at lib/constant_pool/cpinfo.rb:93
149 name = "\"#{name}\"" if Util::Java.is_array?(name)
name = "\"#{name}\"" if Util::Java.is_array?(name)
36 #<Class:YAJD::Util::Java>#is_array? at lib/utils.rb:55
150 [ pc + 2, "\t\##{index}; //class #{name}" ]
151 when BIPUSH
152 value = YAJD::Util::SignedNum.to_little_endian_byte(@object.code[pc])
value = YAJD::Util::SignedNum.to_little_endian_byte(@object.code[pc])
18 #<Class:YAJD::Util::SignedNum>#to_little_endian_byte at lib/utils.rb:10
153 [ pc + 1, "\t#{value}" ]
154 when GETSTATIC, GETFIELD, PUTFIELD, PUTSTATIC
155 field_index, field = object_ref(pc)
field_index, field = object_ref(pc)
345 YAJD::Visitor::Javap::CodeInfoVisitor#object_ref at lib/visitor/javap/code_info.rb:235
156 unless field.klass.eql?(@object.parent.parent)
unless field.klass.eql?(@object.parent.parent)
345 YAJD::ConstantPool::CommonAttrs#klass at (eval):2
345 YAJD::ConstantPool::CClass#eql? at lib/constant_pool/cpinfo.rb:117
345 YAJD::CommonInfo#parent at (eval):2
157 suffix = "#{field.klass.full_name}."
suffix = "#{field.klass.full_name}."
22 YAJD::ConstantPool::CommonAttrs#klass at (eval):2
22 YAJD::ConstantPool::CClass#full_name at lib/constant_pool/cpinfo.rb:93
158 end
159 [ pc + 2, "\t\##{field_index}; //Field #{suffix}#{field.name_and_type.name.bytes}:#{field.name_and_type.descriptor.bytes}" ]
[ pc + 2, "\t\##{field_index}; //Field #{suffix}#{field.name_and_type.name.bytes}:#{field.name_and_type.descriptor.bytes}" ]
690 YAJD::ConstantPool::CommonAttrs#name_and_type at (eval):2
345 YAJD::ConstantPool::CNameType#name at (eval):2
345 YAJD::ConstantPool::CNameType#descriptor at (eval):2
160 when NEWARRAY
161 array_type = @object.code[pc]
162 #TODO check if this is needed somewhere else
163 a_type = {
164 4 => 'boolean',
165 5 => 'char',
166 6 => 'float',
167 7 => 'double',
168 8 => 'byte',
169 9 => 'short',
170 10 => 'int',
171 11 => 'long'
172 }
173 [ pc + 1, " #{a_type[array_type.to_i]}" ]
174 when IFEQ, IFNE, IFLT, IFGE, IFGT, IFLE, GOTO, IF_ICMPEQ, IF_ICMPNE, IF_ICMPLT, IF_ICMPGE, IF_ICMPGT, IF_ICMPLE, IFNONNULL, IF_ACMPEQ, IF_ACMPNE, IFNULL
175 [ pc + 2, "\t#{pc - 1 + YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])}" ]
[ pc + 2, "\t#{pc - 1 + YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])}" ]
217 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
176 when ASTORE, ALOAD, LSTORE, LLOAD, DSTORE, DLOAD, FLOAD, FSTORE
177 [ pc + 1, "\t#{@object.code[pc]}" ]
178 when IINC
179 [ pc + 2, "\t#{@object.code[pc]}, #{YAJD::Util::SignedNum.to_little_endian_byte(@object.code[pc + 1])}" ]
[ pc + 2, "\t#{@object.code[pc]}, #{YAJD::Util::SignedNum.to_little_endian_byte(@object.code[pc + 1])}" ]
26 #<Class:YAJD::Util::SignedNum>#to_little_endian_byte at lib/utils.rb:10
180 #TODO add and option to output nops?
181 when NOP
182 pc
183 when ISTORE, ILOAD
184 [ pc + 1, "\t#{@object.code[pc]}" ]
185 when SIPUSH
186 [ pc + 2, "\t#{YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])}" ]
[ pc + 2, "\t#{YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])}" ]
10 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
187 when TABLE_SWITCH
188 pc -= 1
189 new_pc = pc + 4 - (pc % 4)
190 default = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc, 4])
default = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc, 4])
1 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
191 low = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc+4, 4])
low = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc+4, 4])
1 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
192 high = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc+8, 4])
high = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc+8, 4])
1 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
193
194 if low > high
195 raise "low (#{low}) must be less than or equal to high (#{high})"
196 end
197
198 new_pc += 12
199
200 aux = [ "{ //#{low} to #{high}" ]
201 (low..high).each do |i|
202 offset = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc + (i-low)*4, 4])
offset = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc + (i-low)*4, 4])
3 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
203 aux << "\t\t#{i}: #{offset + pc};"
204 end
205 aux << "\t\tdefault: #{default + pc} }"
206
207 new_pc += (high - low + 1) * 4
208 [ new_pc, aux.join("\n") ]
209 when LOOKUP_SWITCH
210 pc -= 1
211 new_pc = pc + 4 - (pc % 4)
212 default = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc, 4])
213 npairs = YAJD::Util::SignedNum.to_little_endian(@object.code[new_pc+4, 4])
214
215 if npairs < 0
216 raise "npairs (#{npairs}) must be greater than or equal to 0"
217 end
218
219 new_pc += 8
220
221 aux = [ "{ //#{npairs}" ]
222 npairs.times do |i|
223 idx = new_pc + i * 8
224 match = YAJD::Util::SignedNum.to_little_endian(@object.code[idx, 4])
225 offset = YAJD::Util::SignedNum.to_little_endian(@object.code[idx + 4, 4])
226 aux << "\t\t#{match}: #{offset + pc};"
227 end
228 aux << "\t\tdefault: #{default + pc } }"
229 return [ new_pc + npairs * 8, aux.join("\n") ]
230 else
231 nil
232 end
233 end
234
235 def object_ref(pc)
def object_ref(pc)
741 lib/visitor/javap/code_info.rb:90 in 'YAJD::Visitor::Javap::CodeInfoVisitor#refactor_me'
345 lib/visitor/javap/code_info.rb:155 in 'YAJD::Visitor::Javap::CodeInfoVisitor#refactor_me'
184 lib/visitor/javap/code_info.rb:76 in 'YAJD::Visitor::Javap::CodeInfoVisitor#refactor_me'
87 lib/visitor/javap/code_info.rb:104 in 'YAJD::Visitor::Javap::CodeInfoVisitor#refactor_me'
36 lib/visitor/javap/code_info.rb:147 in 'YAJD::Visitor::Javap::CodeInfoVisitor#refactor_me'
236 index = YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])
index = YAJD::Util::SignedNum.to_little_endian(@object.code[pc, 2])
1393 #<Class:YAJD::Util::SignedNum>#to_little_endian at lib/utils.rb:16
237 value = @object.pool.at(index)
value = @object.pool.at(index)
1393 YAJD::ConstantPool::Pool#at at lib/constant_pool.rb:42
238
239 [index, value]
240 end
241
242 def self.load_opcodes
def self.load_opcodes
1 lib/visitor/javap/code_info.rb:265 in '#'
243 return unless @@opcodes.nil?
244
245 #TODO find an easier way
246 filename = nil
247 $LOAD_PATH.each { |d|
248 filename = "#{d}/opcodes" if File.exist?("#{d}/opcodes")
249 }
250 raise "couldn't find opcodes file" if filename.nil?
251 opcodes = {}
252 File.open(filename).each_line { |line|
253 opcode, skip, name = line.split(/\s+/)
254
255 opcode = opcode.to_i
256
257 raise "dup opcode 0x#{opcode.to_s(16)}" unless opcodes[opcode].nil?
258 skip = skip.to_i unless skip == 'nil'
259 opcodes[opcode] = { :name => name, :skip => skip }
260 }
261
262 @@opcodes = opcodes
263 end
264
265 load_opcodes
load_opcodes
1 #<Class:YAJD::Visitor::Javap::CodeInfoVisitor>#load_opcodes at lib/visitor/javap/code_info.rb:242
266
267 #TODO these are repeated in the opcodes file
268 WIDE = 0xC4
269 RET = 169
270
271 def handle_special_case(pc, opcode)
def handle_special_case(pc, opcode)
2063 lib/visitor/javap/code_info.rb:352 in 'YAJD::Visitor::Javap::CodeInfoVisitor#dump_code'
272 case opcode
273 when WIDE
274 handle_wide(pc)
275 end
276 end
277
278 def handle_wide(pc)
279 opcode = @object.code[pc+1]
280 #TODO check opcode is valid ([ifald]load, [ifald]store, ret, iinc)
281 case opcode
282 when RET
283 skip = 2
284 else
285 raise "invalid opcode (#{opcode}) at wide instruction"
286 end
287
288 pc + 2 + skip
289 end
290
291 def dump_line_numbers(result)
def dump_line_numbers(result)
248 lib/visitor/javap/code_info.rb:15 in 'YAJD::Visitor::Javap::CodeInfoVisitor#accept'
292 table = @object.line_number_table
table = @object.line_number_table
248 YAJD::Attributes::CodeInfo#line_number_table at lib/attributes/code.rb:28
293 unless table.nil?
294 result << ' LineNumberTable: '
295 table.line_number_table.each do |line|
296 result << " line #{line[:line_number]}: #{line[:start_pc]}"
297 end
298 result << nil
299 end
300 end
301
302 def dump_exception_table(result)
def dump_exception_table(result)
248 lib/visitor/javap/code_info.rb:14 in 'YAJD::Visitor::Javap::CodeInfoVisitor#accept'
303 table = @object.exception_table
304 unless table.empty?
305 result << ' Exception table: '
306 result << ' from to target type'
307 table.each do |e|
308 #TODO which is the max value? %3d is enough?
309 catch_type = e.catch_class
catch_type = e.catch_class
31 YAJD::Attributes::ExceptionTable#catch_class at (eval):2
310 if catch_type.nil?
311 catch_type = 'any'
312 else
313 catch_type = "Class #{catch_type.full_name}"
catch_type = "Class #{catch_type.full_name}"
31 YAJD::ConstantPool::CClass#full_name at lib/constant_pool/cpinfo.rb:93
314 end
315
316 result << " #{sprintf('%4d', e.start_pc)} #{sprintf("%4d", e.end_pc)} #{sprintf("%4d", e.handler_pc)} #{catch_type}"
317 end
318 else
319 result << nil
320 end
321 end
322
323 def dump_code(result)
def dump_code(result)
248 lib/visitor/javap/code_info.rb:13 in 'YAJD::Visitor::Javap::CodeInfoVisitor#accept'
324 result << ' Code:'
325 #TODO Is this info somewhere else?
326 m = MethodDescriptor.new(@object.method.descriptor.bytes)
m = MethodDescriptor.new(@object.method.descriptor.bytes)
248 YAJD::MethodDescriptor#initialize at lib/method_descriptor.rb:6
248 YAJD::CommonInfo#descriptor at (eval):2
248 YAJD::Attributes::CodeInfo#method at lib/attributes/code.rb:34
327 args = m.args.size
328 #TODO all the checks in AccessFlags should be included in
329 #the classes which hace an 'access_flags' attribute, so the
330 #check is something like @object.method.abstract?
331 args += 1 unless AccessFlags::static?(@object.method.access_flags)
args += 1 unless AccessFlags::static?(@object.method.access_flags)
248 YAJD::Attributes::CodeInfo#method at lib/attributes/code.rb:34
248 #<Class:YAJD::AccessFlags>#static? at lib/access_flags.rb:49
332 result << " Stack=#{@object.max_stack}, Locals=#{@object.max_locals}, Args_size=#{args}"
333
334 pc = 0
335 while pc < @object.code.size do
336 opcode = @object.code[pc]
337
338 raise "unknown opcode 0x#{opcode.to_s(16)} (#{opcode}) at pc #{pc}" if @@opcodes[opcode].nil?
339 op = @@opcodes[opcode]
340
341 new_pc, code = refactor_me(pc, opcode)
new_pc, code = refactor_me(pc, opcode)
4130 YAJD::Visitor::Javap::CodeInfoVisitor#refactor_me at lib/visitor/javap/code_info.rb:72
342 unless new_pc.nil?
343 unless code.nil?
344 result << " #{pc}:\t#{op[:name]}#{code}"
345 end
346 pc = new_pc
347 next
348 end
349
350 YAJD::logger.debug { "#{pc}: #{op[:name]}" }
YAJD::logger.debug { "#{pc}: #{op[:name]}" }
2063 Logger#debug at /usr/lib/ruby/1.8/logger.rb:347
2063 #<Class:YAJD>#logger at lib/yajd.rb:20
351
352 new_pc = handle_special_case(pc, opcode)
new_pc = handle_special_case(pc, opcode)
2063 YAJD::Visitor::Javap::CodeInfoVisitor#handle_special_case at lib/visitor/javap/code_info.rb:271
353 unless new_pc.nil?
354 result << " #{pc}:\t#{op[:name]}"
355 pc = new_pc
356 next
357 end
358
359 raise "skip missing for instruction 0x#{opcode.to_s(16)} (#{opcode})" if op[:skip] == 'nil'
360
361 result << " #{pc}:\t#{op[:name]}"
362 pc += 1 + (op[:skip] || 0)
363 end
364 end
365
366 end
367
368 end
369
370 end
371
372 end
Generated using the rcov code coverage analysis tool for Ruby version 0.8.0.