1#!perl 2 3BEGIN { 4 unshift @INC, 't'; 5 require Config; 6 if (($Config::Config{'extensions'} !~ /\bB\b/) ){ 7 print "1..0 # Skip -- Perl configured without B module\n"; 8 exit 0; 9 } 10} 11 12use OptreeCheck; # ALSO DOES @ARGV HANDLING !!!!!! 13 14plan tests => 99; 15 16################################# 17 18my sub lleexx {} 19sub tsub0 {} 20sub tsub1 {} $tsub1 = 1; 21sub t::tsub2 {} 22sub t::tsub3 {} $tsub3 = 1; 23{ 24 package t; 25 sub tsub4 {} 26 sub tsub5 {} $tsub5 = 1; 27} 28 29use constant { # see also t/op/gv.t line 358 30 myaref => [ 1,2,3 ], 31 myfl => 1.414213, 32 myglob => \*STDIN, 33 myhref => { a => 1 }, 34 myint => 42, 35 myrex => qr/foo/, 36 mystr => 'hithere', 37 mysub => \&ok, 38 myundef => undef, 39 myunsub => \&nosuch, 40 myanonsub => sub {}, 41 mylexsub => \&lleexx, 42 tsub0 => \&tsub0, 43 tsub1 => \&tsub1, 44 tsub2 => \&t::tsub2, 45 tsub3 => \&t::tsub3, 46 tsub4 => \&t::tsub4, 47 tsub5 => \&t::tsub5, 48}; 49 50sub myyes() { 1==1 } 51sub myno () { return 1!=1 } 52sub pi () { 3.14159 }; 53 54my $want = { # expected types, how value renders in-line, todos (maybe) 55 mystr => [ 'PV', '"'.mystr.'"' ], 56 myhref => [ 'IV', '\\\\HASH'], 57 pi => [ 'NV', pi ], 58 myglob => [ 'IV', '\\\\' ], 59 mysub => [ 'IV', '\\\\&main::ok' ], 60 myunsub => [ 'IV', '\\\\&main::nosuch' ], 61 myanonsub => [ 'IV', '\\\\CODE' ], 62 mylexsub => [ 'IV', '\\\\&lleexx' ], 63 tsub0 => [ 'IV', '\\\\&main::tsub0' ], 64 tsub1 => [ 'IV', '\\\\&main::tsub1' ], 65 tsub2 => [ 'IV', '\\\\&t::tsub2' ], 66 tsub3 => [ 'IV', '\\\\&t::tsub3' ], 67 tsub4 => [ 'IV', '\\\\&t::tsub4' ], 68 tsub5 => [ 'IV', '\\\\&t::tsub5' ], 69 # these are not inlined, at least not per BC::Concise 70 #myyes => [ 'IV', ], 71 #myno => [ 'IV', ], 72 myaref => [ 'IV', '\\\\ARRAY' ], 73 myfl => [ 'NV', myfl ], 74 myint => [ 'IV', myint ], 75 myrex => [ 'IV', '\\\\"\\(?^:Foo\\)"' ], 76 myundef => [ 'NULL', ], 77}; 78 79use constant WEEKDAYS 80 => qw ( Sunday Monday Tuesday Wednesday Thursday Friday Saturday ); 81 82 83$::{napier} = \2.71828; # counter-example (doesn't get optimized). 84eval "sub napier ();"; 85 86 87# should be able to undefine constant::import here ??? 88INIT { 89 # eval 'sub constant::import () {}'; 90 # undef *constant::import::{CODE}; 91}; 92 93################################# 94pass("RENDER CONSTANT SUBS RETURNING SCALARS"); 95 96for $func (sort keys %$want) { 97 # no strict 'refs'; # why not needed ? 98 checkOptree ( name => "$func() as a coderef", 99 code => \&{$func}, 100 noanchors => 1, 101 expect => <<EOT_EOT, expect_nt => <<EONT_EONT); 102 is a constant sub, optimized to a $want->{$func}[0] 103EOT_EOT 104 is a constant sub, optimized to a $want->{$func}[0] 105EONT_EONT 106 107} 108 109pass("RENDER CALLS TO THOSE CONSTANT SUBS"); 110 111for $func (sort keys %$want) { 112 # print "# doing $func\n"; 113 checkOptree ( name => "call $func", 114 code => "$func", 115 ($want->{$func}[2]) ? ( todo => $want->{$func}[2]) : (), 116 bc_opts => '-nobanner', 117 expect => <<EOT_EOT, expect_nt => <<EONT_EONT); 1183 <1> leavesub[2 refs] K/REFC,1 ->(end) 119- <\@> lineseq KP ->3 1201 <;> dbstate(main 833 (eval 44):1) v ->2 1212 <\$> const[$want->{$func}[0] $want->{$func}[1]] s*/FOLD ->3 122EOT_EOT 1233 <1> leavesub[2 refs] K/REFC,1 ->(end) 124- <\@> lineseq KP ->3 1251 <;> dbstate(main 833 (eval 44):1) v ->2 1262 <\$> const($want->{$func}[0] $want->{$func}[1]) s*/FOLD ->3 127EONT_EONT 128 129} 130 131############## 132pass("MORE TESTS"); 133 134checkOptree ( name => 'myyes() as coderef', 135 code => sub () { 1==1 }, 136 noanchors => 1, 137 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 138 is a constant sub, optimized to a SPECIAL 139EOT_EOT 140 is a constant sub, optimized to a SPECIAL 141EONT_EONT 142 143 144checkOptree ( name => 'myyes() as coderef', 145 prog => 'sub a() { 1==1 }; print a', 146 noanchors => 1, 147 strip_open_hints => 1, 148 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 149# 6 <@> leave[1 ref] vKP/REFC ->(end) 150# 1 <0> enter v ->2 151# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3 152# 5 <@> print vK ->6 153# 3 <0> pushmark s ->4 154# 4 <$> const[SPECIAL sv_yes] s*/FOLD ->5 155EOT_EOT 156# 6 <@> leave[1 ref] vKP/REFC ->(end) 157# 1 <0> enter v ->2 158# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3 159# 5 <@> print vK ->6 160# 3 <0> pushmark s ->4 161# 4 <$> const(SPECIAL sv_yes) s*/FOLD ->5 162EONT_EONT 163 164 165# Need to do this as a prog, not code, as only the first constant to use 166# PL_sv_no actually gets to use the real thing - every one following is 167# copied. 168checkOptree ( name => 'myno() as coderef', 169 prog => 'sub a() { 1!=1 }; print a', 170 noanchors => 1, 171 strip_open_hints => 1, 172 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 173# 6 <@> leave[1 ref] vKP/REFC ->(end) 174# 1 <0> enter v ->2 175# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3 176# 5 <@> print vK ->6 177# 3 <0> pushmark s ->4 178# 4 <$> const[SPECIAL sv_no] s*/FOLD ->5 179EOT_EOT 180# 6 <@> leave[1 ref] vKP/REFC ->(end) 181# 1 <0> enter v ->2 182# 2 <;> nextstate(main 2 -e:1) v:>,<,%,{ ->3 183# 5 <@> print vK ->6 184# 3 <0> pushmark s ->4 185# 4 <$> const(SPECIAL sv_no) s*/FOLD ->5 186EONT_EONT 187 188 189my ($expect, $expect_nt) = (" is a constant sub, optimized to a AV\n") x 2; 190 191 192checkOptree ( name => 'constant sub returning list', 193 code => \&WEEKDAYS, 194 noanchors => 1, 195 expect => $expect, expect_nt => $expect_nt); 196 197 198sub printem { 199 printf "myint %d mystr %s myfl %f pi %f\n" 200 , myint, mystr, myfl, pi; 201} 202 203my ($expect, $expect_nt) = (<<'EOT_EOT', <<'EONT_EONT'); 204# 9 <1> leavesub[1 ref] K/REFC,1 ->(end) 205# - <@> lineseq KP ->9 206# 1 <;> nextstate(main 635 optree_constants.t:163) v:>,<,% ->2 207# 8 <@> prtf sK ->9 208# 2 <0> pushmark sM ->3 209# 3 <$> const[PV "myint %d mystr %s myfl %f pi %f\n"] sM/FOLD ->4 210# 4 <$> const[IV 42] sM*/FOLD ->5 211# 5 <$> const[PV "hithere"] sM*/FOLD ->6 212# 6 <$> const[NV 1.414213] sM*/FOLD ->7 213# 7 <$> const[NV 3.14159] sM*/FOLD ->8 214EOT_EOT 215# 9 <1> leavesub[1 ref] K/REFC,1 ->(end) 216# - <@> lineseq KP ->9 217# 1 <;> nextstate(main 635 optree_constants.t:163) v:>,<,% ->2 218# 8 <@> prtf sK ->9 219# 2 <0> pushmark sM ->3 220# 3 <$> const(PV "myint %d mystr %s myfl %f pi %f\n") sM/FOLD ->4 221# 4 <$> const(IV 42) sM*/FOLD ->5 222# 5 <$> const(PV "hithere") sM*/FOLD ->6 223# 6 <$> const(NV 1.414213) sM*/FOLD ->7 224# 7 <$> const(NV 3.14159) sM*/FOLD ->8 225EONT_EONT 226 227s|\\n"[])] sM\K/FOLD|| for $expect, $expect_nt; 228 229checkOptree ( name => 'call many in a print statement', 230 code => \&printem, 231 strip_open_hints => 1, 232 expect => $expect, expect_nt => $expect_nt); 233 234# test constant expression folding 235 236checkOptree ( name => 'arithmetic constant folding in print', 237 code => 'print 1+2+3', 238 strip_open_hints => 1, 239 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 240# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 241# - <@> lineseq KP ->5 242# 1 <;> nextstate(main 937 (eval 53):1) v ->2 243# 4 <@> print sK ->5 244# 2 <0> pushmark s ->3 245# 3 <$> const[IV 6] s/FOLD ->4 246EOT_EOT 247# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 248# - <@> lineseq KP ->5 249# 1 <;> nextstate(main 937 (eval 53):1) v ->2 250# 4 <@> print sK ->5 251# 2 <0> pushmark s ->3 252# 3 <$> const(IV 6) s/FOLD ->4 253EONT_EONT 254 255checkOptree ( name => 'string constant folding in print', 256 code => 'print "foo"."bar"', 257 strip_open_hints => 1, 258 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 259# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 260# - <@> lineseq KP ->5 261# 1 <;> nextstate(main 942 (eval 55):1) v ->2 262# 4 <@> print sK ->5 263# 2 <0> pushmark s ->3 264# 3 <$> const[PV "foobar"] s/FOLD ->4 265EOT_EOT 266# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 267# - <@> lineseq KP ->5 268# 1 <;> nextstate(main 942 (eval 55):1) v ->2 269# 4 <@> print sK ->5 270# 2 <0> pushmark s ->3 271# 3 <$> const(PV "foobar") s/FOLD ->4 272EONT_EONT 273 274checkOptree ( name => 'boolean or folding', 275 code => 'print "foobar" if 1 or 0', 276 strip_open_hints => 1, 277 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 278# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 279# - <@> lineseq KP ->5 280# 1 <;> nextstate(main 942 (eval 55):1) v ->2 281# 4 <@> print sK/FOLD ->5 282# 2 <0> pushmark s ->3 283# 3 <$> const[PV "foobar"] s ->4 284EOT_EOT 285# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 286# - <@> lineseq KP ->5 287# 1 <;> nextstate(main 942 (eval 55):1) v ->2 288# 4 <@> print sK/FOLD ->5 289# 2 <0> pushmark s ->3 290# 3 <$> const(PV "foobar") s ->4 291EONT_EONT 292 293checkOptree ( name => 'lc*,uc*,gt,lt,ge,le,cmp', 294 code => sub { 295 $s = uc('foo.').ucfirst('bar.').lc('LOW.').lcfirst('LOW'); 296 print "a-lt-b" if "a" lt "b"; 297 print "b-gt-a" if "b" gt "a"; 298 print "a-le-b" if "a" le "b"; 299 print "b-ge-a" if "b" ge "a"; 300 print "b-cmp-a" if "b" cmp "a"; 301 print "a-gt-b" if "a" gt "b"; # should be suppressed 302 }, 303 strip_open_hints => 1, 304 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 305# r <1> leavesub[1 ref] K/REFC,1 ->(end) 306# - <@> lineseq KP ->r 307# 1 <;> nextstate(main 916 optree_constants.t:307) v:>,<,%,{ ->2 308# 4 <2> sassign vKS/2 ->5 309# 2 <$> const[PV "FOO.Bar.low.lOW"] s/FOLD ->3 310# - <1> ex-rv2sv sKRM*/1 ->4 311# 3 <#> gvsv[*s] s ->4 312# 5 <;> nextstate(main 916 optree_constants.t:308) v:>,<,%,{ ->6 313# 8 <@> print vK/FOLD ->9 314# 6 <0> pushmark s ->7 315# 7 <$> const[PV "a-lt-b"] s ->8 316# 9 <;> nextstate(main 916 optree_constants.t:309) v:>,<,%,{ ->a 317# c <@> print vK/FOLD ->d 318# a <0> pushmark s ->b 319# b <$> const[PV "b-gt-a"] s ->c 320# d <;> nextstate(main 916 optree_constants.t:310) v:>,<,%,{ ->e 321# g <@> print vK/FOLD ->h 322# e <0> pushmark s ->f 323# f <$> const[PV "a-le-b"] s ->g 324# h <;> nextstate(main 916 optree_constants.t:311) v:>,<,%,{ ->i 325# k <@> print vK/FOLD ->l 326# i <0> pushmark s ->j 327# j <$> const[PV "b-ge-a"] s ->k 328# l <;> nextstate(main 916 optree_constants.t:312) v:>,<,%,{ ->m 329# o <@> print vK/FOLD ->p 330# m <0> pushmark s ->n 331# n <$> const[PV "b-cmp-a"] s ->o 332# p <;> nextstate(main 916 optree_constants.t:313) v:>,<,%,{ ->q 333# q <$> const[SPECIAL sv_no] s/SHORT,FOLD ->r 334EOT_EOT 335# r <1> leavesub[1 ref] K/REFC,1 ->(end) 336# - <@> lineseq KP ->r 337# 1 <;> nextstate(main 916 optree_constants.t:307) v:>,<,%,{ ->2 338# 4 <2> sassign vKS/2 ->5 339# 2 <$> const(PV "FOO.Bar.low.lOW") s/FOLD ->3 340# - <1> ex-rv2sv sKRM*/1 ->4 341# 3 <$> gvsv(*s) s ->4 342# 5 <;> nextstate(main 916 optree_constants.t:308) v:>,<,%,{ ->6 343# 8 <@> print vK/FOLD ->9 344# 6 <0> pushmark s ->7 345# 7 <$> const(PV "a-lt-b") s ->8 346# 9 <;> nextstate(main 916 optree_constants.t:309) v:>,<,%,{ ->a 347# c <@> print vK/FOLD ->d 348# a <0> pushmark s ->b 349# b <$> const(PV "b-gt-a") s ->c 350# d <;> nextstate(main 916 optree_constants.t:310) v:>,<,%,{ ->e 351# g <@> print vK/FOLD ->h 352# e <0> pushmark s ->f 353# f <$> const(PV "a-le-b") s ->g 354# h <;> nextstate(main 916 optree_constants.t:311) v:>,<,%,{ ->i 355# k <@> print vK/FOLD ->l 356# i <0> pushmark s ->j 357# j <$> const(PV "b-ge-a") s ->k 358# l <;> nextstate(main 916 optree_constants.t:312) v:>,<,%,{ ->m 359# o <@> print vK/FOLD ->p 360# m <0> pushmark s ->n 361# n <$> const(PV "b-cmp-a") s ->o 362# p <;> nextstate(main 916 optree_constants.t:313) v:>,<,%,{ ->q 363# q <$> const(SPECIAL sv_no) s/SHORT,FOLD ->r 364EONT_EONT 365 366checkOptree ( name => 'mixed constant folding, with explicit braces', 367 code => 'print "foo"."bar".(2+3)', 368 strip_open_hints => 1, 369 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 370# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 371# - <@> lineseq KP ->5 372# 1 <;> nextstate(main 977 (eval 28):1) v ->2 373# 4 <@> print sK ->5 374# 2 <0> pushmark s ->3 375# 3 <$> const[PV "foobar5"] s/FOLD ->4 376EOT_EOT 377# 5 <1> leavesub[1 ref] K/REFC,1 ->(end) 378# - <@> lineseq KP ->5 379# 1 <;> nextstate(main 977 (eval 28):1) v ->2 380# 4 <@> print sK ->5 381# 2 <0> pushmark s ->3 382# 3 <$> const(PV "foobar5") s/FOLD ->4 383EONT_EONT 384 385__END__ 386 387=head NB 388 389Optimized constant subs are stored as bare scalars in the stash 390(package hash), which formerly held only GVs (typeglobs). 391 392But you cant create them manually - you cant assign a scalar to a 393stash element, and expect it to work like a constant-sub, even if you 394provide a prototype. 395 396This is a feature; alternative is too much action-at-a-distance. The 397following test demonstrates - napier is not seen as a function at all, 398much less an optimized one. 399 400=cut 401 402checkOptree ( name => 'not evertnapier', 403 code => \&napier, 404 noanchors => 1, 405 expect => <<'EOT_EOT', expect_nt => <<'EONT_EONT'); 406 has no START 407EOT_EOT 408 has no START 409EONT_EONT 410 411 412