1# B::Bytecode.pm 2# Copyright (c) 2003 Enache Adrian. All rights reserved. 3# This module is free software; you can redistribute and/or modify 4# it under the same terms as Perl itself. 5 6# Based on the original Bytecode.pm module written by Malcolm Beattie. 7 8package B::Bytecode; 9 10our $VERSION = '1.01'; 11 12use strict; 13use Config; 14use B qw(class main_cv main_root main_start cstring comppadlist 15 defstash curstash begin_av init_av end_av inc_gv warnhook diehook 16 dowarn SVt_PVGV SVt_PVHV OPf_SPECIAL OPf_STACKED OPf_MOD 17 OPpLVAL_INTRO SVf_FAKE SVf_READONLY); 18use B::Asmdata qw(@specialsv_name); 19use B::Assembler qw(asm newasm endasm); 20 21################################################# 22 23my ($varix, $opix, $savebegins, %walked, %files, @cloop); 24my %strtab = (0,0); 25my %svtab = (0,0); 26my %optab = (0,0); 27my %spectab = (0,0); 28my $tix = 1; 29sub asm; 30sub nice ($) { } 31 32BEGIN { 33 my $ithreads = $Config{'useithreads'} eq 'define'; 34 eval qq{ 35 sub ITHREADS() { $ithreads } 36 sub VERSION() { $] } 37 }; die $@ if $@; 38} 39 40################################################# 41 42sub pvstring { 43 my $pv = shift; 44 defined($pv) ? cstring ($pv."\0") : "\"\""; 45} 46 47sub pvix { 48 my $str = pvstring shift; 49 my $ix = $strtab{$str}; 50 defined($ix) ? $ix : do { 51 asm "newpv", $str; 52 asm "stpv", $strtab{$str} = $tix; 53 $tix++; 54 } 55} 56 57sub B::OP::ix { 58 my $op = shift; 59 my $ix = $optab{$$op}; 60 defined($ix) ? $ix : do { 61 nice "[".$op->name." $tix]"; 62 asm "newopx", $op->size | $op->type <<7; 63 $optab{$$op} = $opix = $ix = $tix++; 64 $op->bsave($ix); 65 $ix; 66 } 67} 68 69sub B::SPECIAL::ix { 70 my $spec = shift; 71 my $ix = $spectab{$$spec}; 72 defined($ix) ? $ix : do { 73 nice '['.$specialsv_name[$$spec].']'; 74 asm "ldspecsvx", $$spec; 75 $spectab{$$spec} = $varix = $tix++; 76 } 77} 78 79sub B::SV::ix { 80 my $sv = shift; 81 my $ix = $svtab{$$sv}; 82 defined($ix) ? $ix : do { 83 nice '['.class($sv).']'; 84 asm "newsvx", $sv->FLAGS; 85 $svtab{$$sv} = $varix = $ix = $tix++; 86 $sv->bsave($ix); 87 $ix; 88 } 89} 90 91sub B::GV::ix { 92 my ($gv,$desired) = @_; 93 my $ix = $svtab{$$gv}; 94 defined($ix) ? $ix : do { 95 if ($gv->GP) { 96 my ($svix, $avix, $hvix, $cvix, $ioix, $formix); 97 nice "[GV]"; 98 my $name = $gv->STASH->NAME . "::" . $gv->NAME; 99 asm "gv_fetchpvx", cstring $name; 100 $svtab{$$gv} = $varix = $ix = $tix++; 101 asm "sv_flags", $gv->FLAGS; 102 asm "sv_refcnt", $gv->REFCNT; 103 asm "xgv_flags", $gv->GvFLAGS; 104 105 asm "gp_refcnt", $gv->GvREFCNT; 106 asm "load_glob", $ix if $name eq "CORE::GLOBAL::glob"; 107 return $ix 108 unless $desired || desired $gv; 109 $svix = $gv->SV->ix; 110 $avix = $gv->AV->ix; 111 $hvix = $gv->HV->ix; 112 113 # XXX {{{{ 114 my $cv = $gv->CV; 115 $cvix = $$cv && defined $files{$cv->FILE} ? $cv->ix : 0; 116 my $form = $gv->FORM; 117 $formix = $$form && defined $files{$form->FILE} ? $form->ix : 0; 118 119 $ioix = $name !~ /STDOUT$/ ? $gv->IO->ix : 0; 120 # }}}} XXX 121 122 nice "-GV-", 123 asm "ldsv", $varix = $ix unless $ix == $varix; 124 asm "gp_sv", $svix; 125 asm "gp_av", $avix; 126 asm "gp_hv", $hvix; 127 asm "gp_cv", $cvix; 128 asm "gp_io", $ioix; 129 asm "gp_cvgen", $gv->CVGEN; 130 asm "gp_form", $formix; 131 asm "gp_file", pvix $gv->FILE; 132 asm "gp_line", $gv->LINE; 133 asm "formfeed", $svix if $name eq "main::\cL"; 134 } else { 135 nice "[GV]"; 136 asm "newsvx", $gv->FLAGS; 137 $svtab{$$gv} = $varix = $ix = $tix++; 138 my $stashix = $gv->STASH->ix; 139 $gv->B::PVMG::bsave($ix); 140 asm "xgv_flags", $gv->GvFLAGS; 141 asm "xgv_stash", $stashix; 142 } 143 $ix; 144 } 145} 146 147sub B::HV::ix { 148 my $hv = shift; 149 my $ix = $svtab{$$hv}; 150 defined($ix) ? $ix : do { 151 my ($ix,$i,@array); 152 my $name = $hv->NAME; 153 if ($name) { 154 nice "[STASH]"; 155 asm "gv_stashpvx", cstring $name; 156 asm "sv_flags", $hv->FLAGS; 157 $svtab{$$hv} = $varix = $ix = $tix++; 158 asm "xhv_name", pvix $name; 159 # my $pmrootix = $hv->PMROOT->ix; # XXX 160 asm "ldsv", $varix = $ix unless $ix == $varix; 161 # asm "xhv_pmroot", $pmrootix; # XXX 162 } else { 163 nice "[HV]"; 164 asm "newsvx", $hv->FLAGS; 165 $svtab{$$hv} = $varix = $ix = $tix++; 166 my $stashix = $hv->SvSTASH->ix; 167 for (@array = $hv->ARRAY) { 168 next if $i = not $i; 169 $_ = $_->ix; 170 } 171 nice "-HV-", 172 asm "ldsv", $varix = $ix unless $ix == $varix; 173 ($i = not $i) ? asm ("newpv", pvstring $_) : asm("hv_store", $_) 174 for @array; 175 asm "xnv", $hv->NVX; 176 asm "xmg_stash", $stashix; 177 asm "xhv_riter", $hv->RITER; 178 } 179 asm "sv_refcnt", $hv->REFCNT; 180 $ix; 181 } 182} 183 184sub B::NULL::ix { 185 my $sv = shift; 186 $$sv ? $sv->B::SV::ix : 0; 187} 188 189sub B::NULL::opwalk { 0 } 190 191################################################# 192 193sub B::NULL::bsave { 194 my ($sv,$ix) = @_; 195 196 nice '-'.class($sv).'-', 197 asm "ldsv", $varix = $ix unless $ix == $varix; 198 asm "sv_refcnt", $sv->REFCNT; 199} 200 201sub B::SV::bsave; 202 *B::SV::bsave = *B::NULL::bsave; 203 204sub B::RV::bsave { 205 my ($sv,$ix) = @_; 206 my $rvix = $sv->RV->ix; 207 $sv->B::NULL::bsave($ix); 208 asm "xrv", $rvix; 209} 210 211sub B::PV::bsave { 212 my ($sv,$ix) = @_; 213 $sv->B::NULL::bsave($ix); 214 asm "newpv", pvstring $sv->PVBM; 215 asm "xpv"; 216} 217 218sub B::IV::bsave { 219 my ($sv,$ix) = @_; 220 $sv->B::NULL::bsave($ix); 221 asm "xiv", $sv->IVX; 222} 223 224sub B::NV::bsave { 225 my ($sv,$ix) = @_; 226 $sv->B::NULL::bsave($ix); 227 asm "xnv", sprintf "%.40g", $sv->NVX; 228} 229 230sub B::PVIV::bsave { 231 my ($sv,$ix) = @_; 232 $sv->POK ? 233 $sv->B::PV::bsave($ix): 234 $sv->ROK ? 235 $sv->B::RV::bsave($ix): 236 $sv->B::NULL::bsave($ix); 237 asm "xiv", !ITHREADS && $sv->FLAGS & (SVf_FAKE|SVf_READONLY) ? 238 "0 but true" : $sv->IVX; 239} 240 241sub B::PVNV::bsave { 242 my ($sv,$ix) = @_; 243 $sv->B::PVIV::bsave($ix); 244 asm "xnv", sprintf "%.40g", $sv->NVX; 245} 246 247sub B::PVMG::domagic { 248 my ($sv,$ix) = @_; 249 nice '-MAGICAL-'; 250 my @mglist = $sv->MAGIC; 251 my (@mgix, @namix); 252 for (@mglist) { 253 push @mgix, $_->OBJ->ix; 254 push @namix, $_->PTR->ix if $_->LENGTH == B::HEf_SVKEY; 255 } 256 257 nice '-'.class($sv).'-', 258 asm "ldsv", $varix = $ix unless $ix == $varix; 259 for (@mglist) { 260 asm "sv_magic", cstring $_->TYPE; 261 asm "mg_obj", shift @mgix; 262 my $length = $_->LENGTH; 263 if ($length == B::HEf_SVKEY) { 264 asm "mg_namex", shift @namix; 265 } elsif ($length) { 266 asm "newpv", pvstring $_->PTR; 267 asm "mg_name"; 268 } 269 } 270} 271 272sub B::PVMG::bsave { 273 my ($sv,$ix) = @_; 274 my $stashix = $sv->SvSTASH->ix; 275 $sv->B::PVNV::bsave($ix); 276 asm "xmg_stash", $stashix; 277 $sv->domagic($ix) if $sv->MAGICAL; 278} 279 280sub B::PVLV::bsave { 281 my ($sv,$ix) = @_; 282 my $targix = $sv->TARG->ix; 283 $sv->B::PVMG::bsave($ix); 284 asm "xlv_targ", $targix; 285 asm "xlv_targoff", $sv->TARGOFF; 286 asm "xlv_targlen", $sv->TARGLEN; 287 asm "xlv_type", $sv->TYPE; 288 289} 290 291sub B::BM::bsave { 292 my ($sv,$ix) = @_; 293 $sv->B::PVMG::bsave($ix); 294 asm "xpv_cur", $sv->CUR; 295 asm "xbm_useful", $sv->USEFUL; 296 asm "xbm_previous", $sv->PREVIOUS; 297 asm "xbm_rare", $sv->RARE; 298} 299 300sub B::IO::bsave { 301 my ($io,$ix) = @_; 302 my $topix = $io->TOP_GV->ix; 303 my $fmtix = $io->FMT_GV->ix; 304 my $bottomix = $io->BOTTOM_GV->ix; 305 $io->B::PVMG::bsave($ix); 306 asm "xio_lines", $io->LINES; 307 asm "xio_page", $io->PAGE; 308 asm "xio_page_len", $io->PAGE_LEN; 309 asm "xio_lines_left", $io->LINES_LEFT; 310 asm "xio_top_name", pvix $io->TOP_NAME; 311 asm "xio_top_gv", $topix; 312 asm "xio_fmt_name", pvix $io->FMT_NAME; 313 asm "xio_fmt_gv", $fmtix; 314 asm "xio_bottom_name", pvix $io->BOTTOM_NAME; 315 asm "xio_bottom_gv", $bottomix; 316 asm "xio_subprocess", $io->SUBPROCESS; 317 asm "xio_type", ord $io->IoTYPE; 318 # asm "xio_flags", ord($io->IoFLAGS) & ~32; # XXX XXX 319} 320 321sub B::CV::bsave { 322 my ($cv,$ix) = @_; 323 my $stashix = $cv->STASH->ix; 324 my $gvix = $cv->GV->ix; 325 my $padlistix = $cv->PADLIST->ix; 326 my $outsideix = $cv->OUTSIDE->ix; 327 my $constix = $cv->CONST ? $cv->XSUBANY->ix : 0; 328 my $startix = $cv->START->opwalk; 329 my $rootix = $cv->ROOT->ix; 330 331 $cv->B::PVMG::bsave($ix); 332 asm "xcv_stash", $stashix; 333 asm "xcv_start", $startix; 334 asm "xcv_root", $rootix; 335 asm "xcv_xsubany", $constix; 336 asm "xcv_gv", $gvix; 337 asm "xcv_file", pvix $cv->FILE if $cv->FILE; # XXX AD 338 asm "xcv_padlist", $padlistix; 339 asm "xcv_outside", $outsideix; 340 asm "xcv_flags", $cv->CvFLAGS; 341 asm "xcv_outside_seq", $cv->OUTSIDE_SEQ; 342 asm "xcv_depth", $cv->DEPTH; 343} 344 345sub B::FM::bsave { 346 my ($form,$ix) = @_; 347 348 $form->B::CV::bsave($ix); 349 asm "xfm_lines", $form->LINES; 350} 351 352sub B::AV::bsave { 353 my ($av,$ix) = @_; 354 return $av->B::PVMG::bsave($ix) if $av->MAGICAL; 355 my @array = $av->ARRAY; 356 $_ = $_->ix for @array; 357 my $stashix = $av->SvSTASH->ix; 358 359 nice "-AV-", 360 asm "ldsv", $varix = $ix unless $ix == $varix; 361 asm "av_extend", $av->MAX if $av->MAX >= 0; 362 asm "av_pushx", $_ for @array; 363 asm "sv_refcnt", $av->REFCNT; 364 asm "xav_flags", $av->AvFLAGS; 365 asm "xmg_stash", $stashix; 366} 367 368sub B::GV::desired { 369 my $gv = shift; 370 my ($cv, $form); 371 $files{$gv->FILE} && $gv->LINE 372 || ${$cv = $gv->CV} && $files{$cv->FILE} 373 || ${$form = $gv->FORM} && $files{$form->FILE} 374} 375 376sub B::HV::bwalk { 377 my $hv = shift; 378 return if $walked{$$hv}++; 379 my %stash = $hv->ARRAY; 380 while (my($k,$v) = each %stash) { 381 if ($v->SvTYPE == SVt_PVGV) { 382 my $hash = $v->HV; 383 if ($$hash && $hash->NAME) { 384 $hash->bwalk; 385 } 386 $v->ix(1) if desired $v; 387 } else { 388 nice "[prototype]"; 389 asm "gv_fetchpvx", cstring $hv->NAME . "::$k"; 390 $svtab{$$v} = $varix = $tix; 391 $v->bsave($tix++); 392 asm "sv_flags", $v->FLAGS; 393 } 394 } 395} 396 397###################################################### 398 399 400sub B::OP::bsave_thin { 401 my ($op, $ix) = @_; 402 my $next = $op->next; 403 my $nextix = $optab{$$next}; 404 $nextix = 0, push @cloop, $op unless defined $nextix; 405 if ($ix != $opix) { 406 nice '-'.$op->name.'-', 407 asm "ldop", $opix = $ix; 408 } 409 asm "op_next", $nextix; 410 asm "op_targ", $op->targ if $op->type; # tricky 411 asm "op_flags", $op->flags; 412 asm "op_private", $op->private; 413} 414 415sub B::OP::bsave; 416 *B::OP::bsave = *B::OP::bsave_thin; 417 418sub B::UNOP::bsave { 419 my ($op, $ix) = @_; 420 my $name = $op->name; 421 my $flags = $op->flags; 422 my $first = $op->first; 423 my $firstix = 424 $name =~ /fl[io]p/ 425 # that's just neat 426 || (!ITHREADS && $name eq 'regcomp') 427 # trick for /$a/o in pp_regcomp 428 || $name eq 'rv2sv' 429 && $op->flags & OPf_MOD 430 && $op->private & OPpLVAL_INTRO 431 # change #18774 made my life hard 432 ? $first->ix 433 : 0; 434 435 $op->B::OP::bsave($ix); 436 asm "op_first", $firstix; 437} 438 439sub B::BINOP::bsave { 440 my ($op, $ix) = @_; 441 if ($op->name eq 'aassign' && $op->private & B::OPpASSIGN_HASH()) { 442 my $last = $op->last; 443 my $lastix = do { 444 local *B::OP::bsave = *B::OP::bsave_fat; 445 local *B::UNOP::bsave = *B::UNOP::bsave_fat; 446 $last->ix; 447 }; 448 asm "ldop", $lastix unless $lastix == $opix; 449 asm "op_targ", $last->targ; 450 $op->B::OP::bsave($ix); 451 asm "op_last", $lastix; 452 } else { 453 $op->B::OP::bsave($ix); 454 } 455} 456 457# not needed if no pseudohashes 458 459*B::BINOP::bsave = *B::OP::bsave if VERSION >= 5.009; 460 461# deal with sort / formline 462 463sub B::LISTOP::bsave { 464 my ($op, $ix) = @_; 465 my $name = $op->name; 466 sub blocksort() { OPf_SPECIAL|OPf_STACKED } 467 if ($name eq 'sort' && ($op->flags & blocksort) == blocksort) { 468 my $first = $op->first; 469 my $pushmark = $first->sibling; 470 my $rvgv = $pushmark->first; 471 my $leave = $rvgv->first; 472 473 my $leaveix = $leave->ix; 474 475 my $rvgvix = $rvgv->ix; 476 asm "ldop", $rvgvix unless $rvgvix == $opix; 477 asm "op_first", $leaveix; 478 479 my $pushmarkix = $pushmark->ix; 480 asm "ldop", $pushmarkix unless $pushmarkix == $opix; 481 asm "op_first", $rvgvix; 482 483 my $firstix = $first->ix; 484 asm "ldop", $firstix unless $firstix == $opix; 485 asm "op_sibling", $pushmarkix; 486 487 $op->B::OP::bsave($ix); 488 asm "op_first", $firstix; 489 } elsif ($name eq 'formline') { 490 $op->B::UNOP::bsave_fat($ix); 491 } else { 492 $op->B::OP::bsave($ix); 493 } 494} 495 496# fat versions 497 498sub B::OP::bsave_fat { 499 my ($op, $ix) = @_; 500 my $siblix = $op->sibling->ix; 501 502 $op->B::OP::bsave_thin($ix); 503 asm "op_sibling", $siblix; 504 # asm "op_seq", -1; XXX don't allocate OPs piece by piece 505} 506 507sub B::UNOP::bsave_fat { 508 my ($op,$ix) = @_; 509 my $firstix = $op->first->ix; 510 511 $op->B::OP::bsave($ix); 512 asm "op_first", $firstix; 513} 514 515sub B::BINOP::bsave_fat { 516 my ($op,$ix) = @_; 517 my $last = $op->last; 518 my $lastix = $op->last->ix; 519 if (VERSION < 5.009 && $op->name eq 'aassign' && $last->name eq 'null') { 520 asm "ldop", $lastix unless $lastix == $opix; 521 asm "op_targ", $last->targ; 522 } 523 524 $op->B::UNOP::bsave($ix); 525 asm "op_last", $lastix; 526} 527 528sub B::LOGOP::bsave { 529 my ($op,$ix) = @_; 530 my $otherix = $op->other->ix; 531 532 $op->B::UNOP::bsave($ix); 533 asm "op_other", $otherix; 534} 535 536sub B::PMOP::bsave { 537 my ($op,$ix) = @_; 538 my ($rrop, $rrarg, $rstart); 539 540 # my $pmnextix = $op->pmnext->ix; # XXX 541 542 if (ITHREADS) { 543 if ($op->name eq 'subst') { 544 $rrop = "op_pmreplroot"; 545 $rrarg = $op->pmreplroot->ix; 546 $rstart = $op->pmreplstart->ix; 547 } elsif ($op->name eq 'pushre') { 548 $rrop = "op_pmreplrootpo"; 549 $rrarg = $op->pmreplroot; 550 } 551 $op->B::BINOP::bsave($ix); 552 asm "op_pmstashpv", pvix $op->pmstashpv; 553 } else { 554 $rrop = "op_pmreplrootgv"; 555 $rrarg = $op->pmreplroot->ix; 556 $rstart = $op->pmreplstart->ix if $op->name eq 'subst'; 557 my $stashix = $op->pmstash->ix; 558 $op->B::BINOP::bsave($ix); 559 asm "op_pmstash", $stashix; 560 } 561 562 asm $rrop, $rrarg if $rrop; 563 asm "op_pmreplstart", $rstart if $rstart; 564 565 asm "op_pmflags", $op->pmflags; 566 asm "op_pmpermflags", $op->pmpermflags; 567 asm "op_pmdynflags", $op->pmdynflags; 568 # asm "op_pmnext", $pmnextix; # XXX 569 asm "newpv", pvstring $op->precomp; 570 asm "pregcomp"; 571} 572 573sub B::SVOP::bsave { 574 my ($op,$ix) = @_; 575 my $svix = $op->sv->ix; 576 577 $op->B::OP::bsave($ix); 578 asm "op_sv", $svix; 579} 580 581sub B::PADOP::bsave { 582 my ($op,$ix) = @_; 583 584 $op->B::OP::bsave($ix); 585 asm "op_padix", $op->padix; 586} 587 588sub B::PVOP::bsave { 589 my ($op,$ix) = @_; 590 $op->B::OP::bsave($ix); 591 return unless my $pv = $op->pv; 592 593 if ($op->name eq 'trans') { 594 asm "op_pv_tr", join ',', length($pv)/2, unpack("s*", $pv); 595 } else { 596 asm "newpv", pvstring $pv; 597 asm "op_pv"; 598 } 599} 600 601sub B::LOOP::bsave { 602 my ($op,$ix) = @_; 603 my $nextix = $op->nextop->ix; 604 my $lastix = $op->lastop->ix; 605 my $redoix = $op->redoop->ix; 606 607 $op->B::BINOP::bsave($ix); 608 asm "op_redoop", $redoix; 609 asm "op_nextop", $nextix; 610 asm "op_lastop", $lastix; 611} 612 613sub B::COP::bsave { 614 my ($cop,$ix) = @_; 615 my $warnix = $cop->warnings->ix; 616 my $ioix = $cop->io->ix; 617 if (ITHREADS) { 618 $cop->B::OP::bsave($ix); 619 asm "cop_stashpv", pvix $cop->stashpv; 620 asm "cop_file", pvix $cop->file; 621 } else { 622 my $stashix = $cop->stash->ix; 623 my $fileix = $cop->filegv->ix(1); 624 $cop->B::OP::bsave($ix); 625 asm "cop_stash", $stashix; 626 asm "cop_filegv", $fileix; 627 } 628 asm "cop_label", pvix $cop->label if $cop->label; # XXX AD 629 asm "cop_seq", $cop->cop_seq; 630 asm "cop_arybase", $cop->arybase; 631 asm "cop_line", $cop->line; 632 asm "cop_warnings", $warnix; 633 asm "cop_io", $ioix; 634} 635 636sub B::OP::opwalk { 637 my $op = shift; 638 my $ix = $optab{$$op}; 639 defined($ix) ? $ix : do { 640 my $ix; 641 my @oplist = $op->oplist; 642 push @cloop, undef; 643 $ix = $_->ix while $_ = pop @oplist; 644 while ($_ = pop @cloop) { 645 asm "ldop", $optab{$$_}; 646 asm "op_next", $optab{${$_->next}}; 647 } 648 $ix; 649 } 650} 651 652################################################# 653 654sub save_cq { 655 my $av; 656 if (($av=begin_av)->isa("B::AV")) { 657 if ($savebegins) { 658 for ($av->ARRAY) { 659 next unless $_->FILE eq $0; 660 asm "push_begin", $_->ix; 661 } 662 } else { 663 for ($av->ARRAY) { 664 next unless $_->FILE eq $0; 665 # XXX BEGIN { goto A while 1; A: } 666 for (my $op = $_->START; $$op; $op = $op->next) { 667 next unless $op->name eq 'require' || 668 # this kludge needed for tests 669 $op->name eq 'gv' && do { 670 my $gv = class($op) eq 'SVOP' ? 671 $op->gv : 672 (($_->PADLIST->ARRAY)[1]->ARRAY)[$op->padix]; 673 $$gv && $gv->NAME =~ /use_ok|plan/ 674 }; 675 asm "push_begin", $_->ix; 676 last; 677 } 678 } 679 } 680 } 681 if (($av=init_av)->isa("B::AV")) { 682 for ($av->ARRAY) { 683 next unless $_->FILE eq $0; 684 asm "push_init", $_->ix; 685 } 686 } 687 if (($av=end_av)->isa("B::AV")) { 688 for ($av->ARRAY) { 689 next unless $_->FILE eq $0; 690 asm "push_end", $_->ix; 691 } 692 } 693} 694 695sub compile { 696 my ($head, $scan, $T_inhinc, $keep_syn); 697 my $cwd = ''; 698 $files{$0} = 1; 699 sub keep_syn { 700 $keep_syn = 1; 701 *B::OP::bsave = *B::OP::bsave_fat; 702 *B::UNOP::bsave = *B::UNOP::bsave_fat; 703 *B::BINOP::bsave = *B::BINOP::bsave_fat; 704 *B::LISTOP::bsave = *B::LISTOP::bsave_fat; 705 } 706 sub bwarn { print STDERR "Bytecode.pm: @_\n" } 707 708 for (@_) { 709 if (/^-S/) { 710 *newasm = *endasm = sub { }; 711 *asm = sub { print " @_\n" }; 712 *nice = sub ($) { print "\n@_\n" }; 713 } elsif (/^-H/) { 714 require ByteLoader; 715 $head = "#! $^X\nuse ByteLoader $ByteLoader::VERSION;\n"; 716 } elsif (/^-k/) { 717 keep_syn; 718 } elsif (/^-o(.*)$/) { 719 open STDOUT, ">$1" or die "open $1: $!"; 720 } elsif (/^-f(.*)$/) { 721 $files{$1} = 1; 722 } elsif (/^-s(.*)$/) { 723 $scan = length($1) ? $1 : $0; 724 } elsif (/^-b/) { 725 $savebegins = 1; 726 # this is here for the testsuite 727 } elsif (/^-TI/) { 728 $T_inhinc = 1; 729 } elsif (/^-TF(.*)/) { 730 my $thatfile = $1; 731 *B::COP::file = sub { $thatfile }; 732 } else { 733 bwarn "Ignoring '$_' option"; 734 } 735 } 736 if ($scan) { 737 my $f; 738 if (open $f, $scan) { 739 while (<$f>) { 740 /^#\s*line\s+\d+\s+("?)(.*)\1/ and $files{$2} = 1; 741 /^#/ and next; 742 if (/\bgoto\b\s*[^&]/ && !$keep_syn) { 743 bwarn "keeping the syntax tree: \"goto\" op found"; 744 keep_syn; 745 } 746 } 747 } else { 748 bwarn "cannot rescan '$scan'"; 749 } 750 close $f; 751 } 752 binmode STDOUT; 753 return sub { 754 print $head if $head; 755 newasm sub { print @_ }; 756 757 defstash->bwalk; 758 asm "main_start", main_start->opwalk; 759 asm "main_root", main_root->ix; 760 asm "main_cv", main_cv->ix; 761 asm "curpad", (comppadlist->ARRAY)[1]->ix; 762 763 asm "signal", cstring "__WARN__" # XXX 764 if warnhook->ix; 765 asm "incav", inc_gv->AV->ix if $T_inhinc; 766 save_cq; 767 asm "incav", inc_gv->AV->ix if $T_inhinc; 768 asm "dowarn", dowarn; 769 770 { 771 no strict 'refs'; 772 nice "<DATA>"; 773 my $dh = *{defstash->NAME."::DATA"}; 774 unless (eof $dh) { 775 local undef $/; 776 asm "data", ord 'D'; 777 print <$dh>; 778 } else { 779 asm "ret"; 780 } 781 } 782 783 endasm; 784 } 785} 786 7871; 788 789=head1 NAME 790 791B::Bytecode - Perl compiler's bytecode backend 792 793=head1 SYNOPSIS 794 795B<perl -MO=Bytecode>[B<,-H>][B<,-o>I<script.plc>] I<script.pl> 796 797=head1 DESCRIPTION 798 799Compiles a Perl script into a bytecode format that could be loaded 800later by the ByteLoader module and executed as a regular Perl script. 801 802=head1 EXAMPLE 803 804 $ perl -MO=Bytecode,-H,-ohi -e 'print "hi!\n"' 805 $ perl hi 806 hi! 807 808=head1 OPTIONS 809 810=over 4 811 812=item B<-b> 813 814Save all the BEGIN blocks. Normally only BEGIN blocks that C<require> 815other files (ex. C<use Foo;>) are saved. 816 817=item B<-H> 818 819prepend a C<use ByteLoader VERSION;> line to the produced bytecode. 820 821=item B<-k> 822 823keep the syntax tree - it is stripped by default. 824 825=item B<-o>I<outfile> 826 827put the bytecode in <outfile> instead of dumping it to STDOUT. 828 829=item B<-s> 830 831scan the script for C<# line ..> directives and for <goto LABEL> 832expressions. When gotos are found keep the syntax tree. 833 834=back 835 836=head1 KNOWN BUGS 837 838=over 4 839 840=item * 841 842C<BEGIN { goto A: while 1; A: }> won't even compile. 843 844=item * 845 846C<?...?> and C<reset> do not work as expected. 847 848=item * 849 850variables in C<(?{ ... })> constructs are not properly scoped. 851 852=item * 853 854scripts that use source filters will fail miserably. 855 856=back 857 858=head1 NOTICE 859 860There are also undocumented bugs and options. 861 862THIS CODE IS HIGHLY EXPERIMENTAL. USE AT YOUR OWN RISK. 863 864=head1 AUTHORS 865 866Originally written by Malcolm Beattie <mbeattie@sable.ox.ac.uk> and 867modified by Benjamin Stuhl <sho_pi@hotmail.com>. 868 869Rewritten by Enache Adrian <enache@rdslink.ro>, 2003 a.d. 870 871=cut 872