use
B
qw(main_cv main_root main_start comppadlist
class peekop walkoptree svref_2object cstring walksymtable
init_av begin_av end_av
SVf_POK SVp_POK SVf_IOK SVp_IOK SVf_NOK SVp_NOK
SVf_READONLY GVf_IMPORTED_AV GVf_IMPORTED_CV GVf_IMPORTED_HV
GVf_IMPORTED_SV SVTYPEMASK
)
;
my
%optype_enum
;
my
$i
;
for
(
$i
= 0 ;
$i
<
@optype
;
$i
++ ) {
$optype_enum
{
$optype
[
$i
] } =
$i
;
}
sub
POK () { SVf_POK | SVp_POK }
sub
IOK () { SVf_IOK | SVp_IOK }
sub
NOK () { SVf_NOK | SVp_NOK }
sub
GVf_IMPORTED_IO () { 0; }
sub
GVf_IMPORTED_FORM () { 0; }
my
(
$verbose
,
$no_assemble
,
$debug_bc
,
$debug_cv
);
my
@packages
;
sub
asm (@) {
if
(
$no_assemble
) {
print
@_
;
}
else
{
my
$buf
=
join
''
,
@_
;
assemble(
$_
)
for
(
split
/\n/,
$buf
);
}
}
sub
asmf (@) {
if
(
$no_assemble
) {
printf
shift
(),
@_
;
}
else
{
my
$format
=
shift
;
my
$buf
=
sprintf
$format
,
@_
;
assemble(
$_
)
for
(
split
/\n/,
$buf
);
}
}
my
(
$compress_nullops
,
$omit_seq
,
$bypass_nullops
);
my
%optimise
= (
compress_nullops
=> \
$compress_nullops
,
omit_sequence_numbers
=> \
$omit_seq
,
bypass_nullops
=> \
$bypass_nullops
);
my
$strip_syntree
;
my
$nextix
= 0;
my
%symtable
;
my
%saved
;
my
%strtable
;
my
$svix
= -1;
my
$opix
= -1;
sub
ldsv {
my
$ix
=
shift
;
if
(
$ix
!=
$svix
) {
asm
"ldsv $ix\n"
;
$svix
=
$ix
;
}
}
sub
stsv {
my
$ix
=
shift
;
asm
"stsv $ix\n"
;
$svix
=
$ix
;
}
sub
set_svix {
$svix
=
shift
;
}
sub
ldop {
my
$ix
=
shift
;
if
(
$ix
!=
$opix
) {
asm
"ldop $ix\n"
;
$opix
=
$ix
;
}
}
sub
stop {
my
$ix
=
shift
;
asm
"stop $ix\n"
;
$opix
=
$ix
;
}
sub
set_opix {
$opix
=
shift
;
}
sub
pvstring {
my
$str
=
shift
;
if
(
defined
(
$str
) ) {
return
cstring(
$str
.
"\0"
);
}
else
{
return
'""'
;
}
}
sub
nv {
my
$str
=
sprintf
"%.40f"
,
$_
[0];
$str
=~ s/0+$//;
$str
=~ s/\.$/.0/;
return
$str
;
}
sub
saved {
$saved
{ ${
$_
[0] } } }
sub
mark_saved {
$saved
{ ${
$_
[0] } } = 1 }
sub
unmark_saved {
$saved
{ ${
$_
[0] } } = 0 }
sub
debug {
$debug_bc
=
shift
}
sub
pvix {
return
$strtable
{
$_
[0] }
if
defined
(
$strtable
{
$_
[0] } );
asmf
"newpv %s\n"
, pvstring(
$_
[0] );
my
$ix
=
$nextix
++;
$strtable
{
$_
[0] } =
$ix
;
asmf
"stpv %d\n"
,
$ix
;
return
$ix
;
}
sub
B::OBJECT::nyi {
my
$obj
=
shift
;
warn
sprintf
(
"bytecode save method for %s (0x%x) not yet implemented\n"
,
class(
$obj
),
$$obj
);
}
sub
B::OBJECT::objix {
my
$obj
=
shift
;
my
$ix
=
$symtable
{
$$obj
};
if
(
defined
(
$ix
) ) {
return
$ix
;
}
else
{
$obj
->newix(
$nextix
);
return
$symtable
{
$$obj
} =
$nextix
++;
}
}
sub
B::SV::newix {
my
(
$sv
,
$ix
) =
@_
;
asmf
"newsv %d\t# %s\n"
,
$sv
->FLAGS & SVTYPEMASK, class(
$sv
);
stsv(
$ix
);
}
sub
B::GV::newix {
my
(
$gv
,
$ix
) =
@_
;
my
$gvname
=
$gv
->NAME;
my
$name
= cstring(
$gv
->STASH->NAME .
"::"
.
$gvname
);
asm
"gv_fetchpv $name\n"
;
stsv(
$ix
);
}
sub
B::HV::newix {
my
(
$hv
,
$ix
) =
@_
;
my
$name
=
$hv
->NAME;
if
(
$name
) {
asmf
"gv_stashpv %s\n"
, cstring(
$name
);
stsv(
$ix
);
}
else
{
$hv
->B::SV::newix(
$ix
);
}
}
sub
B::SPECIAL::newix {
my
(
$sv
,
$ix
) =
@_
;
asmf
"ldspecsv $$sv\t# %s\n"
,
$specialsv_name
[
$$sv
];
stsv(
$ix
);
}
sub
B::OP::newix {
my
(
$op
,
$ix
) =
@_
;
my
$class
= class(
$op
);
my
$typenum
=
$optype_enum
{
$class
};
croak(
"OP::newix: can't understand class $class"
)
unless
defined
(
$typenum
);
asm
"newop $typenum\t# $class\n"
;
stop(
$ix
);
}
sub
B::OP::walkoptree_debug {
my
$op
=
shift
;
warn
(
sprintf
(
"walkoptree: %s\n"
, peekop(
$op
) ) );
}
sub
B::OP::bytecode {
my
$op
=
shift
;
my
$next
=
$op
->
next
;
my
$nextix
;
my
$sibix
=
$op
->sibling->objix
unless
$strip_syntree
;
my
$ix
=
$op
->objix;
my
$type
=
$op
->type;
if
(
$bypass_nullops
) {
$next
=
$next
->
next
while
$$next
&&
$next
->type == 0;
}
$nextix
=
$next
->objix;
asmf
"# %s\n"
, peekop(
$op
)
if
$debug_bc
;
ldop(
$ix
);
asm
"op_next $nextix\n"
;
asm
"op_sibling $sibix\n"
unless
$strip_syntree
;
asmf
"op_type %s\t# %d\n"
,
"pp_"
.
$op
->name,
$type
;
asmf(
"op_seq %d\n"
,
$op
->seq )
unless
$omit_seq
;
if
(
$type
|| !
$compress_nullops
) {
asmf
"op_targ %d\nop_flags 0x%x\nop_private 0x%x\n"
,
$op
->targ,
$op
->flags,
$op
->private;
}
}
sub
B::UNOP::bytecode {
my
$op
=
shift
;
my
$firstix
=
$op
->first->objix
unless
$strip_syntree
;
$op
->B::OP::bytecode;
if
( (
$op
->type || !
$compress_nullops
) && !
$strip_syntree
) {
asm
"op_first $firstix\n"
;
}
}
sub
B::LOGOP::bytecode {
my
$op
=
shift
;
my
$otherix
=
$op
->other->objix;
$op
->B::UNOP::bytecode;
asm
"op_other $otherix\n"
;
}
sub
B::SVOP::bytecode {
my
$op
=
shift
;
my
$sv
=
$op
->sv;
my
$svix
=
$sv
->objix;
$op
->B::OP::bytecode;
asm
"op_sv $svix\n"
;
$sv
->bytecode;
}
sub
B::PADOP::bytecode {
my
$op
=
shift
;
my
$padix
=
$op
->padix;
$op
->B::OP::bytecode;
asm
"op_padix $padix\n"
;
}
sub
B::PVOP::bytecode {
my
$op
=
shift
;
my
$pv
=
$op
->pv;
$op
->B::OP::bytecode;
if
(
$op
->name eq
"trans"
) {
my
@shorts
=
unpack
(
"s256"
,
$pv
);
asm
"op_pv_tr "
,
join
(
","
,
@shorts
),
"\n"
;
}
else
{
asmf
"newpv %s\nop_pv\n"
, pvstring(
$pv
);
}
}
sub
B::BINOP::bytecode {
my
$op
=
shift
;
my
$lastix
=
$op
->
last
->objix
unless
$strip_syntree
;
$op
->B::UNOP::bytecode;
if
( (
$op
->type || !
$compress_nullops
) && !
$strip_syntree
) {
asm
"op_last $lastix\n"
;
}
}
sub
B::LOOP::bytecode {
my
$op
=
shift
;
my
$redoopix
=
$op
->redoop->objix;
my
$nextopix
=
$op
->nextop->objix;
my
$lastopix
=
$op
->lastop->objix;
$op
->B::LISTOP::bytecode;
asm
"op_redoop $redoopix\nop_nextop $nextopix\nop_lastop $lastopix\n"
;
}
sub
B::COP::bytecode {
my
$op
=
shift
;
my
$file
=
$op
->file;
my
$line
=
$op
->line;
if
(
$debug_bc
) {
asmf
"# line %s:%d\n"
,
$file
,
$line
;
}
my
$stashpv
=
$op
->stashpv;
my
$warnings
=
$op
->warnings;
my
$warningsix
=
$warnings
->objix;
my
$labelix
= pvix(
$op
->label );
my
$stashix
= pvix(
$stashpv
);
my
$fileix
= pvix(
$file
);
$warnings
->bytecode;
$op
->B::OP::bytecode;
asmf
<<"EOT", $labelix, $stashix, $op->cop_seq, $fileix, $op->arybase;
cop_label %d
cop_stashpv %d
cop_seq %d
cop_file %d
cop_arybase %d
cop_line $line
cop_warnings $warningsix
EOT
}
sub
B::PMOP::bytecode {
my
$op
=
shift
;
my
$replroot
=
$op
->pmreplroot;
my
$replrootix
=
$replroot
->objix;
my
$replstartix
=
$op
->pmreplstart->objix;
my
$opname
=
$op
->name;
if
(
$$replroot
) {
if
(
$opname
eq
"pushre"
) {
$replroot
->bytecode;
}
else
{
walkoptree(
$replroot
,
"bytecode"
);
}
}
$op
->B::LISTOP::bytecode;
if
(
$opname
eq
"pushre"
) {
asmf
"op_pmreplrootgv $replrootix\n"
;
}
else
{
asm
"op_pmreplroot $replrootix\nop_pmreplstart $replstartix\n"
;
}
my
$re
= pvstring(
$op
->precomp );
asmf
<<"EOT", $op->pmflags, $op->pmpermflags;
op_pmflags 0x%x
op_pmpermflags 0x%x
newpv $re
pregcomp
EOT
}
sub
B::SV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
my
$ix
=
$sv
->objix;
my
$refcnt
=
$sv
->REFCNT;
my
$flags
=
sprintf
(
"0x%x"
,
$sv
->FLAGS );
ldsv(
$ix
);
asm
"sv_refcnt $refcnt\nsv_flags $flags\n"
;
mark_saved(
$sv
);
}
sub
B::PV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
$sv
->B::SV::bytecode;
asmf(
"newpv %s\nxpv\n"
, pvstring(
$sv
->PV ) )
if
$sv
->FLAGS & POK;
}
sub
B::IV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
my
$iv
=
$sv
->IVX;
$sv
->B::SV::bytecode;
asmf
"%s $iv\n"
,
$sv
->needs64bits ?
"xiv64"
:
"xiv32"
if
$sv
->FLAGS & IOK;
}
sub
B::NV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
$sv
->B::SV::bytecode;
asmf
"xnv %s\n"
, nv(
$sv
->NVX );
}
sub
B::RV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
my
$rv
=
$sv
->RV;
my
$rvix
=
$rv
->objix;
$rv
->bytecode;
$sv
->B::SV::bytecode;
asm
"xrv $rvix\n"
;
}
sub
B::PVIV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
my
$iv
=
$sv
->IVX;
$sv
->B::PV::bytecode;
asmf
"%s $iv\n"
,
$sv
->needs64bits ?
"xiv64"
:
"xiv32"
;
}
sub
B::PVNV::bytecode {
my
$sv
=
shift
;
my
$flag
=
shift
|| 0;
return
if
saved(
$sv
);
if
(
$flag
== 2 ) {
$sv
->B::SV::bytecode;
}
else
{
my
$pv
=
$sv
->PV;
$sv
->B::IV::bytecode;
asmf
"xnv %s\n"
, nv(
$sv
->NVX );
if
(
$flag
== 1 ) {
$pv
.=
"\0"
.
$sv
->TABLE;
asmf
"newpv %s\npv_cur %d\nxpv\n"
, pvstring(
$pv
),
length
(
$pv
) - 257;
}
else
{
asmf(
"newpv %s\nxpv\n"
, pvstring(
$pv
) )
if
$sv
->FLAGS & POK;
}
}
}
sub
B::PVMG::bytecode {
my
(
$sv
,
$flag
) =
@_
;
return
if
saved(
$sv
);
my
$stashix
=
$sv
->SvSTASH->objix;
my
@mgchain
=
$sv
->MAGIC;
my
(
@mgobjix
,
$mg
);
@mgobjix
=
map
(
$_
->OBJ->objix,
@mgchain
);
$sv
->B::PVNV::bytecode(
$flag
);
asm
"xmg_stash $stashix\n"
;
foreach
$mg
(
@mgchain
) {
asmf
"sv_magic %s\nmg_obj %d\nnewpv %s\nmg_pv\n"
,
cstring(
$mg
->TYPE ),
shift
(
@mgobjix
), pvstring(
$mg
->PTR );
}
}
sub
B::PVLV::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
$sv
->B::PVMG::bytecode;
asmf
<<'EOT', $sv->TARGOFF, $sv->TARGLEN, cstring( $sv->TYPE );
xlv_targoff %d
xlv_targlen %d
xlv_type %s
EOT
}
sub
B::BM::bytecode {
my
$sv
=
shift
;
return
if
saved(
$sv
);
$sv
->B::PVMG::bytecode(1);
asmf
"xbm_useful %d\nxbm_previous %d\nxbm_rare %d\n"
,
$sv
->USEFUL,
$sv
->PREVIOUS,
$sv
->RARE;
}
sub
empty_gv {
my
$gv
=
shift
;
return
0
if
(
$gv
->SV->FLAGS & SVTYPEMASK );
my
@subfield_names
=
qw(AV HV CV FORM IO)
;
@subfield_names
=
grep
{
;
no
strict
'refs'
;
!(
$gv
->GvFLAGS & ${ \
"GVf_IMPORTED_$_"
}->() ) && ${
$gv
->
$_
() };
}
@subfield_names
;
return
scalar
@subfield_names
;
}
sub
B::GV::bytecode {
my
$gv
=
shift
;
return
if
saved(
$gv
);
return
unless
grep
{
$_
eq
$gv
->STASH->NAME; }
@packages
;
return
if
$gv
->NAME =~ m/^\(/;
my
$ix
=
$gv
->objix;
mark_saved(
$gv
);
ldsv(
$ix
);
asmf
<<"EOT", $gv->FLAGS, $gv->GvFLAGS;
sv_flags 0x%x
xgv_flags 0x%x
EOT
my
$refcnt
=
$gv
->REFCNT;
asmf(
"sv_refcnt_add %d\n"
,
$refcnt
- 1 )
if
$refcnt
> 1;
return
if
$gv
->is_empty;
asmf
<<"EOT", $gv->LINE, pvix( $gv->FILE );
gp_line %d
gp_file %d
EOT
my
$gvname
=
$gv
->NAME;
my
$name
= cstring(
$gv
->STASH->NAME .
"::"
.
$gvname
);
my
$egv
=
$gv
->EGV;
my
$egvix
=
$egv
->objix;
my
$gvrefcnt
=
$gv
->GvREFCNT;
asmf(
"gp_refcnt_add %d\n"
,
$gvrefcnt
- 1 )
if
$gvrefcnt
> 1;
if
(
$gvrefcnt
> 1 &&
$ix
!=
$egvix
) {
asm
"gp_share $egvix\n"
;
}
else
{
if
(
$gvname
!~ /^([^A-Za-z]|STDIN|STDOUT|STDERR|ARGV|SIG|ENV)$/ ) {
my
$i
;
my
@subfield_names
=
qw(SV AV HV CV FORM IO)
;
@subfield_names
=
grep
{
;
no
strict
'refs'
;
!(
$gv
->GvFLAGS & ${ \
"GVf_IMPORTED_$_"
}->() );
}
@subfield_names
;
my
@subfields
=
map
(
$gv
->
$_
(),
@subfield_names
);
my
@ixes
=
map
(
$_
->objix,
@subfields
);
ldsv(
$ix
);
for
(
$i
= 0 ;
$i
<
@ixes
;
$i
++ ) {
asmf
"gp_%s %d\n"
,
lc
(
$subfield_names
[
$i
] ),
$ixes
[
$i
];
}
my
$sv
;
foreach
$sv
(
@subfields
) {
$sv
->bytecode;
}
}
}
}
sub
B::HV::bytecode {
my
$hv
=
shift
;
return
if
saved(
$hv
);
mark_saved(
$hv
);
my
$name
=
$hv
->NAME;
my
$ix
=
$hv
->objix;
if
( !
$name
) {
my
@contents
=
$hv
->ARRAY;
my
(
$i
,
@ixes
);
for
(
$i
= 1 ;
$i
<
@contents
;
$i
+= 2 ) {
push
(
@ixes
,
$contents
[
$i
]->objix );
}
for
(
$i
= 1 ;
$i
<
@contents
;
$i
+= 2 ) {
$contents
[
$i
]->bytecode;
}
ldsv(
$ix
);
for
(
$i
= 0 ;
$i
<
@contents
;
$i
+= 2 ) {
asmf(
"newpv %s\nhv_store %d\n"
,
pvstring(
$contents
[
$i
] ),
$ixes
[
$i
/ 2 ]
);
}
asmf
"sv_refcnt %d\nsv_flags 0x%x\n"
,
$hv
->REFCNT,
$hv
->FLAGS;
}
}
sub
B::AV::bytecode {
my
$av
=
shift
;
return
if
saved(
$av
);
my
$ix
=
$av
->objix;
my
$fill
=
$av
->FILL;
my
$max
=
$av
->MAX;
my
(
@array
,
@ixes
);
if
(
$fill
> -1 ) {
@array
=
$av
->ARRAY;
@ixes
=
map
(
$_
->objix,
@array
);
my
$sv
;
foreach
$sv
(
@array
) {
$sv
->bytecode;
}
}
$av
->B::PVMG::bytecode(2);
ldsv(
$ix
);
asmf
"sv_flags 0x%x\n"
,
$av
->FLAGS & ~SVf_READONLY;
asmf
"xav_flags 0x%x\nxav_max -1\nxav_fill -1\n"
,
$av
->AvFLAGS;
if
(
$fill
> -1 ) {
my
$elix
;
foreach
$elix
(
@ixes
) {
asm
"av_push $elix\n"
;
}
}
else
{
if
(
$max
> -1 ) {
asm
"av_extend $max\n"
;
}
}
asmf
"sv_flags 0x%x\n"
,
$av
->FLAGS;
}
sub
B::CV::bytecode {
my
$cv
=
shift
;
return
if
saved(
$cv
);
return
if
${
$cv
->GV } && (
$cv
->GV->GvFLAGS & GVf_IMPORTED_CV );
my
$fileix
= pvix(
$cv
->FILE );
my
$ix
=
$cv
->objix;
$cv
->B::PVMG::bytecode;
my
$i
;
my
@subfield_names
=
qw(ROOT START STASH GV PADLIST OUTSIDE)
;
my
@subfields
=
map
(
$cv
->
$_
(),
@subfield_names
);
my
@ixes
=
map
(
$_
->objix,
@subfields
);
my
$root
=
shift
@subfields
;
if
(
$$root
) {
walkoptree(
$root
,
"bytecode"
);
}
ldsv(
$ix
);
for
(
$i
= 0 ;
$i
<
@ixes
;
$i
++ ) {
asmf
"xcv_%s %d\n"
,
lc
(
$subfield_names
[
$i
] ),
$ixes
[
$i
];
}
asmf
"xcv_depth %d\nxcv_flags 0x%x\n"
,
$cv
->DEPTH,
$cv
->CvFLAGS;
asmf
"xcv_file %d\n"
,
$fileix
;
shift
@subfields
;
my
$sv
;
foreach
$sv
(
@subfields
) {
$sv
->bytecode;
}
}
sub
B::IO::bytecode {
my
$io
=
shift
;
return
if
saved(
$io
);
my
$ix
=
$io
->objix;
my
$top_gv
=
$io
->TOP_GV;
my
$top_gvix
=
$top_gv
->objix;
my
$fmt_gv
=
$io
->FMT_GV;
my
$fmt_gvix
=
$fmt_gv
->objix;
my
$bottom_gv
=
$io
->BOTTOM_GV;
my
$bottom_gvix
=
$bottom_gv
->objix;
$io
->B::PVMG::bytecode;
ldsv(
$ix
);
asm
"xio_top_gv $top_gvix\n"
;
asm
"xio_fmt_gv $fmt_gvix\n"
;
asm
"xio_bottom_gv $bottom_gvix\n"
;
my
$field
;
foreach
$field
(
qw(TOP_NAME FMT_NAME BOTTOM_NAME)
) {
asmf
"newpv %s\nxio_%s\n"
, pvstring(
$io
->
$field
() ),
lc
(
$field
);
}
foreach
$field
(
qw(LINES PAGE PAGE_LEN LINES_LEFT SUBPROCESS)
) {
asmf
"xio_%s %d\n"
,
lc
(
$field
),
$io
->
$field
();
}
asmf
"xio_type %s\nxio_flags 0x%x\n"
, cstring(
$io
->IoTYPE ),
$io
->IoFLAGS;
$top_gv
->bytecode;
$fmt_gv
->bytecode;
$bottom_gv
->bytecode;
}
sub
B::SPECIAL::bytecode {
}
sub
bytecompile_object {
for
my
$sv
(
@_
) {
svref_2object(
$sv
)->bytecode;
}
}
sub
B::GV::bytecodecv {
my
$gv
=
shift
;
my
$cv
=
$gv
->CV;
if
(
$$cv
&& !saved(
$cv
) && !(
$gv
->FLAGS & GVf_IMPORTED_CV ) ) {
if
(
$debug_cv
) {
warn
sprintf
(
"saving extra CV &%s::%s (0x%x) from GV 0x%x\n"
,
$gv
->STASH->NAME,
$gv
->NAME,
$$cv
,
$$gv
);
}
$gv
->bytecode;
}
}
sub
save_call_queues {
if
( begin_av()->isa(
"B::AV"
) ) {
for
my
$cv
( begin_av()->ARRAY ) {
next
unless
grep
{
$_
eq
$cv
->STASH->NAME; }
@packages
;
my
$op
=
$cv
->START;
OPLOOP:
while
(
$$op
) {
if
(
$op
->name eq
'require'
) {
$cv
->bytecode;
asmf
"push_begin %d\n"
,
$cv
->objix;
last
OPLOOP;
}
$op
=
$op
->
next
;
}
}
}
if
( init_av()->isa(
"B::AV"
) ) {
for
my
$cv
( init_av()->ARRAY ) {
next
unless
grep
{
$_
eq
$cv
->STASH->NAME; }
@packages
;
$cv
->bytecode;
asmf
"push_init %d\n"
,
$cv
->objix;
}
}
if
( end_av()->isa(
"B::AV"
) ) {
for
my
$cv
( end_av()->ARRAY ) {
next
unless
grep
{
$_
eq
$cv
->STASH->NAME; }
@packages
;
$cv
->bytecode;
asmf
"push_end %d\n"
,
$cv
->objix;
}
}
}
sub
symwalk {
no
strict
'refs'
;
my
$ok
= 1
if
grep
{ (
my
$name
=
$_
[0] ) =~ s/::$//;
$_
eq
$name
; }
@packages
;
if
(
grep
{ /^
$_
[0]/; }
@packages
) {
walksymtable( \%{
"$_[0]"
},
"bytecodecv"
, \
&symwalk
,
$_
[0] );
}
warn
"considering $_[0] ... "
. (
$ok
?
"accepted\n"
:
"rejected\n"
)
if
$debug_bc
;
$ok
;
}
sub
bytecompile_main {
my
$curpad
= ( comppadlist->ARRAY )[1];
my
$curpadix
=
$curpad
->objix;
$curpad
->bytecode;
save_call_queues();
walkoptree( main_root,
"bytecode"
)
unless
ref
(main_root) eq
"B::NULL"
;
warn
"done main program, now walking symbol table\n"
if
$debug_bc
;
if
(
@packages
) {
no
strict
qw(refs)
;
walksymtable( \%{
"main::"
},
"bytecodecv"
, \
&symwalk
);
}
else
{
die
"No packages requested for compilation!\n"
;
}
asmf
"main_root %d\n"
, main_root->objix;
asmf
"main_start %d\n"
, main_start->objix;
asmf
"curpad $curpadix\n"
;
}
sub
compile {
my
@options
=
@_
;
my
(
$option
,
$opt
,
$arg
);
open
( OUT,
">&STDOUT"
);
binmode
OUT;
select
OUT;
OPTION:
while
(
$option
=
shift
@options
) {
if
(
$option
=~ /^-(.)(.*)/ ) {
$opt
= $1;
$arg
= $2;
}
else
{
unshift
@options
,
$option
;
last
OPTION;
}
if
(
$opt
eq
"-"
&&
$arg
eq
"-"
) {
shift
@options
;
last
OPTION;
}
elsif
(
$opt
eq
"o"
) {
$arg
||=
shift
@options
;
open
( OUT,
">$arg"
) or
return
"$arg: $!\n"
;
binmode
OUT;
}
elsif
(
$opt
eq
"a"
) {
$arg
||=
shift
@options
;
open
( OUT,
">>$arg"
) or
return
"$arg: $!\n"
;
binmode
OUT;
}
elsif
(
$opt
eq
"D"
) {
$arg
||=
shift
@options
;
foreach
$arg
(
split
( //,
$arg
) ) {
if
(
$arg
eq
"b"
) {
$| = 1;
debug(1);
}
elsif
(
$arg
eq
"o"
) {
B->debug(1);
}
elsif
(
$arg
eq
"a"
) {
B::Assembler::debug(1);
}
elsif
(
$arg
eq
"C"
) {
$debug_cv
= 1;
}
}
}
elsif
(
$opt
eq
"v"
) {
$verbose
= 1;
}
elsif
(
$opt
eq
"S"
) {
$no_assemble
= 1;
}
elsif
(
$opt
eq
"f"
) {
$arg
||=
shift
@options
;
my
$value
=
$arg
!~ s/^
no
-//;
$arg
=~ s/-/_/g;
my
$ref
=
$optimise
{
$arg
};
if
(
defined
(
$ref
) ) {
$$ref
=
$value
;
}
else
{
warn
qq(ignoring unknown optimisation option "$arg"\n)
;
}
}
elsif
(
$opt
eq
"O"
) {
$arg
= 1
if
$arg
eq
""
;
my
$ref
;
foreach
$ref
(
values
%optimise
) {
$$ref
= 0;
}
if
(
$arg
>= 2 ) {
$bypass_nullops
= 1;
}
if
(
$arg
>= 1 ) {
$compress_nullops
= 1;
$omit_seq
= 1;
}
}
elsif
(
$opt
eq
"u"
) {
$arg
||=
shift
@options
;
push
@packages
,
$arg
;
}
else
{
warn
qq(ignoring unknown option "$opt$arg"\n)
;
}
}
if
( !
@packages
) {
warn
"No package specified for compilation, assuming main::\n"
;
@packages
=
qw(main)
;
}
if
(
@options
) {
die
"Extraneous options left on B::Bytecode commandline: @options\n"
;
}
else
{
return
sub
{
newasm( \
&apr
)
unless
$no_assemble
;
bytecompile_main();
endasm()
unless
$no_assemble
;
};
}
}
sub
apr {
print
@_
; }
1;