File Coverage

blib/lib/PJVM/Bytecode/Reader.pm
Criterion Covered Total %
statement 7 9 77.7
branch n/a
condition n/a
subroutine 3 3 100.0
pod n/a
total 10 12 83.3


line stmt bran cond sub pod time code
1             package PJVM::Bytecode::Reader;
2              
3 1     1   41165 use strict;
  1         2  
  1         38  
4 1     1   5 use warnings;
  1         2  
  1         29  
5              
6 1     1   420 use List::MoreUtils qw(any);
  0            
  0            
7              
8             sub _index_byte { ${$_[1]} += 1; return (shift @{$_[0]}); }
9              
10             sub _index_short { ${$_[1]} += 2; my ($i1, $i2) = splice @{$_[0]}, 0, 2; return ($i1 << 8 | $i2); }
11              
12             sub _byte { ${$_[1]} += 1; return (shift @{$_[0]}); }
13              
14             sub _short { ${$_[1]} += 2; my ($i1, $i2) = splice @{$_[0]}, 0, 2; return ($i1 << 8 | $i2); }
15              
16             sub _offset_short { ${$_[1]} += 2; my ($o1, $o2) = splice @{$_[0]}, 0, 2; return ($o1 << 8 | $o2); }
17              
18             sub _offset_long {
19             ${$_[1]} += 4;
20             my ($o1, $o2, $o3, $o4) = splice @{$_[0]}, 0, 4;
21             return ($o1 << 24 | $o2 << 16 | $o3 << 8 | $o4);
22             }
23              
24             sub _index_byte_const {
25             ${$_[1]} += 2;
26             return splice @{$_[0]}, 0, 2;
27             }
28              
29             sub _index_short_count_0 {
30             ${$_[1]} += 4;
31             my ($i1, $i2, $count, undef) = splice @{$_[0]}, 0, 4;
32             return ($i1 << 8 | $i2, $count);
33             }
34              
35             sub _index_short_count {
36             ${$_[1]} += 3;
37             my ($i1, $i2, $count) = splice @{$_[0]}, 0, 3;
38             return ($i1 << 8 | $i2, $count);
39             }
40              
41              
42             my %Op_transformation = (
43             0x19 => \&_index_byte, # aload
44             0xbd => \&_index_short, # anewarray
45             0x3a => \&_index_byte, # astore
46            
47             0x10 => \&_byte, # bipush
48              
49             0xc0 => \&_index_short, # checkcast
50            
51             0x18 => \&_index_byte, # dload
52             0x39 => \&_index_byte, # dstore
53            
54             0x17 => \&_index_byte, # fload
55             0x38 => \&_index_byte, # fstore
56            
57             0xb4 => \&_index_short, # getfield
58             0xb2 => \&_index_short, # getstatic
59             0xa7 => \&_offset_short, # goto
60             0xc8 => \&_offset_long, # goto_w
61            
62             0xa5 => \&_offset_short, # if_acmpeq
63             0xa6 => \&_offset_short, # if_acmpne
64             0x9f => \&_offset_short, # if_icmpeq
65             0xa0 => \&_offset_short, # if_icmpne
66             0xa1 => \&_offset_short, # if_icmplt
67             0xa2 => \&_offset_short, # if_icmpge
68             0xa3 => \&_offset_short, # if_icmpgt
69             0xa4 => \&_offset_short, # if_icmple
70             0x99 => \&_offset_short, # ifeq
71             0x9a => \&_offset_short, # ifne
72             0x9b => \&_offset_short, # iflt
73             0x9c => \&_offset_short, # ifge
74             0x9d => \&_offset_short, # ifgt
75             0x9e => \&_offset_short, # ifle
76             0xc7 => \&_offset_short, # ifnotnull
77             0xc6 => \&_offset_short, # ifnull
78             0x84 => \&_index_byte_const, # iinc
79             0x15 => \&_index_byte, # iload
80             0xc1 => \&_index_short, # instanceof
81             0xb9 => \&_index_short_count_0, # invokeinterface
82             0xb7 => \&_index_short, # invokespecial
83             0xb8 => \&_index_short, # invokestatic
84             0xb6 => \&_index_short, # invokevirtual
85             0x36 => \&_index_byte, # istore
86            
87             0xa8 => \&_offset_short, # jsr
88             0xc9 => \&_offset_long, # jsr_w
89            
90             0x12 => \&_index_byte, # ldc
91             0x13 => \&_index_short, # ldc_w
92             0x14 => \&_index_short, # ldc2_w
93             0x16 => \&_index_short, # lload
94             0xab => sub { # lookupswitch
95             my ($ops, $ix) = @_;
96             my $pad = 3 - ($$ix - 1) % 4;
97             if ($pad) {
98             splice @$ops, 0, $pad;
99             $$ix += $pad;
100             };
101            
102             # default offset
103             my ($d1, $d2, $d3, $d4) = splice @$ops, 0, 4;
104             $$ix += 4;
105             my $default = ($d1 << 24 | $d2 << 16 | $d3 << 8 | $d4);
106              
107             # number of case :
108             my ($n1, $n2, $n3, $n4) = splice @$ops, 0, 4;
109             $$ix += 4;
110             my $case_no = ($d1 << 24 | $d2 << 16 | $d3 << 8 | $d4);
111            
112             my @pairs;
113             if ($case_no) {
114             my ($i1, $i2, $i3, $i4, $o1, $o2, $o3, $o4) = splice @$ops, 0, 8;
115             $$ix += 8;
116             push @pairs, ($i1 << 24 | $i2 << 16 | $i3 << 8 | $i4), ($o1 << 24 | $o2 << 16 | $o3 << 8 | $o4);
117             }
118            
119             return ($default, @pairs);
120             },
121             0x37 => \&_index_byte, # lstore
122            
123             0xc5 => \&_index_short_count, # multianewarray
124            
125             0xbb => \&_index_short, # new
126             0xbc => \&_byte, # newarray
127            
128             0xb5 => \&_index_short, # putfield
129             0xb3 => \&_index_short, # putstatic
130            
131             0xa9 => \&_index_byte, # ret
132            
133             0x11 => \&_short, # sipush
134              
135             0xaa => sub { # tableswitch
136             my ($ops, $ix) = @_;
137             my $pad = 3 - ($$ix - 1) % 4;
138             if ($pad) {
139             splice @$ops, 0, $pad;
140             $$ix += $pad;
141             };
142            
143             # default offset
144             my ($d1, $d2, $d3, $d4) = splice @$ops, 0, 4;
145             $$ix += 4;
146             my $default = ($d1 << 24 | $d2 << 16 | $d3 << 8 | $d4);
147              
148             # low :
149             my ($l1, $l2, $l3, $l4) = splice @$ops, 0, 4;
150             $$ix += 4;
151             my $low = ($l1 << 24 | $l2 << 16 | $l3 << 8 | $l4);
152              
153             my ($h1, $h2, $h3, $h4) = splice @$ops, 0, 4;
154             $$ix += 4;
155             my $high = ($h1 << 24 | $h2 << 16 | $h3 << 8 | $h4);
156            
157             my $jump_offsets = $high - $low + 1;
158             my @jump_offsets;
159             if ($jump_offsets) {
160             my ($o1, $o2, $o3, $o4) = splice @$ops, 0, 4;
161             $$ix += 4;
162             push @jump_offsets, ($o1 << 24 | $o2 << 16 | $o3 << 8 | $o4);
163             }
164            
165             return ($default, $low, $high, @jump_offsets);
166             },
167            
168             0xc4 => sub { # wide
169             my ($ops, $ix) = @_;
170            
171             my $op = shift @$ops;
172             $$ix++;
173            
174             if ($op == 0x84) {
175             my ($i1, $i2, $c1, $c2) = splice @$ops, 0, 4;
176             $$ix += 4;
177             return ($op, $i1 << 8 | $i2, $c1 << 8 | $c2);
178             }
179             elsif (any { $_ == $op } (0x15, 0x36, 0x17, 0x38, 0x19, 0x3a, 0x16, 0x37, 0x18, 0x39, 0xa9)) {
180             my ($i1, $i2) = splice @$ops, 0, 2;
181             $$ix += 2;
182             return ($op, $i1 << 8 | $i2);
183             }
184             else {
185             die "Bytecode stream error"
186             }
187             }
188             );
189            
190             sub read {
191             my ($pkg, $bytecode) = @_;
192            
193             my @bytecode = unpack("C*", $bytecode);
194             my @ops;
195             my $ix = 0;
196             while (@bytecode) {
197             my $opcode = shift @bytecode;
198             my $pc = $ix++;
199             my $transformer = $Op_transformation{$opcode};
200             my @args = defined $transformer ? $transformer->(\@bytecode, \$ix) : ();
201             push @ops, [$opcode, @args], (undef) x ($ix - 1 - $pc);
202             }
203            
204             return \@ops;
205             }
206              
207             1;
208             __END__