File Coverage

blib/lib/Opcodes.pm
Criterion Covered Total %
statement 69 72 95.8
branch 15 26 57.6
condition 4 6 66.6
subroutine 20 20 100.0
pod 7 7 100.0
total 115 131 87.7


line stmt bran cond sub pod time code
1             package Opcodes;
2              
3 1     1   27800 use 5.006_001;
  1         4  
  1         40  
4 1     1   7 use strict;
  1         2  
  1         204  
5              
6             our($VERSION, @ISA, @EXPORT, @EXPORT_OK);
7              
8             $VERSION = "0.14";
9              
10 1     1   6 use Exporter ();
  1         6  
  1         16  
11 1     1   5 use XSLoader ();
  1         1  
  1         90  
12              
13             BEGIN {
14 1     1   16 @ISA = qw(Exporter);
15 1         6 @EXPORT =
16             qw(opcodes opname opname2code opflags opaliases
17             opargs opclass opdesc opname
18             OA_CLASS_MASK
19             OA_MARK
20             OA_FOLDCONST
21             OA_RETSCALAR
22             OA_TARGET
23             OA_RETINTEGER
24             OA_OTHERINT
25             OA_DANGEROUS
26             OA_DEFGV
27             OA_TARGLEX
28              
29             OA_BASEOP
30             OA_UNOP
31             OA_BINOP
32             OA_LOGOP
33             OA_LISTOP
34             OA_PMOP
35             OA_SVOP
36             OA_PADOP
37             OA_PVOP_OR_SVOP
38             OA_LOOP
39             OA_COP
40             OA_BASEOP_OR_UNOP
41             OA_FILESTATOP
42             OA_LOOPEXOP
43              
44             OA_SCALAR
45             OA_LIST
46             OA_AVREF
47             OA_HVREF
48             OA_CVREF
49             OA_FILEREF
50             OA_SCALARREF
51             OA_OPTIONAL
52              
53             OA_NOSTACK
54             OA_MAYSCALAR
55             OA_MAYARRAY
56             OA_MAYVOID
57             OA_RETFIXED
58             OA_MAYBRANCH
59             );
60 1         34 @EXPORT_OK = qw(ppaddr check argnum maybranch);
61             }
62 1     1   1089 use subs @EXPORT_OK;
  1         21  
  1         7  
63              
64             sub AUTOLOAD {
65             # 'autoload' constants from the constant() XS function.
66 1     1   2 my $constname;
67 1         1 our $AUTOLOAD;
68 1         7 ($constname = $AUTOLOAD) =~ s/.*:://;
69 1 50       5 die "&Opcodes::constant not defined" if $constname eq 'constant';
70 1         14 my ($error, $val) = constant($constname);
71 1 50       3 if ($error) { die $error; }
  0         0  
72             {
73 1     1   140 no strict 'refs';
  1         1  
  1         1274  
  1         2  
74 1     2   8 *$AUTOLOAD = sub { $val };
  2         8  
75             }
76 1         6 goto &$AUTOLOAD;
77             }
78              
79             XSLoader::load 'Opcodes', $VERSION;
80              
81             our @opcodes = opcodes();
82              
83             sub opname ($) {
84 258     258 1 991 $opcodes[ $_[0] ]->[1];
85             }
86              
87             sub ppaddr ($) {
88 6     6   16 $opcodes[ $_[0] ]->[2];
89             }
90              
91             sub check ($) {
92 2     2   239 $opcodes[ $_[0] ]->[3];
93             }
94              
95             sub opdesc ($) {
96 1     1 1 237 Opcode::opdesc( opname( $_[0] ));
97             }
98              
99             sub opargs ($) {
100 9     9 1 40 $opcodes[ $_[0] ]->[4];
101             }
102              
103             # n no_stack - A handcoded list of ops without any SP handling (Note: stack_base is allowed),
104             # i.e. no args + no return values.
105             # 'n' 512 is not encoded in opcode.pl. We could add it but then we would have to
106             # maintain it in CORE as well as here. Here its is needed for older perls. So
107             # keep it this way. Note that enter,entertry,leave indirectly use the stack.
108             our %no_stack = map{$_=>1}qw[null unstack scope lineseq
109             next redo goto break continue nextstate dbstate pushmark
110             regcmaybe regcreset];
111             # S retval may be scalar. s and i are automatically included
112             our %retval_scalar = map{$_=>1}qw[];
113             # A retval may be array
114             our %retval_array = map{$_=>1}qw[];
115             # V retval may be void
116             our %retval_void = map{$_=>1}qw[];
117             # F fixed retval type (S, A or V)
118             our %retval_fixed = map{$_=>1}qw[];
119             # N pp_* may return other than op_next
120             our %maybranch = map{$_=>1}
121             # LOGOP's which return op_other
122             qw[once cond_expr and or orassign andassign dor dorassign grepwhile mapwhile substcont
123             enterwhen entergiven range
124             ],
125             # other OPs
126             qw[formline grepstart flip dbstate goto leaveeval
127             break
128             subst entersub
129             return last next redo require entereval entertry continue dump
130             ];
131              
132             sub opflags ($) {
133             # 0x1ff = 9 bits OCSHIFT
134 2     2 1 7 my $OCSHIFT = constant('OCSHIFT'); # 9
135 2         3 my $mask = (2 ** $OCSHIFT) - 1;
136 2         5 my $flags = opargs($_[0]) & $mask; # & 0x1ff
137             # now the extras
138 2         4 my $opname = opname($_[0]);
139             #$flags += 16 if $retint{$opname};
140 2 50       7 $flags += 512 if $no_stack{$opname};
141 2 50 33     15 $flags += 1024 if $retval_scalar{$opname} or $flags & 20; # 4|16
142 2 50       7 $flags += 2048 if $retval_array{$opname};
143 2 50       6 $flags += 4096 if $retval_void{$opname};
144 2 50       4 $flags += 8192 if $retval_fixed{$opname};
145 2 50       7 $flags += 16384 if maybranch($_[0]);
146 2         11 return $flags;
147             }
148              
149             # See F for $OASHIFT and $OCSHIFT. For flags n 512 we
150             # would have to change that.
151             sub opclass ($) {
152 4     4 1 29 my $OCSHIFT = constant('OCSHIFT'); # 9
153 4         9 my $OASHIFT = constant('OASHIFT'); # 13
154 4         8 my $mask = (2 ** ($OASHIFT-$OCSHIFT)) - 1; # 0b1111 4bit 13-9=4 bits
155 4         6 $mask = $mask << $OCSHIFT; # 1e00: 4bit left-shifted by 9
156 4         8 (opargs($_[0]) & $mask) >> $OCSHIFT;
157             }
158              
159             sub argnum ($) {
160             #my $ARGSHIFT = 4;
161             #my $ARGBITS = 32;
162 1     1   4 my $OASHIFT = constant('OASHIFT'); # 13
163             # ffffe000 = 32-13 bits left-shifted by 13
164 1         3 my $mask = ((2 ** (32-$OASHIFT)) - 1) << $OASHIFT;
165 1         3 (opargs($_[0]) & $mask) >> $OASHIFT;
166             }
167              
168             sub opaliases ($) {
169 4     4 1 6 my $op = shift;
170 4         7 my @aliases = ();
171 4         10 my $ppaddr = ppaddr($op);
172 4         8 for (@opcodes) {
173 1516 100 100     2938 push @aliases, ($_->[0])
174             if $_->[2] == $ppaddr and $_->[0] != $op;
175             }
176 4         19 @aliases;
177             }
178              
179             sub opname2code ($) {
180 3     3 1 1728 my $name = shift;
181 3 100       14 for (0..$#opcodes) { return $_ if opname($_) eq $name; }
  227         282  
182 0         0 return undef;
183             }
184              
185             # All LOGOPs: perl -Mblib -MOpcodes -e'$,=q( );print map {opname $_} grep {opclass($_) == 3} 1..opcodes' =>
186             # regcomp substcont grepwhile mapwhile range and or dor cond_expr andassign orassign dorassign entergiven
187             # enterwhen entertry once
188             # All pp which can return other then op_next (inspected pp*.c):
189             # once and cond_expr or defined grepwhile
190             # substcont formline grepstart mapwhile range flip dbstate goto leaveeval enterwhen break subst entersub
191             # return last next redo require entereval entertry continue
192             # + aliases: maybranch perl -MOpcodes -e'$,=q( );print map {opname $_} grep {opflags($_) & 16384} 1..opcodes'
193             # => subst substcont defined formline grepstart grepwhile mapwhile range and or dor cond_expr andassign
194             # orassign dorassign dbstate return last next redo dump goto entergiven enterwhen require entereval
195             # entertry once
196             sub maybranch ($) {
197 3 50   3   7 return undef if opclass($_[0]) <= 2; # NOT if lower than LOGOP
198 3         5 my $opname = opname($_[0]);
199 3 100       12 return 1 if $maybranch{$opname};
200 2         4 for (opaliases($_[0])) {
201 0 0       0 return 1 if $maybranch{opname($_)};
202             }
203 2         7 return undef;
204             }
205              
206              
207             1;
208             __END__