diff options
Diffstat (limited to 'contrib/perl5/ext/B')
23 files changed, 2480 insertions, 1362 deletions
diff --git a/contrib/perl5/ext/B/B.pm b/contrib/perl5/ext/B/B.pm index 75dcfb3..4512d91 100644 --- a/contrib/perl5/ext/B/B.pm +++ b/contrib/perl5/ext/B/B.pm @@ -6,15 +6,15 @@ # License or the Artistic License, as specified in the README file. # package B; -require DynaLoader; +use XSLoader (); require Exporter; -@ISA = qw(Exporter DynaLoader); -@EXPORT_OK = qw(byteload_fh byteload_string minus_c ppname +@ISA = qw(Exporter); +@EXPORT_OK = qw(minus_c ppname class peekop cast_I32 cstring cchar hash threadsv_names - main_root main_start main_cv svref_2object + main_root main_start main_cv svref_2object opnumber amagic_generation walkoptree walkoptree_slow walkoptree_exec walksymtable parents comppadlist sv_undef compile_stats timing_info init_av); - +sub OPf_KIDS (); use strict; @B::SV::ISA = 'B::OBJECT'; @B::NULL::ISA = 'B::SV'; @@ -38,10 +38,9 @@ use strict; @B::UNOP::ISA = 'B::OP'; @B::BINOP::ISA = 'B::UNOP'; @B::LOGOP::ISA = 'B::UNOP'; -@B::CONDOP::ISA = 'B::UNOP'; @B::LISTOP::ISA = 'B::BINOP'; @B::SVOP::ISA = 'B::OP'; -@B::GVOP::ISA = 'B::OP'; +@B::PADOP::ISA = 'B::OP'; @B::PVOP::ISA = 'B::OP'; @B::CVOP::ISA = 'B::OP'; @B::LOOP::ISA = 'B::LISTOP'; @@ -65,10 +64,6 @@ sub debug { walkoptree_debug($value); } -# sub OPf_KIDS; -# add to .xs for perl5.002 -sub OPf_KIDS () { 4 } - sub class { my $obj = shift; my $name = ref $obj; @@ -81,7 +76,7 @@ sub parents { \@parents } # For debugging sub peekop { my $op = shift; - return sprintf("%s (0x%x) %s", class($op), $$op, $op->ppaddr); + return sprintf("%s (0x%x) %s", class($op), $$op, $op->name); } sub walkoptree_slow { @@ -112,6 +107,11 @@ sub timing_info { } my %symtable; + +sub clearsym { + %symtable = (); +} + sub savesym { my ($obj, $value) = @_; # warn(sprintf("savesym: sym_%x => %s\n", $$obj, $value)); # debug @@ -135,37 +135,26 @@ sub walkoptree_exec { } savesym($op, sprintf("%s (0x%lx)", class($op), $$op)); $op->$method($level); - $ppname = $op->ppaddr; - if ($ppname =~ /^pp_(or|and|mapwhile|grepwhile|entertry)$/) { + $ppname = $op->name; + if ($ppname =~ + /^(or|and|mapwhile|grepwhile|entertry|range|cond_expr)$/) + { print $prefix, uc($1), " => {\n"; walkoptree_exec($op->other, $method, $level + 1); print $prefix, "}\n"; - } elsif ($ppname eq "pp_match" || $ppname eq "pp_subst") { + } elsif ($ppname eq "match" || $ppname eq "subst") { my $pmreplstart = $op->pmreplstart; if ($$pmreplstart) { print $prefix, "PMREPLSTART => {\n"; walkoptree_exec($pmreplstart, $method, $level + 1); print $prefix, "}\n"; } - } elsif ($ppname eq "pp_substcont") { + } elsif ($ppname eq "substcont") { print $prefix, "SUBSTCONT => {\n"; walkoptree_exec($op->other->pmreplstart, $method, $level + 1); print $prefix, "}\n"; $op = $op->other; - } elsif ($ppname eq "pp_cond_expr") { - # pp_cond_expr never returns op_next - print $prefix, "TRUE => {\n"; - walkoptree_exec($op->true, $method, $level + 1); - print $prefix, "}\n"; - $op = $op->false; - redo; - } elsif ($ppname eq "pp_range") { - print $prefix, "TRUE => {\n"; - walkoptree_exec($op->true, $method, $level + 1); - print $prefix, "}\n", $prefix, "FALSE => {\n"; - walkoptree_exec($op->false, $method, $level + 1); - print $prefix, "}\n"; - } elsif ($ppname eq "pp_enterloop") { + } elsif ($ppname eq "enterloop") { print $prefix, "REDO => {\n"; walkoptree_exec($op->redoop, $method, $level + 1); print $prefix, "}\n", $prefix, "NEXT => {\n"; @@ -173,7 +162,7 @@ sub walkoptree_exec { print $prefix, "}\n", $prefix, "LAST => {\n"; walkoptree_exec($op->lastop, $method, $level + 1); print $prefix, "}\n"; - } elsif ($ppname eq "pp_subst") { + } elsif ($ppname eq "subst") { my $replstart = $op->pmreplstart; if ($$replstart) { print $prefix, "SUBST => {\n"; @@ -187,9 +176,12 @@ sub walkoptree_exec { sub walksymtable { my ($symref, $method, $recurse, $prefix) = @_; my $sym; + my $ref; no strict 'vars'; local(*glob); - while (($sym, *glob) = each %$symref) { + $prefix = '' unless defined $prefix; + while (($sym, $ref) = each %$symref) { + *glob = "*main::".$prefix.$sym; if ($sym =~ /::$/) { $sym = $prefix . $sym; if ($sym ne "main::" && &$recurse($sym)) { @@ -267,7 +259,7 @@ sub walksymtable { } } -bootstrap B; +XSLoader::load 'B'; 1; @@ -428,6 +420,10 @@ C<REFCNT> (corresponding to the C function C<SvREFCNT>). =over 4 +=item is_empty + +This method returns TRUE if the GP field of the GV is NULL. + =item NAME =item STASH @@ -450,6 +446,8 @@ C<REFCNT> (corresponding to the C function C<SvREFCNT>). =item LINE +=item FILE + =item FILEGV =item GvREFCNT @@ -518,7 +516,7 @@ C<REFCNT> (corresponding to the C function C<SvREFCNT>). =item GV -=item FILEGV +=item FILE =item DEPTH @@ -556,8 +554,8 @@ C<REFCNT> (corresponding to the C function C<SvREFCNT>). =head2 OP-RELATED CLASSES -B::OP, B::UNOP, B::BINOP, B::LOGOP, B::CONDOP, B::LISTOP, B::PMOP, -B::SVOP, B::GVOP, B::PVOP, B::CVOP, B::LOOP, B::COP. +B::OP, B::UNOP, B::BINOP, B::LOGOP, B::LISTOP, B::PMOP, +B::SVOP, B::PADOP, B::PVOP, B::CVOP, B::LOOP, B::COP. These classes correspond in the obvious way to the underlying C structures of similar names. The inheritance hierarchy mimics the underlying C "inheritance". Access @@ -572,9 +570,14 @@ leading "class indication" prefix removed (op_). =item sibling +=item name + +This returns the op name as a string (e.g. "add", "rv2av"). + =item ppaddr -This returns the function name as a string (e.g. pp_add, pp_rv2av). +This returns the function name as a string (e.g. "PL_ppaddr[OP_ADD]", +"PL_ppaddr[OP_RV2AV]"). =item desc @@ -617,16 +620,6 @@ This returns the op description from the global C PL_op_desc array =back -=head2 B::CONDOP METHODS - -=over 4 - -=item true - -=item false - -=back - =head2 B::LISTOP METHOD =over 4 @@ -661,13 +654,15 @@ This returns the op description from the global C PL_op_desc array =item sv +=item gv + =back -=head2 B::GVOP METHOD +=head2 B::PADOP METHOD =over 4 -=item gv +=item padix =back @@ -699,7 +694,7 @@ This returns the op description from the global C PL_op_desc array =item stash -=item filegv +=item file =item cop_seq @@ -751,6 +746,10 @@ Returns the SV object corresponding to the C variable C<sv_yes>. Returns the SV object corresponding to the C variable C<sv_no>. +=item amagic_generation + +Returns the SV object corresponding to the C variable C<amagic_generation>. + =item walkoptree(OP, METHOD) Does a tree-walk of the syntax tree based at OP and calls METHOD on @@ -817,11 +816,6 @@ preceding the first "::". This is used to turn "B::UNOP" into In a perl compiled for threads, this returns a list of the special per-thread threadsv variables. -=item byteload_fh(FILEHANDLE) - -Load the contents of FILEHANDLE as bytecode. See documentation for -the B<Bytecode> module in F<B::Backend> for how to generate bytecode. - =back =head1 AUTHOR diff --git a/contrib/perl5/ext/B/B.xs b/contrib/perl5/ext/B/B.xs index 6610ae8..9e29855 100644 --- a/contrib/perl5/ext/B/B.xs +++ b/contrib/perl5/ext/B/B.xs @@ -7,18 +7,18 @@ * */ +#define PERL_NO_GET_CONTEXT #include "EXTERN.h" #include "perl.h" #include "XSUB.h" -#include "INTERN.h" #ifdef PERL_OBJECT -#undef op_name -#undef opargs -#undef op_desc -#define op_name (pPerl->Perl_get_op_names()) -#define opargs (pPerl->Perl_get_opargs()) -#define op_desc (pPerl->Perl_get_op_descs()) +#undef PL_op_name +#undef PL_opargs +#undef PL_op_desc +#define PL_op_name (get_op_names()) +#define PL_opargs (get_opargs()) +#define PL_op_desc (get_op_descs()) #endif #ifdef PerlIO @@ -53,15 +53,14 @@ typedef enum { OPc_UNOP, /* 2 */ OPc_BINOP, /* 3 */ OPc_LOGOP, /* 4 */ - OPc_CONDOP, /* 5 */ - OPc_LISTOP, /* 6 */ - OPc_PMOP, /* 7 */ - OPc_SVOP, /* 8 */ - OPc_GVOP, /* 9 */ - OPc_PVOP, /* 10 */ - OPc_CVOP, /* 11 */ - OPc_LOOP, /* 12 */ - OPc_COP /* 13 */ + OPc_LISTOP, /* 5 */ + OPc_PMOP, /* 6 */ + OPc_SVOP, /* 7 */ + OPc_PADOP, /* 8 */ + OPc_PVOP, /* 9 */ + OPc_CVOP, /* 10 */ + OPc_LOOP, /* 11 */ + OPc_COP /* 12 */ } opclass; static char *opclassnames[] = { @@ -70,11 +69,10 @@ static char *opclassnames[] = { "B::UNOP", "B::BINOP", "B::LOGOP", - "B::CONDOP", "B::LISTOP", "B::PMOP", "B::SVOP", - "B::GVOP", + "B::PADOP", "B::PVOP", "B::CVOP", "B::LOOP", @@ -83,8 +81,10 @@ static char *opclassnames[] = { static int walkoptree_debug = 0; /* Flag for walkoptree debug hook */ +static SV *specialsv_list[4]; + static opclass -cc_opclass(OP *o) +cc_opclass(pTHX_ OP *o) { if (!o) return OPc_NULL; @@ -95,7 +95,12 @@ cc_opclass(OP *o) if (o->op_type == OP_SASSIGN) return ((o->op_private & OPpASSIGN_BACKWARDS) ? OPc_UNOP : OPc_BINOP); - switch (opargs[o->op_type] & OA_CLASS_MASK) { +#ifdef USE_ITHREADS + if (o->op_type == OP_GV || o->op_type == OP_GVSV || o->op_type == OP_AELEMFAST) + return OPc_PADOP; +#endif + + switch (PL_opargs[o->op_type] & OA_CLASS_MASK) { case OA_BASEOP: return OPc_BASEOP; @@ -108,9 +113,6 @@ cc_opclass(OP *o) case OA_LOGOP: return OPc_LOGOP; - case OA_CONDOP: - return OPc_CONDOP; - case OA_LISTOP: return OPc_LISTOP; @@ -120,11 +122,19 @@ cc_opclass(OP *o) case OA_SVOP: return OPc_SVOP; - case OA_GVOP: - return OPc_GVOP; + case OA_PADOP: + return OPc_PADOP; - case OA_PVOP: - return OPc_PVOP; + case OA_PVOP_OR_SVOP: + /* + * Character translations (tr///) are usually a PVOP, keeping a + * pointer to a table of shorts used to look up translations. + * Under utf8, however, a simple table isn't practical; instead, + * the OP is an SVOP, and the SV is a reference to a swash + * (i.e., an RV pointing to an HV). + */ + return (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF)) + ? OPc_SVOP : OPc_PVOP; case OA_LOOP: return OPc_LOOP; @@ -150,11 +160,14 @@ cc_opclass(OP *o) * return OPc_UNOP so that walkoptree can find our children. If * OPf_KIDS is not set then we check OPf_REF. Without OPf_REF set * (no argument to the operator) it's an OP; with OPf_REF set it's - * a GVOP (and op_gv is the GV for the filehandle argument). + * an SVOP (and op_sv is the GV for the filehandle argument). */ return ((o->op_flags & OPf_KIDS) ? OPc_UNOP : - (o->op_flags & OPf_REF) ? OPc_GVOP : OPc_BASEOP); - +#ifdef USE_ITHREADS + (o->op_flags & OPf_REF) ? OPc_PADOP : OPc_BASEOP); +#else + (o->op_flags & OPf_REF) ? OPc_SVOP : OPc_BASEOP); +#endif case OA_LOOPEXOP: /* * next, last, redo, dump and goto use OPf_SPECIAL to indicate that a @@ -173,47 +186,47 @@ cc_opclass(OP *o) return OPc_PVOP; } warn("can't determine class of operator %s, assuming BASEOP\n", - op_name[o->op_type]); + PL_op_name[o->op_type]); return OPc_BASEOP; } static char * -cc_opclassname(OP *o) +cc_opclassname(pTHX_ OP *o) { - return opclassnames[cc_opclass(o)]; + return opclassnames[cc_opclass(aTHX_ o)]; } static SV * -make_sv_object(SV *arg, SV *sv) +make_sv_object(pTHX_ SV *arg, SV *sv) { char *type = 0; IV iv; - for (iv = 0; iv < sizeof(PL_specialsv_list)/sizeof(SV*); iv++) { - if (sv == PL_specialsv_list[iv]) { + for (iv = 0; iv < sizeof(specialsv_list)/sizeof(SV*); iv++) { + if (sv == specialsv_list[iv]) { type = "B::SPECIAL"; break; } } if (!type) { type = svclassnames[SvTYPE(sv)]; - iv = (IV)sv; + iv = PTR2IV(sv); } sv_setiv(newSVrv(arg, type), iv); return arg; } static SV * -make_mg_object(SV *arg, MAGIC *mg) +make_mg_object(pTHX_ SV *arg, MAGIC *mg) { - sv_setiv(newSVrv(arg, "B::MAGIC"), (IV)mg); + sv_setiv(newSVrv(arg, "B::MAGIC"), PTR2IV(mg)); return arg; } static SV * -cstring(SV *sv) +cstring(pTHX_ SV *sv) { - SV *sstr = newSVpv("", 0); + SV *sstr = newSVpvn("", 0); STRLEN len; char *s; @@ -264,9 +277,9 @@ cstring(SV *sv) } static SV * -cchar(SV *sv) +cchar(pTHX_ SV *sv) { - SV *sstr = newSVpv("'", 0); + SV *sstr = newSVpvn("'", 1); STRLEN n_a; char *s = SvPV(sv, n_a); @@ -303,76 +316,8 @@ cchar(SV *sv) return sstr; } -#ifdef INDIRECT_BGET_MACROS -void freadpv(U32 len, void *data) -{ - New(666, pv.xpv_pv, len, char); - fread(pv.xpv_pv, 1, len, (FILE*)data); - pv.xpv_len = len; - pv.xpv_cur = len - 1; -} - -void byteload_fh(InputStream fp) -{ - struct bytestream bs; - bs.data = fp; - bs.fgetc = (int(*) _((void*)))fgetc; - bs.fread = (int(*) _((char*,size_t,size_t,void*)))fread; - bs.freadpv = freadpv; - byterun(bs); -} - -static int fgetc_fromstring(void *data) -{ - char **strp = (char **)data; - return *(*strp)++; -} - -static int fread_fromstring(char *argp, size_t elemsize, size_t nelem, - void *data) -{ - char **strp = (char **)data; - size_t len = elemsize * nelem; - - memcpy(argp, *strp, len); - *strp += len; - return (int)len; -} - -static void freadpv_fromstring(U32 len, void *data) -{ - char **strp = (char **)data; - - New(666, pv.xpv_pv, len, char); - memcpy(pv.xpv_pv, *strp, len); - pv.xpv_len = len; - pv.xpv_cur = len - 1; - *strp += len; -} - -void byteload_string(char *str) -{ - struct bytestream bs; - bs.data = &str; - bs.fgetc = fgetc_fromstring; - bs.fread = fread_fromstring; - bs.freadpv = freadpv_fromstring; - byterun(bs); -} -#else -void byteload_fh(InputStream fp) -{ - byterun(fp); -} - -void byteload_string(char *str) -{ - croak("Must compile with -DINDIRECT_BGET_MACROS for byteload_string"); -} -#endif /* INDIRECT_BGET_MACROS */ - void -walkoptree(SV *opsv, char *method) +walkoptree(pTHX_ SV *opsv, char *method) { dSP; OP *o; @@ -380,7 +325,7 @@ walkoptree(SV *opsv, char *method) if (!SvROK(opsv)) croak("opsv is not a reference"); opsv = sv_mortalcopy(opsv); - o = (OP*)SvIV((SV*)SvRV(opsv)); + o = INT2PTR(OP*,SvIV((SV*)SvRV(opsv))); if (walkoptree_debug) { PUSHMARK(sp); XPUSHs(opsv); @@ -395,8 +340,8 @@ walkoptree(SV *opsv, char *method) OP *kid; for (kid = ((UNOP*)o)->op_first; kid; kid = kid->op_sibling) { /* Use the same opsv. Rely on methods not to mess it up. */ - sv_setiv(newSVrv(opsv, cc_opclassname(kid)), (IV)kid); - walkoptree(opsv, method); + sv_setiv(newSVrv(opsv, cc_opclassname(aTHX_ kid)), PTR2IV(kid)); + walkoptree(aTHX_ opsv, method); } } } @@ -405,11 +350,10 @@ typedef OP *B__OP; typedef UNOP *B__UNOP; typedef BINOP *B__BINOP; typedef LOGOP *B__LOGOP; -typedef CONDOP *B__CONDOP; typedef LISTOP *B__LISTOP; typedef PMOP *B__PMOP; typedef SVOP *B__SVOP; -typedef GVOP *B__GVOP; +typedef PADOP *B__PADOP; typedef PVOP *B__PVOP; typedef LOOP *B__LOOP; typedef COP *B__COP; @@ -435,12 +379,21 @@ MODULE = B PACKAGE = B PREFIX = B_ PROTOTYPES: DISABLE BOOT: - INIT_SPECIALSV_LIST; +{ + HV *stash = gv_stashpvn("B", 1, TRUE); + AV *export_ok = perl_get_av("B::EXPORT_OK",TRUE); + specialsv_list[0] = Nullsv; + specialsv_list[1] = &PL_sv_undef; + specialsv_list[2] = &PL_sv_yes; + specialsv_list[3] = &PL_sv_no; +#include "defsubs.h" +} #define B_main_cv() PL_main_cv #define B_init_av() PL_initav #define B_main_root() PL_main_root #define B_main_start() PL_main_start +#define B_amagic_generation() PL_amagic_generation #define B_comppadlist() (PL_main_cv ? CvPADLIST(PL_main_cv) : CvPADLIST(PL_compcv)) #define B_sv_undef() &PL_sv_undef #define B_sv_yes() &PL_sv_yes @@ -458,6 +411,9 @@ B_main_root() B::OP B_main_start() +long +B_amagic_generation() + B::AV B_comppadlist() @@ -477,6 +433,8 @@ void walkoptree(opsv, method) SV * opsv char * method + CODE: + walkoptree(aTHX_ opsv, method); int walkoptree_debug(...) @@ -487,20 +445,7 @@ walkoptree_debug(...) OUTPUT: RETVAL -int -byteload_fh(fp) - InputStream fp - CODE: - byteload_fh(fp); - RETVAL = 1; - OUTPUT: - RETVAL - -void -byteload_string(str) - char * str - -#define address(sv) (IV)sv +#define address(sv) PTR2IV(sv) IV address(sv) @@ -514,7 +459,28 @@ svref_2object(sv) croak("argument is not a reference"); RETVAL = (SV*)SvRV(sv); OUTPUT: - RETVAL + RETVAL + +void +opnumber(name) +char * name +CODE: +{ + int i; + IV result = -1; + ST(0) = sv_newmortal(); + if (strncmp(name,"pp_",3) == 0) + name += 3; + for (i = 0; i < PL_maxo; i++) + { + if (strcmp(name, PL_op_name[i]) == 0) + { + result = i; + break; + } + } + sv_setiv(ST(0),result); +} void ppname(opnum) @@ -523,7 +489,7 @@ ppname(opnum) ST(0) = sv_newmortal(); if (opnum >= 0 && opnum < PL_maxo) { sv_setpvn(ST(0), "pp_", 3); - sv_catpv(ST(0), op_name[opnum]); + sv_catpv(ST(0), PL_op_name[opnum]); } void @@ -533,11 +499,10 @@ hash(sv) char *s; STRLEN len; U32 hash = 0; - char hexhash[11]; /* must fit "0xffffffff" plus trailing \0 */ + char hexhash[19]; /* must fit "0xffffffffffffffff" plus trailing \0 */ s = SvPV(sv, len); - while (len--) - hash = hash * 33 + *s++; - sprintf(hexhash, "0x%x", hash); + PERL_HASH(hash, s, len); + sprintf(hexhash, "0x%"UVxf, (UV)hash); ST(0) = sv_2mortal(newSVpv(hexhash, 0)); #define cast_I32(foo) (I32)foo @@ -553,10 +518,18 @@ minus_c() SV * cstring(sv) SV * sv + CODE: + RETVAL = cstring(aTHX_ sv); + OUTPUT: + RETVAL SV * cchar(sv) SV * sv + CODE: + RETVAL = cchar(aTHX_ sv); + OUTPUT: + RETVAL void threadsv_names() @@ -567,13 +540,13 @@ threadsv_names() EXTEND(sp, len); for (i = 0; i < len; i++) - PUSHs(sv_2mortal(newSVpv(&PL_threadsv_names[i], 1))); + PUSHs(sv_2mortal(newSVpvn(&PL_threadsv_names[i], 1))); #endif #define OP_next(o) o->op_next #define OP_sibling(o) o->op_sibling -#define OP_desc(o) op_desc[o->op_type] +#define OP_desc(o) PL_op_desc[o->op_type] #define OP_targ(o) o->op_targ #define OP_type(o) o->op_type #define OP_seq(o) o->op_seq @@ -591,18 +564,32 @@ OP_sibling(o) B::OP o char * -OP_ppaddr(o) +OP_name(o) B::OP o CODE: ST(0) = sv_newmortal(); - sv_setpvn(ST(0), "pp_", 3); - sv_catpv(ST(0), op_name[o->op_type]); + sv_setpv(ST(0), PL_op_name[o->op_type]); + + +char * +OP_ppaddr(o) + B::OP o + PREINIT: + int i; + SV *sv = sv_newmortal(); + CODE: + sv_setpvn(sv, "PL_ppaddr[OP_", 13); + sv_catpv(sv, PL_op_name[o->op_type]); + for (i=13; i<SvCUR(sv); ++i) + SvPVX(sv)[i] = toUPPER(SvPVX(sv)[i]); + sv_catpv(sv, "]"); + ST(0) = sv; char * OP_desc(o) B::OP o -U16 +PADOFFSET OP_targ(o) B::OP o @@ -646,19 +633,6 @@ B::OP LOGOP_other(o) B::LOGOP o -#define CONDOP_true(o) o->op_true -#define CONDOP_false(o) o->op_false - -MODULE = B PACKAGE = B::CONDOP PREFIX = CONDOP_ - -B::OP -CONDOP_true(o) - B::CONDOP o - -B::OP -CONDOP_false(o) - B::CONDOP o - #define LISTOP_children(o) o->op_children MODULE = B PACKAGE = B::LISTOP PREFIX = LISTOP_ @@ -687,10 +661,10 @@ PMOP_pmreplroot(o) if (o->op_type == OP_PUSHRE) { sv_setiv(newSVrv(ST(0), root ? svclassnames[SvTYPE((SV*)root)] : "B::SV"), - (IV)root); + PTR2IV(root)); } else { - sv_setiv(newSVrv(ST(0), cc_opclassname(root)), (IV)root); + sv_setiv(newSVrv(ST(0), cc_opclassname(aTHX_ root)), PTR2IV(root)); } B::OP @@ -719,23 +693,38 @@ PMOP_precomp(o) if (rx) sv_setpvn(ST(0), rx->precomp, rx->prelen); -#define SVOP_sv(o) o->op_sv +#define SVOP_sv(o) cSVOPo->op_sv +#define SVOP_gv(o) ((GV*)cSVOPo->op_sv) MODULE = B PACKAGE = B::SVOP PREFIX = SVOP_ - B::SV SVOP_sv(o) B::SVOP o -#define GVOP_gv(o) o->op_gv +B::GV +SVOP_gv(o) + B::SVOP o + +#define PADOP_padix(o) o->op_padix +#define PADOP_sv(o) (o->op_padix ? PL_curpad[o->op_padix] : Nullsv) +#define PADOP_gv(o) ((o->op_padix \ + && SvTYPE(PL_curpad[o->op_padix]) == SVt_PVGV) \ + ? (GV*)PL_curpad[o->op_padix] : Nullgv) + +MODULE = B PACKAGE = B::PADOP PREFIX = PADOP_ -MODULE = B PACKAGE = B::GVOP PREFIX = GVOP_ +PADOFFSET +PADOP_padix(o) + B::PADOP o +B::SV +PADOP_sv(o) + B::PADOP o B::GV -GVOP_gv(o) - B::GVOP o +PADOP_gv(o) + B::PADOP o MODULE = B PACKAGE = B::PVOP PREFIX = PVOP_ @@ -770,11 +759,13 @@ LOOP_lastop(o) B::LOOP o #define COP_label(o) o->cop_label -#define COP_stash(o) o->cop_stash -#define COP_filegv(o) o->cop_filegv +#define COP_stashpv(o) CopSTASHPV(o) +#define COP_stash(o) CopSTASH(o) +#define COP_file(o) CopFILE(o) #define COP_cop_seq(o) o->cop_seq #define COP_arybase(o) o->cop_arybase -#define COP_line(o) o->cop_line +#define COP_line(o) CopLINE(o) +#define COP_warnings(o) o->cop_warnings MODULE = B PACKAGE = B::COP PREFIX = COP_ @@ -782,12 +773,16 @@ char * COP_label(o) B::COP o +char * +COP_stashpv(o) + B::COP o + B::HV COP_stash(o) B::COP o -B::GV -COP_filegv(o) +char * +COP_file(o) B::COP o U32 @@ -802,6 +797,10 @@ U16 COP_line(o) B::COP o +B::SV +COP_warnings(o) + B::COP o + MODULE = B PACKAGE = B::SV PREFIX = Sv U32 @@ -822,6 +821,11 @@ IV SvIVX(sv) B::IV sv +UV +SvUVX(sv) + B::IV sv + + MODULE = B PACKAGE = B::IV #define needs64bits(sv) ((I32)SvIVX(sv) != SvIVX(sv)) @@ -844,12 +848,16 @@ packiv(sv) * reach this code anyway (unless sizeof(IV) > 8 but then * everything else breaks too so I'm not fussed at the moment). */ - wp[0] = htonl(((U32)iv) >> (sizeof(IV)*4)); +#ifdef UV_IS_QUAD + wp[0] = htonl(((UV)iv) >> (sizeof(UV)*4)); +#else + wp[0] = htonl(((U32)iv) >> (sizeof(UV)*4)); +#endif wp[1] = htonl(iv & 0xffffffff); - ST(0) = sv_2mortal(newSVpv((char *)wp, 8)); + ST(0) = sv_2mortal(newSVpvn((char *)wp, 8)); } else { U32 w = htonl((U32)SvIVX(sv)); - ST(0) = sv_2mortal(newSVpv((char *)&w, 4)); + ST(0) = sv_2mortal(newSVpvn((char *)&w, 4)); } MODULE = B PACKAGE = B::NV PREFIX = Sv @@ -877,6 +885,14 @@ SvPV(sv) ST(0) = sv_newmortal(); sv_setpvn(ST(0), SvPVX(sv), SvCUR(sv)); +STRLEN +SvLEN(sv) + B::PV sv + +STRLEN +SvCUR(sv) + B::PV sv + MODULE = B PACKAGE = B::PVMG PREFIX = Sv void @@ -885,7 +901,7 @@ SvMAGIC(sv) MAGIC * mg = NO_INIT PPCODE: for (mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) - XPUSHs(make_mg_object(sv_newmortal(), mg)); + XPUSHs(make_mg_object(aTHX_ sv_newmortal(), mg)); MODULE = B PACKAGE = B::PVMG @@ -898,6 +914,7 @@ SvSTASH(sv) #define MgTYPE(mg) mg->mg_type #define MgFLAGS(mg) mg->mg_flags #define MgOBJ(mg) mg->mg_obj +#define MgLENGTH(mg) mg->mg_len MODULE = B PACKAGE = B::MAGIC PREFIX = Mg @@ -921,13 +938,23 @@ B::SV MgOBJ(mg) B::MAGIC mg +I32 +MgLENGTH(mg) + B::MAGIC mg + void MgPTR(mg) B::MAGIC mg CODE: ST(0) = sv_newmortal(); - if (mg->mg_ptr) - sv_setpvn(ST(0), mg->mg_ptr, mg->mg_len); + if (mg->mg_ptr){ + if (mg->mg_len >= 0){ + sv_setpvn(ST(0), mg->mg_ptr, mg->mg_len); + } else { + if (mg->mg_len == HEf_SVKEY) + sv_setsv(ST(0),newRV((SV*)mg->mg_ptr)); + } + } MODULE = B PACKAGE = B::PVLV PREFIX = Lv @@ -969,7 +996,7 @@ BmTABLE(sv) CODE: str = SvPV(sv, len); /* Boyer-Moore table is just after string and its safety-margin \0 */ - ST(0) = sv_2mortal(newSVpv(str + len + 1, 256)); + ST(0) = sv_2mortal(newSVpvn(str + len + 1, 256)); MODULE = B PACKAGE = B::GV PREFIX = Gv @@ -977,7 +1004,15 @@ void GvNAME(gv) B::GV gv CODE: - ST(0) = sv_2mortal(newSVpv(GvNAME(gv), GvNAMELEN(gv))); + ST(0) = sv_2mortal(newSVpvn(GvNAME(gv), GvNAMELEN(gv))); + +bool +is_empty(gv) + B::GV gv + CODE: + RETVAL = GvGP(gv) == Null(GP*); + OUTPUT: + RETVAL B::HV GvSTASH(gv) @@ -1019,6 +1054,10 @@ U16 GvLINE(gv) B::GV gv +char * +GvFILE(gv) + B::GV gv + B::GV GvFILEGV(gv) B::GV gv @@ -1113,7 +1152,7 @@ AvARRAY(av) SV **svp = AvARRAY(av); I32 i; for (i = 0; i <= AvFILL(av); i++) - XPUSHs(make_sv_object(sv_newmortal(), svp[i])); + XPUSHs(make_sv_object(aTHX_ sv_newmortal(), svp[i])); } MODULE = B PACKAGE = B::AV @@ -1140,8 +1179,8 @@ B::GV CvGV(cv) B::CV cv -B::GV -CvFILEGV(cv) +char * +CvFILE(cv) B::CV cv long @@ -1160,7 +1199,7 @@ void CvXSUB(cv) B::CV cv CODE: - ST(0) = sv_2mortal(newSViv((IV)CvXSUB(cv))); + ST(0) = sv_2mortal(newSViv(PTR2IV(CvXSUB(cv)))); void @@ -1213,7 +1252,7 @@ HvARRAY(hv) (void)hv_iterinit(hv); EXTEND(sp, HvKEYS(hv) * 2); while (sv = hv_iternextsv(hv, &key, &len)) { - PUSHs(newSVpv(key, len)); - PUSHs(make_sv_object(sv_newmortal(), sv)); + PUSHs(newSVpvn(key, len)); + PUSHs(make_sv_object(aTHX_ sv_newmortal(), sv)); } } diff --git a/contrib/perl5/ext/B/B/Asmdata.pm b/contrib/perl5/ext/B/B/Asmdata.pm index f3e57a1..bc0eda9 100644 --- a/contrib/perl5/ext/B/B/Asmdata.pm +++ b/contrib/perl5/ext/B/B/Asmdata.pm @@ -1,5 +1,5 @@ # -# Copyright (c) 1996-1998 Malcolm Beattie +# Copyright (c) 1996-1999 Malcolm Beattie # # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the README file. @@ -12,9 +12,9 @@ package B::Asmdata; use Exporter; @ISA = qw(Exporter); @EXPORT_OK = qw(%insn_data @insn_name @optype @specialsv_name); -use vars qw(%insn_data @insn_name @optype @specialsv_name); +our(%insn_data, @insn_name, @optype, @specialsv_name); -@optype = qw(OP UNOP BINOP LOGOP CONDOP LISTOP PMOP SVOP GVOP PVOP LOOP COP); +@optype = qw(OP UNOP BINOP LOGOP LISTOP PMOP SVOP PADOP PVOP LOOP COP); @specialsv_name = qw(Nullsv &PL_sv_undef &PL_sv_yes &PL_sv_no); # XXX insn_data is initialised this way because with a large @@ -42,7 +42,7 @@ $insn_data{xrv} = [17, \&PUT_svindex, "GET_svindex"]; $insn_data{xpv} = [18, \&PUT_none, "GET_none"]; $insn_data{xiv32} = [19, \&PUT_I32, "GET_I32"]; $insn_data{xiv64} = [20, \&PUT_IV64, "GET_IV64"]; -$insn_data{xnv} = [21, \&PUT_double, "GET_double"]; +$insn_data{xnv} = [21, \&PUT_NV, "GET_NV"]; $insn_data{xlv_targoff} = [22, \&PUT_U32, "GET_U32"]; $insn_data{xlv_targlen} = [23, \&PUT_U32, "GET_U32"]; $insn_data{xlv_targ} = [24, \&PUT_svindex, "GET_svindex"]; @@ -68,11 +68,11 @@ $insn_data{xcv_stash} = [44, \&PUT_svindex, "GET_svindex"]; $insn_data{xcv_start} = [45, \&PUT_opindex, "GET_opindex"]; $insn_data{xcv_root} = [46, \&PUT_opindex, "GET_opindex"]; $insn_data{xcv_gv} = [47, \&PUT_svindex, "GET_svindex"]; -$insn_data{xcv_filegv} = [48, \&PUT_svindex, "GET_svindex"]; +$insn_data{xcv_file} = [48, \&PUT_pvcontents, "GET_pvcontents"]; $insn_data{xcv_depth} = [49, \&PUT_I32, "GET_I32"]; $insn_data{xcv_padlist} = [50, \&PUT_svindex, "GET_svindex"]; $insn_data{xcv_outside} = [51, \&PUT_svindex, "GET_svindex"]; -$insn_data{xcv_flags} = [52, \&PUT_U8, "GET_U8"]; +$insn_data{xcv_flags} = [52, \&PUT_U16, "GET_U16"]; $insn_data{av_extend} = [53, \&PUT_I32, "GET_I32"]; $insn_data{av_push} = [54, \&PUT_svindex, "GET_svindex"]; $insn_data{xav_fill} = [55, \&PUT_I32, "GET_I32"]; @@ -95,7 +95,7 @@ $insn_data{gp_refcnt_add} = [71, \&PUT_I32, "GET_I32"]; $insn_data{gp_av} = [72, \&PUT_svindex, "GET_svindex"]; $insn_data{gp_hv} = [73, \&PUT_svindex, "GET_svindex"]; $insn_data{gp_cv} = [74, \&PUT_svindex, "GET_svindex"]; -$insn_data{gp_filegv} = [75, \&PUT_svindex, "GET_svindex"]; +$insn_data{gp_file} = [75, \&PUT_pvcontents, "GET_pvcontents"]; $insn_data{gp_io} = [76, \&PUT_svindex, "GET_svindex"]; $insn_data{gp_form} = [77, \&PUT_svindex, "GET_svindex"]; $insn_data{gp_cvgen} = [78, \&PUT_U32, "GET_U32"]; @@ -113,32 +113,31 @@ $insn_data{op_private} = [89, \&PUT_U8, "GET_U8"]; $insn_data{op_first} = [90, \&PUT_opindex, "GET_opindex"]; $insn_data{op_last} = [91, \&PUT_opindex, "GET_opindex"]; $insn_data{op_other} = [92, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_true} = [93, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_false} = [94, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_children} = [95, \&PUT_U32, "GET_U32"]; -$insn_data{op_pmreplroot} = [96, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_pmreplrootgv} = [97, \&PUT_svindex, "GET_svindex"]; -$insn_data{op_pmreplstart} = [98, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_pmnext} = [99, \&PUT_opindex, "GET_opindex"]; -$insn_data{pregcomp} = [100, \&PUT_pvcontents, "GET_pvcontents"]; -$insn_data{op_pmflags} = [101, \&PUT_U16, "GET_U16"]; -$insn_data{op_pmpermflags} = [102, \&PUT_U16, "GET_U16"]; -$insn_data{op_sv} = [103, \&PUT_svindex, "GET_svindex"]; -$insn_data{op_gv} = [104, \&PUT_svindex, "GET_svindex"]; -$insn_data{op_pv} = [105, \&PUT_pvcontents, "GET_pvcontents"]; -$insn_data{op_pv_tr} = [106, \&PUT_op_tr_array, "GET_op_tr_array"]; -$insn_data{op_redoop} = [107, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_nextop} = [108, \&PUT_opindex, "GET_opindex"]; -$insn_data{op_lastop} = [109, \&PUT_opindex, "GET_opindex"]; -$insn_data{cop_label} = [110, \&PUT_pvcontents, "GET_pvcontents"]; -$insn_data{cop_stash} = [111, \&PUT_svindex, "GET_svindex"]; -$insn_data{cop_filegv} = [112, \&PUT_svindex, "GET_svindex"]; -$insn_data{cop_seq} = [113, \&PUT_U32, "GET_U32"]; -$insn_data{cop_arybase} = [114, \&PUT_I32, "GET_I32"]; -$insn_data{cop_line} = [115, \&PUT_U16, "GET_U16"]; -$insn_data{main_start} = [116, \&PUT_opindex, "GET_opindex"]; -$insn_data{main_root} = [117, \&PUT_opindex, "GET_opindex"]; -$insn_data{curpad} = [118, \&PUT_svindex, "GET_svindex"]; +$insn_data{op_children} = [93, \&PUT_U32, "GET_U32"]; +$insn_data{op_pmreplroot} = [94, \&PUT_opindex, "GET_opindex"]; +$insn_data{op_pmreplrootgv} = [95, \&PUT_svindex, "GET_svindex"]; +$insn_data{op_pmreplstart} = [96, \&PUT_opindex, "GET_opindex"]; +$insn_data{op_pmnext} = [97, \&PUT_opindex, "GET_opindex"]; +$insn_data{pregcomp} = [98, \&PUT_pvcontents, "GET_pvcontents"]; +$insn_data{op_pmflags} = [99, \&PUT_U16, "GET_U16"]; +$insn_data{op_pmpermflags} = [100, \&PUT_U16, "GET_U16"]; +$insn_data{op_sv} = [101, \&PUT_svindex, "GET_svindex"]; +$insn_data{op_padix} = [102, \&PUT_U32, "GET_U32"]; +$insn_data{op_pv} = [103, \&PUT_pvcontents, "GET_pvcontents"]; +$insn_data{op_pv_tr} = [104, \&PUT_op_tr_array, "GET_op_tr_array"]; +$insn_data{op_redoop} = [105, \&PUT_opindex, "GET_opindex"]; +$insn_data{op_nextop} = [106, \&PUT_opindex, "GET_opindex"]; +$insn_data{op_lastop} = [107, \&PUT_opindex, "GET_opindex"]; +$insn_data{cop_label} = [108, \&PUT_pvcontents, "GET_pvcontents"]; +$insn_data{cop_stashpv} = [109, \&PUT_pvcontents, "GET_pvcontents"]; +$insn_data{cop_file} = [110, \&PUT_pvcontents, "GET_pvcontents"]; +$insn_data{cop_seq} = [111, \&PUT_U32, "GET_U32"]; +$insn_data{cop_arybase} = [112, \&PUT_I32, "GET_I32"]; +$insn_data{cop_line} = [113, \&PUT_U16, "GET_U16"]; +$insn_data{cop_warnings} = [114, \&PUT_svindex, "GET_svindex"]; +$insn_data{main_start} = [115, \&PUT_opindex, "GET_opindex"]; +$insn_data{main_root} = [116, \&PUT_opindex, "GET_opindex"]; +$insn_data{curpad} = [117, \&PUT_svindex, "GET_svindex"]; my ($insn_name, $insn_data); while (($insn_name, $insn_data) = each %insn_data) { diff --git a/contrib/perl5/ext/B/B/Assembler.pm b/contrib/perl5/ext/B/B/Assembler.pm index 06e00ad..6c51a9a 100644 --- a/contrib/perl5/ext/B/B/Assembler.pm +++ b/contrib/perl5/ext/B/B/Assembler.pm @@ -52,6 +52,7 @@ sub B::Asmdata::PUT_U8 { sub B::Asmdata::PUT_U16 { pack("n", $_[0]) } sub B::Asmdata::PUT_U32 { pack("N", $_[0]) } sub B::Asmdata::PUT_I32 { pack("N", $_[0]) } +sub B::Asmdata::PUT_NV { sprintf("%lf\0", $_[0]) } sub B::Asmdata::PUT_objindex { pack("N", $_[0]) } # could allow names here sub B::Asmdata::PUT_svindex { &B::Asmdata::PUT_objindex } sub B::Asmdata::PUT_opindex { &B::Asmdata::PUT_objindex } diff --git a/contrib/perl5/ext/B/B/Bblock.pm b/contrib/perl5/ext/B/B/Bblock.pm index a54431b..fe7fc52 100644 --- a/contrib/perl5/ext/B/B/Bblock.pm +++ b/contrib/perl5/ext/B/B/Bblock.pm @@ -4,7 +4,9 @@ use Exporter (); @EXPORT_OK = qw(find_leaders); use B qw(peekop walkoptree walkoptree_exec - main_root main_start svref_2object); + main_root main_start svref_2object + OPf_SPECIAL OPf_STACKED ); + use B::Terse; use strict; @@ -18,11 +20,18 @@ sub mark_leader { } } +sub remove_sortblock{ + foreach (keys %$bblock){ + my $leader=$$bblock{$_}; + delete $$bblock{$_} if( $leader == 0); + } +} sub find_leaders { my ($root, $start) = @_; $bblock = {}; - mark_leader($start); - walkoptree($root, "mark_if_leader"); + mark_leader($start) if ( ref $start ne "B::NULL" ); + walkoptree($root, "mark_if_leader") if ((ref $root) ne "B::NULL") ; + remove_sortblock(); return $bblock; } @@ -81,25 +90,32 @@ sub B::LOOP::mark_if_leader { sub B::LOGOP::mark_if_leader { my $op = shift; - my $ppaddr = $op->ppaddr; + my $opname = $op->name; mark_leader($op->next); - if ($ppaddr eq "pp_entertry") { + if ($opname eq "entertry") { mark_leader($op->other->next); } else { mark_leader($op->other); } } -sub B::CONDOP::mark_if_leader { +sub B::LISTOP::mark_if_leader { my $op = shift; + my $first=$op->first; + $first=$first->next while ($first->name eq "null"); + mark_leader($op->first) unless (exists( $bblock->{$$first})); mark_leader($op->next); - mark_leader($op->true); - mark_leader($op->false); + if ($op->name eq "sort" and $op->flags & OPf_SPECIAL + and $op->flags & OPf_STACKED){ + my $root=$op->first->sibling->first; + my $leader=$root->first; + $bblock->{$$leader} = 0; + } } sub B::PMOP::mark_if_leader { my $op = shift; - if ($op->ppaddr ne "pp_pushre") { + if ($op->name ne "pushre") { my $replroot = $op->pmreplroot; if ($$replroot) { mark_leader($replroot); @@ -113,6 +129,7 @@ sub B::PMOP::mark_if_leader { sub compile { my @options = @_; + B::clearsym(); if (@options) { return sub { my $objname; @@ -134,7 +151,6 @@ sub compile { # The ops pointed at by nextop, redoop and lastop->op_next of a LOOP # The ops pointed at by op_next and op_other of a LOGOP, except # for pp_entertry which has op_next and op_other->op_next -# The ops pointed at by op_true and op_false of a CONDOP # The op pointed at by op_pmreplstart of a PMOP # The op pointed at by op_other->op_pmreplstart of pp_substcont? # [The op after a pp_return] Omit @@ -153,7 +169,9 @@ B::Bblock - Walk basic blocks =head1 DESCRIPTION -See F<ext/B/README>. +This module is used by the B::CC back end. It walks "basic blocks". +A basic block is a series of operations which is known to execute from +start to finish, with no possiblity of branching or halting. =head1 AUTHOR diff --git a/contrib/perl5/ext/B/B/Bytecode.pm b/contrib/perl5/ext/B/B/Bytecode.pm index 0c5a58d..27003b6 100644 --- a/contrib/perl5/ext/B/B/Bytecode.pm +++ b/contrib/perl5/ext/B/B/Bytecode.pm @@ -11,7 +11,9 @@ use Carp; use IO::File; use B qw(minus_c main_cv main_root main_start comppadlist - class peekop walkoptree svref_2object cstring walksymtable); + class peekop walkoptree svref_2object cstring walksymtable + SVf_POK SVp_POK SVf_IOK SVp_IOK + ); use B::Asmdata qw(@optype @specialsv_name); use B::Assembler qw(assemble_fh); @@ -23,11 +25,11 @@ for ($i = 0; $i < @optype; $i++) { # Following is SVf_POK|SVp_POK # XXX Shouldn't be hardwired -sub POK () { 0x04040000 } +sub POK () { SVf_POK|SVp_POK } -# Following is SVf_IOK|SVp_OK +# Following is SVf_IOK|SVp_IOK # XXX Shouldn't be hardwired -sub IOK () { 0x01010000 } +sub IOK () { SVf_IOK|SVp_IOK } my ($verbose, $module_only, $no_assemble, $debug_bc, $debug_cv); my $assembler_pid; @@ -191,7 +193,7 @@ sub B::OP::bytecode { ldop($ix); print "op_next $nextix\n"; print "op_sibling $sibix\n" unless $strip_syntree; - printf "op_type %s\t# %d\n", $op->ppaddr, $type; + printf "op_type %s\t# %d\n", "pp_" . $op->name, $type; printf("op_seq %d\n", $op->seq) unless $omit_seq; if ($type || !$compress_nullops) { printf "op_targ %d\nop_flags 0x%x\nop_private 0x%x\n", @@ -224,13 +226,11 @@ sub B::SVOP::bytecode { $sv->bytecode; } -sub B::GVOP::bytecode { +sub B::PADOP::bytecode { my $op = shift; - my $gv = $op->gv; - my $gvix = $gv->objix; + my $padix = $op->padix; $op->B::OP::bytecode; - print "op_gv $gvix\n"; - $gv->bytecode; + print "op_padix $padix\n"; } sub B::PVOP::bytecode { @@ -241,7 +241,7 @@ sub B::PVOP::bytecode { # This would be easy except that OP_TRANS uses a PVOP to store an # endian-dependent array of 256 shorts instead of a plain string. # - if ($op->ppaddr eq "pp_trans") { + if ($op->name eq "trans") { my @shorts = unpack("s256", $pv); # assembler handles endianness print "op_pv_tr ", join(",", @shorts), "\n"; } else { @@ -258,14 +258,6 @@ sub B::BINOP::bytecode { } } -sub B::CONDOP::bytecode { - my $op = shift; - my $trueix = $op->true->objix; - my $falseix = $op->false->objix; - $op->B::UNOP::bytecode; - print "op_true $trueix\nop_false $falseix\n"; -} - sub B::LISTOP::bytecode { my $op = shift; my $children = $op->children; @@ -286,26 +278,27 @@ sub B::LOOP::bytecode { sub B::COP::bytecode { my $op = shift; - my $stash = $op->stash; - my $stashix = $stash->objix; - my $filegv = $op->filegv; - my $filegvix = $filegv->objix; + my $stashpv = $op->stashpv; + my $file = $op->file; my $line = $op->line; + my $warnings = $op->warnings; + my $warningsix = $warnings->objix; if ($debug_bc) { - printf "# line %s:%d\n", $filegv->SV->PV, $line; + printf "# line %s:%d\n", $file, $line; } $op->B::OP::bytecode; - printf <<"EOT", pvstring($op->label), $op->cop_seq, $op->arybase; + printf <<"EOT", pvstring($op->label), pvstring($stashpv), $op->cop_seq, pvstring($file), $op->arybase; newpv %s cop_label -cop_stash $stashix +newpv %s +cop_stashpv cop_seq %d -cop_filegv $filegvix +newpv %s +cop_file cop_arybase %d cop_line $line +cop_warnings $warningsix EOT - $filegv->bytecode; - $stash->bytecode; } sub B::PMOP::bytecode { @@ -313,7 +306,7 @@ sub B::PMOP::bytecode { my $replroot = $op->pmreplroot; my $replrootix = $replroot->objix; my $replstartix = $op->pmreplstart->objix; - my $ppaddr = $op->ppaddr; + my $opname = $op->name; # pmnext is corrupt in some PMOPs (see misc.t for example) #my $pmnextix = $op->pmnext->objix; @@ -321,14 +314,14 @@ sub B::PMOP::bytecode { # OP_PUSHRE (a mutated version of OP_MATCH for the regexp # argument to a split) stores a GV in op_pmreplroot instead # of a substitution syntax tree. We don't want to walk that... - if ($ppaddr eq "pp_pushre") { + if ($opname eq "pushre") { $replroot->bytecode; } else { walkoptree($replroot, "bytecode"); } } $op->B::LISTOP::bytecode; - if ($ppaddr eq "pp_pushre") { + if ($opname eq "pushre") { printf "op_pmreplrootgv $replrootix\n"; } else { print "op_pmreplroot $replrootix\nop_pmreplstart $replstartix\n"; @@ -395,7 +388,8 @@ sub B::PVIV::bytecode { } sub B::PVNV::bytecode { - my ($sv, $flag) = @_; + my $sv = shift; + my $flag = shift || 0; # The $flag argument is passed through PVMG::bytecode by BM::bytecode # and AV::bytecode and indicates special handling. $flag = 1 is used by # BM::bytecode and means that we should ensure we save the whole B-M @@ -469,18 +463,23 @@ sub B::GV::bytecode { return if saved($gv); my $ix = $gv->objix; mark_saved($gv); - my $gvname = $gv->NAME; - my $name = cstring($gv->STASH->NAME . "::" . $gvname); - my $egv = $gv->EGV; - my $egvix = $egv->objix; ldsv($ix); - printf <<"EOT", $gv->FLAGS, $gv->GvFLAGS, $gv->LINE; + printf <<"EOT", $gv->FLAGS, $gv->GvFLAGS; sv_flags 0x%x xgv_flags 0x%x -gp_line %d EOT my $refcnt = $gv->REFCNT; printf("sv_refcnt_add %d\n", $refcnt - 1) if $refcnt > 1; + return if $gv->is_empty; + printf <<"EOT", $gv->LINE, pvstring($gv->FILE); +gp_line %d +newpv %s +gp_file +EOT + my $gvname = $gv->NAME; + my $name = cstring($gv->STASH->NAME . "::" . $gvname); + my $egv = $gv->EGV; + my $egvix = $egv->objix; my $gvrefcnt = $gv->GvREFCNT; printf("gp_refcnt_add %d\n", $gvrefcnt - 1) if $gvrefcnt > 1; if ($gvrefcnt > 1 && $ix != $egvix) { @@ -488,7 +487,7 @@ EOT } else { if ($gvname !~ /^([^A-Za-z]|STDIN|STDOUT|STDERR|ARGV|SIG|ENV)$/) { my $i; - my @subfield_names = qw(SV AV HV CV FILEGV FORM IO); + my @subfield_names = qw(SV AV HV CV FORM IO); my @subfields = map($gv->$_(), @subfield_names); my @ixes = map($_->objix, @subfields); # Reset sv register for $gv @@ -571,7 +570,7 @@ sub B::CV::bytecode { my $ix = $cv->objix; $cv->B::PVMG::bytecode; my $i; - my @subfield_names = qw(ROOT START STASH GV FILEGV PADLIST OUTSIDE); + my @subfield_names = qw(ROOT START STASH GV PADLIST OUTSIDE); my @subfields = map($cv->$_(), @subfield_names); my @ixes = map($_->objix, @subfields); # Save OP tree from CvROOT (first element of @subfields) @@ -584,7 +583,8 @@ sub B::CV::bytecode { for ($i = 0; $i < @ixes; $i++) { printf "xcv_%s %d\n", lc($subfield_names[$i]), $ixes[$i]; } - printf "xcv_depth %d\nxcv_flags 0x%x\n", $cv->DEPTH, $cv->FLAGS; + printf "xcv_depth %d\nxcv_flags 0x%x\n", $cv->DEPTH, $cv->CvFLAGS; + printf "newpv %s\nxcv_file\n", pvstring($cv->FILE); # Now save all the subfields (except for CvROOT which was handled # above) and CvSTART (now the initial element of @subfields). shift @subfields; # bye-bye CvSTART @@ -653,7 +653,7 @@ sub bytecompile_main { walkoptree(main_root, "bytecode"); warn "done main program, now walking symbol table\n" if $debug_bc; my ($pack, %exclude); - foreach $pack (qw(B O AutoLoader DynaLoader Config DB VMS strict vars + foreach $pack (qw(B O AutoLoader DynaLoader XSLoader Config DB VMS strict vars FileHandle Exporter Carp UNIVERSAL IO Fcntl Symbol SelectSaver blib Cwd)) { @@ -707,6 +707,10 @@ sub compile { $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)) { @@ -816,6 +820,10 @@ extra arguments, it saves the main program. Output to filename instead of STDOUT. +=item B<-afilename> + +Append output to filename. + =item B<--> Force end of options. @@ -889,13 +897,16 @@ C<main_root> and C<curpad> are omitted. =head1 EXAMPLES - perl -MO=Bytecode,-O6,-o,foo.plc foo.pl + perl -MO=Bytecode,-O6,-o,foo.plc foo.pl + + perl -MO=Bytecode,-S foo.pl > foo.S + assemble foo.S > foo.plc - perl -MO=Bytecode,-S foo.pl > foo.S - assemble foo.S > foo.plc - byteperl foo.plc +Note that C<assemble> lives in the C<B> subdirectory of your perl +library directory. The utility called perlcc may also be used to +help make use of this compiler. - perl -MO=Bytecode,-m,-oFoo.pmc Foo.pm + perl -MO=Bytecode,-m,-oFoo.pmc Foo.pm =head1 BUGS diff --git a/contrib/perl5/ext/B/B/C.pm b/contrib/perl5/ext/B/B/C.pm index e695cc2..d0c8159 100644 --- a/contrib/perl5/ext/B/B/C.pm +++ b/contrib/perl5/ext/B/B/C.pm @@ -5,34 +5,75 @@ # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the README file. # +package B::C::Section; +use B (); +use base B::Section; + +sub new +{ + my $class = shift; + my $o = $class->SUPER::new(@_); + push(@$o,[]); + return $o; +} + +sub add +{ + my $section = shift; + push(@{$section->[-1]},@_); +} + +sub index +{ + my $section = shift; + return scalar(@{$section->[-1]})-1; +} + +sub output +{ + my ($section, $fh, $format) = @_; + my $sym = $section->symtable || {}; + my $default = $section->default; + foreach (@{$section->[-1]}) + { + s{(s\\_[0-9a-f]+)}{ exists($sym->{$1}) ? $sym->{$1} : $default; }ge; + printf $fh $format, $_; + } +} + package B::C; use Exporter (); @ISA = qw(Exporter); -@EXPORT_OK = qw(output_all output_boilerplate output_main - init_sections set_callback save_unused_subs objsym); +@EXPORT_OK = qw(output_all output_boilerplate output_main mark_unused + init_sections set_callback save_unused_subs objsym save_context); use B qw(minus_c sv_undef walkoptree walksymtable main_root main_start peekop class cstring cchar svref_2object compile_stats comppadlist hash - threadsv_names main_cv init_av); + threadsv_names main_cv init_av opnumber amagic_generation + AVf_REAL HEf_SVKEY); use B::Asmdata qw(@specialsv_name); use FileHandle; use Carp; use strict; +use Config; my $hv_index = 0; my $gv_index = 0; my $re_index = 0; my $pv_index = 0; my $anonsub_index = 0; +my $initsub_index = 0; my %symtable; +my %xsub; my $warn_undefined_syms; my $verbose; -my @unused_sub_packages; +my %unused_sub_packages; my $nullop_count; -my $pv_copy_on_grow; +my $pv_copy_on_grow = 0; my ($debug_cops, $debug_av, $debug_cv, $debug_mg); +my $max_string_len; my @threadsv_names; BEGIN { @@ -40,11 +81,11 @@ BEGIN { } # Code sections -my ($init, $decl, $symsect, $binopsect, $condopsect, $copsect, $cvopsect, - $gvopsect, $listopsect, $logopsect, $loopsect, $opsect, $pmopsect, +my ($init, $decl, $symsect, $binopsect, $condopsect, $copsect, + $padopsect, $listopsect, $logopsect, $loopsect, $opsect, $pmopsect, $pvopsect, $svopsect, $unopsect, $svsect, $xpvsect, $xpvavsect, $xpvhvsect, $xpvcvsect, $xpvivsect, $xpvnvsect, $xpvmgsect, $xpvlvsect, - $xrvsect, $xpvbmsect, $xpviosect, $bootstrap); + $xrvsect, $xpvbmsect, $xpviosect ); sub walk_and_save_optree; my $saveoptree_callback = \&walk_and_save_optree; @@ -66,11 +107,9 @@ sub walk_and_save_optree { # to "know" that op_seq is a U16 and use 65535. Ugh. my $op_seq = 65535; -sub AVf_REAL () { 1 } - -# XXX This shouldn't really be hardcoded here but it saves -# looking up the name of every BASEOP in B::OP -sub OP_THREADSV () { 345 } +# Look this up here so we can do just a number compare +# rather than looking up the name of every BASEOP in B::OP +my $OP_THREADSV = opnumber('threadsv'); sub savesym { my ($obj, $value) = @_; @@ -98,10 +137,11 @@ sub getsym { } sub savepv { - my $pv = shift; + my $pv = shift; + $pv = '' unless defined $pv; # Is this sane ? my $pvsym = 0; my $pvmax = 0; - if ($pv_copy_on_grow) { + if ($pv_copy_on_grow) { my $cstring = cstring($pv); if ($cstring ne "0") { # sic $pvsym = sprintf("pv%d", $pv_index++); @@ -115,17 +155,21 @@ sub savepv { sub B::OP::save { my ($op, $level) = @_; + my $sym = objsym($op); + return $sym if defined $sym; my $type = $op->type; $nullop_count++ unless $type; - if ($type == OP_THREADSV) { + if ($type == $OP_THREADSV) { # saves looking up ppaddr but it's a bit naughty to hard code this $init->add(sprintf("(void)find_threadsv(%s);", cstring($threadsv_names[$op->targ]))); } - $opsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x", - ${$op->next}, ${$op->sibling}, $op->ppaddr, $op->targ, + $opsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x", + ${$op->next}, ${$op->sibling}, $op->targ, $type, $op_seq, $op->flags, $op->private)); - savesym($op, sprintf("&op_list[%d]", $opsect->index)); + my $ix = $opsect->index; + $init->add(sprintf("op_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "&op_list[$ix]"); } sub B::FAKEOP::new { @@ -135,10 +179,12 @@ sub B::FAKEOP::new { sub B::FAKEOP::save { my ($op, $level) = @_; - $opsect->add(sprintf("%s, %s, %s, %u, %u, %u, 0x%x, 0x%x", - $op->next, $op->sibling, $op->ppaddr, $op->targ, + $opsect->add(sprintf("%s, %s, NULL, %u, %u, %u, 0x%x, 0x%x", + $op->next, $op->sibling, $op->targ, $op->type, $op_seq, $op->flags, $op->private)); - return sprintf("&op_list[%d]", $opsect->index); + my $ix = $opsect->index; + $init->add(sprintf("op_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + return "&op_list[$ix]"; } sub B::FAKEOP::next { $_[0]->{"next"} || 0 } @@ -151,114 +197,139 @@ sub B::FAKEOP::private { $_[0]->{private} || 0 } sub B::UNOP::save { my ($op, $level) = @_; - $unopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + my $sym = objsym($op); + return $sym if defined $sym; + $unopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, s\\_%x", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, ${$op->first})); - savesym($op, sprintf("(OP*)&unop_list[%d]", $unopsect->index)); + my $ix = $unopsect->index; + $init->add(sprintf("unop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "(OP*)&unop_list[$ix]"); } sub B::BINOP::save { my ($op, $level) = @_; - $binopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + my $sym = objsym($op); + return $sym if defined $sym; + $binopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, ${$op->first}, ${$op->last})); - savesym($op, sprintf("(OP*)&binop_list[%d]", $binopsect->index)); + my $ix = $binopsect->index; + $init->add(sprintf("binop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "(OP*)&binop_list[$ix]"); } sub B::LISTOP::save { my ($op, $level) = @_; - $listopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, %u", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + my $sym = objsym($op); + return $sym if defined $sym; + $listopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, %u", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, ${$op->first}, ${$op->last}, $op->children)); - savesym($op, sprintf("(OP*)&listop_list[%d]", $listopsect->index)); + my $ix = $listopsect->index; + $init->add(sprintf("listop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "(OP*)&listop_list[$ix]"); } sub B::LOGOP::save { my ($op, $level) = @_; - $logopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + my $sym = objsym($op); + return $sym if defined $sym; + $logopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, ${$op->first}, ${$op->other})); - savesym($op, sprintf("(OP*)&logop_list[%d]", $logopsect->index)); -} - -sub B::CONDOP::save { - my ($op, $level) = @_; - $condopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, s\\_%x", - ${$op->next}, ${$op->sibling}, $op->ppaddr, - $op->targ, $op->type, $op_seq, $op->flags, - $op->private, ${$op->first}, ${$op->true}, - ${$op->false})); - savesym($op, sprintf("(OP*)&condop_list[%d]", $condopsect->index)); + my $ix = $logopsect->index; + $init->add(sprintf("logop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "(OP*)&logop_list[$ix]"); } sub B::LOOP::save { my ($op, $level) = @_; + my $sym = objsym($op); + return $sym if defined $sym; #warn sprintf("LOOP: redoop %s, nextop %s, lastop %s\n", # peekop($op->redoop), peekop($op->nextop), # peekop($op->lastop)); # debug - $loopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, %u, s\\_%x, s\\_%x, s\\_%x", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + $loopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, %u, s\\_%x, s\\_%x, s\\_%x", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, ${$op->first}, ${$op->last}, $op->children, ${$op->redoop}, ${$op->nextop}, ${$op->lastop})); - savesym($op, sprintf("(OP*)&loop_list[%d]", $loopsect->index)); + my $ix = $loopsect->index; + $init->add(sprintf("loop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "(OP*)&loop_list[$ix]"); } sub B::PVOP::save { my ($op, $level) = @_; - $pvopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, %s", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + my $sym = objsym($op); + return $sym if defined $sym; + $pvopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, %s", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, cstring($op->pv))); - savesym($op, sprintf("(OP*)&pvop_list[%d]", $pvopsect->index)); + my $ix = $pvopsect->index; + $init->add(sprintf("pvop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + savesym($op, "(OP*)&pvop_list[$ix]"); } sub B::SVOP::save { my ($op, $level) = @_; + my $sym = objsym($op); + return $sym if defined $sym; my $svsym = $op->sv->save; - $svopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, %s", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + $svopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, Nullsv", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, - $op->private, "(SV*)$svsym")); - savesym($op, sprintf("(OP*)&svop_list[%d]", $svopsect->index)); + $op->private)); + my $ix = $svopsect->index; + $init->add(sprintf("svop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + $init->add("svop_list[$ix].op_sv = (SV*)$svsym;"); + savesym($op, "(OP*)&svop_list[$ix]"); } -sub B::GVOP::save { +sub B::PADOP::save { my ($op, $level) = @_; - my $gvsym = $op->gv->save; - $gvopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, Nullgv", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + my $sym = objsym($op); + return $sym if defined $sym; + $padopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, 0", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private)); - $init->add(sprintf("gvop_list[%d].op_gv = %s;", $gvopsect->index, $gvsym)); - savesym($op, sprintf("(OP*)&gvop_list[%d]", $gvopsect->index)); + $init->add(sprintf("padop_list[%d].op_ppaddr = %s;", $padopsect->index, $op->ppaddr)); + my $ix = $padopsect->index; + $init->add(sprintf("padop_list[$ix].op_padix = %ld;", $op->padix)); + savesym($op, "(OP*)&padop_list[$ix]"); } sub B::COP::save { my ($op, $level) = @_; - my $gvsym = $op->filegv->save; - my $stashsym = $op->stash->save; - warn sprintf("COP: line %d file %s\n", $op->line, $op->filegv->SV->PV) + my $sym = objsym($op); + return $sym if defined $sym; + warn sprintf("COP: line %d file %s\n", $op->line, $op->file) if $debug_cops; - $copsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, %s, Nullhv, Nullgv, %u, %d, %u", - ${$op->next}, ${$op->sibling}, $op->ppaddr, + $copsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, %s, NULL, NULL, %u, %d, %u", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, cstring($op->label), $op->cop_seq, $op->arybase, $op->line)); - my $copix = $copsect->index; - $init->add(sprintf("cop_list[%d].cop_filegv = %s;", $copix, $gvsym), - sprintf("cop_list[%d].cop_stash = %s;", $copix, $stashsym)); - savesym($op, "(OP*)&cop_list[$copix]"); + my $ix = $copsect->index; + $init->add(sprintf("cop_list[$ix].op_ppaddr = %s;", $op->ppaddr)); + $init->add(sprintf("CopFILE_set(&cop_list[$ix], %s);", cstring($op->file)), + sprintf("CopSTASHPV_set(&cop_list[$ix], %s);", cstring($op->stashpv))); + savesym($op, "(OP*)&cop_list[$ix]"); } sub B::PMOP::save { my ($op, $level) = @_; + my $sym = objsym($op); + return $sym if defined $sym; my $replroot = $op->pmreplroot; my $replstart = $op->pmreplstart; my $replrootfield = sprintf("s\\_%x", $$replroot); @@ -269,7 +340,7 @@ sub B::PMOP::save { # OP_PUSHRE (a mutated version of OP_MATCH for the regexp # argument to a split) stores a GV in op_pmreplroot instead # of a substitution syntax tree. We don't want to walk that... - if ($ppaddr eq "pp_pushre") { + if ($op->name eq "pushre") { $gvsym = $replroot->save; # warn "PMOP::save saving a pp_pushre with GV $gvsym\n"; # debug $replrootfield = 0; @@ -280,13 +351,14 @@ sub B::PMOP::save { # pmnext handling is broken in perl itself, I think. Bad op_pmnext # fields aren't noticed in perl's runtime (unless you try reset) but we # segfault when trying to dereference it to find op->op_pmnext->op_type - $pmopsect->add(sprintf("s\\_%x, s\\_%x, %s, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, %u, %s, %s, 0, 0, 0x%x, 0x%x", - ${$op->next}, ${$op->sibling}, $ppaddr, $op->targ, + $pmopsect->add(sprintf("s\\_%x, s\\_%x, NULL, %u, %u, %u, 0x%x, 0x%x, s\\_%x, s\\_%x, %u, %s, %s, 0, 0, 0x%x, 0x%x", + ${$op->next}, ${$op->sibling}, $op->targ, $op->type, $op_seq, $op->flags, $op->private, ${$op->first}, ${$op->last}, $op->children, $replrootfield, $replstartfield, $op->pmflags, $op->pmpermflags,)); my $pm = sprintf("pmop_list[%d]", $pmopsect->index); + $init->add(sprintf("$pm.op_ppaddr = %s;", $ppaddr)); my $re = $op->precomp; if (defined($re)) { my $resym = sprintf("re%d", $re_index++); @@ -297,7 +369,7 @@ sub B::PMOP::save { if ($gvsym) { $init->add("$pm.op_pmreplroot = (OP*)$gvsym;"); } - savesym($op, sprintf("(OP*)&pmop_list[%d]", $pmopsect->index)); + savesym($op, "(OP*)&$pm"); } sub B::SPECIAL::save { @@ -319,10 +391,11 @@ sub B::NULL::save { return $sym if defined $sym; # warn "Saving SVt_NULL SV\n"; # debug # debug - #if ($$sv == 0) { - # warn "NULL::save for sv = 0 called from @{[(caller(1))[3]]}\n"; - #} - $svsect->add(sprintf("0, %u, 0x%x", $sv->REFCNT + 1, $sv->FLAGS)); + if ($$sv == 0) { + warn "NULL::save for sv = 0 called from @{[(caller(1))[3]]}\n"; + return savesym($sv, "Nullsv /* XXX */"); + } + $svsect->add(sprintf("0, %u, 0x%x", $sv->REFCNT , $sv->FLAGS)); return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } @@ -332,7 +405,7 @@ sub B::IV::save { return $sym if defined $sym; $xpvivsect->add(sprintf("0, 0, 0, %d", $sv->IVX)); $svsect->add(sprintf("&xpviv_list[%d], %lu, 0x%x", - $xpvivsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvivsect->index, $sv->REFCNT , $sv->FLAGS)); return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } @@ -340,12 +413,35 @@ sub B::NV::save { my ($sv) = @_; my $sym = objsym($sv); return $sym if defined $sym; - $xpvnvsect->add(sprintf("0, 0, 0, %d, %s", $sv->IVX, $sv->NVX)); + my $val= $sv->NVX; + $val .= '.00' if $val =~ /^-?\d+$/; + $xpvnvsect->add(sprintf("0, 0, 0, %d, %s", $sv->IVX, $val)); $svsect->add(sprintf("&xpvnv_list[%d], %lu, 0x%x", - $xpvnvsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvnvsect->index, $sv->REFCNT , $sv->FLAGS)); return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } +sub savepvn { + my ($dest,$pv) = @_; + my @res; + if (defined $max_string_len && length($pv) > $max_string_len) { + push @res, sprintf("New(0,%s,%u,char);", $dest, length($pv)+1); + my $offset = 0; + while (length $pv) { + my $str = substr $pv, 0, $max_string_len, ''; + push @res, sprintf("Copy(%s,$dest+$offset,%u,char);", + cstring($str), length($str)); + $offset += length $str; + } + push @res, sprintf("%s[%u] = '\\0';", $dest, $offset); + } + else { + push @res, sprintf("%s = savepvn(%s, %u);", $dest, + cstring($pv), length($pv)); + } + return @res; +} + sub B::PVLV::save { my ($sv) = @_; my $sym = objsym($sv); @@ -358,10 +454,10 @@ sub B::PVLV::save { $pvsym, $len, $pvmax, $sv->IVX, $sv->NVX, $sv->TARGOFF, $sv->TARGLEN, cchar($sv->TYPE))); $svsect->add(sprintf("&xpvlv_list[%d], %lu, 0x%x", - $xpvlvsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvlvsect->index, $sv->REFCNT , $sv->FLAGS)); if (!$pv_copy_on_grow) { - $init->add(sprintf("xpvlv_list[%d].xpv_pv = savepvn(%s, %u);", - $xpvlvsect->index, cstring($pv), $len)); + $init->add(savepvn(sprintf("xpvlv_list[%d].xpv_pv", + $xpvlvsect->index), $pv)); } $sv->save_magic; return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); @@ -376,10 +472,10 @@ sub B::PVIV::save { my ($pvsym, $pvmax) = savepv($pv); $xpvivsect->add(sprintf("%s, %u, %u, %d", $pvsym, $len, $pvmax, $sv->IVX)); $svsect->add(sprintf("&xpviv_list[%d], %u, 0x%x", - $xpvivsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvivsect->index, $sv->REFCNT , $sv->FLAGS)); if (!$pv_copy_on_grow) { - $init->add(sprintf("xpviv_list[%d].xpv_pv = savepvn(%s, %u);", - $xpvivsect->index, cstring($pv), $len)); + $init->add(savepvn(sprintf("xpviv_list[%d].xpv_pv", + $xpvivsect->index), $pv)); } return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } @@ -388,16 +484,19 @@ sub B::PVNV::save { my ($sv) = @_; my $sym = objsym($sv); return $sym if defined $sym; - my $pv = $sv->PV; + my $pv = $sv->PV; + $pv = '' unless defined $pv; my $len = length($pv); my ($pvsym, $pvmax) = savepv($pv); + my $val= $sv->NVX; + $val .= '.00' if $val =~ /^-?\d+$/; $xpvnvsect->add(sprintf("%s, %u, %u, %d, %s", - $pvsym, $len, $pvmax, $sv->IVX, $sv->NVX)); + $pvsym, $len, $pvmax, $sv->IVX, $val)); $svsect->add(sprintf("&xpvnv_list[%d], %lu, 0x%x", - $xpvnvsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvnvsect->index, $sv->REFCNT , $sv->FLAGS)); if (!$pv_copy_on_grow) { - $init->add(sprintf("xpvnv_list[%d].xpv_pv = savepvn(%s,%u);", - $xpvnvsect->index, cstring($pv), $len)); + $init->add(savepvn(sprintf("xpvnv_list[%d].xpv_pv", + $xpvnvsect->index), $pv)); } return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } @@ -412,10 +511,10 @@ sub B::BM::save { $len, $len + 258, $sv->IVX, $sv->NVX, $sv->USEFUL, $sv->PREVIOUS, $sv->RARE)); $svsect->add(sprintf("&xpvbm_list[%d], %lu, 0x%x", - $xpvbmsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvbmsect->index, $sv->REFCNT , $sv->FLAGS)); $sv->save_magic; - $init->add(sprintf("xpvbm_list[%d].xpv_pv = savepvn(%s, %u);", - $xpvbmsect->index, cstring($pv), $len), + $init->add(savepvn(sprintf("xpvbm_list[%d].xpv_pv", + $xpvbmsect->index), $pv), sprintf("xpvbm_list[%d].xpv_cur = %u;", $xpvbmsect->index, $len - 257)); return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); @@ -430,10 +529,10 @@ sub B::PV::save { my ($pvsym, $pvmax) = savepv($pv); $xpvsect->add(sprintf("%s, %u, %u", $pvsym, $len, $pvmax)); $svsect->add(sprintf("&xpv_list[%d], %lu, 0x%x", - $xpvsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvsect->index, $sv->REFCNT , $sv->FLAGS)); if (!$pv_copy_on_grow) { - $init->add(sprintf("xpv_list[%d].xpv_pv = savepvn(%s, %u);", - $xpvsect->index, cstring($pv), $len)); + $init->add(savepvn(sprintf("xpv_list[%d].xpv_pv", + $xpvsect->index), $pv)); } return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } @@ -448,10 +547,10 @@ sub B::PVMG::save { $xpvmgsect->add(sprintf("%s, %u, %u, %d, %s, 0, 0", $pvsym, $len, $pvmax, $sv->IVX, $sv->NVX)); $svsect->add(sprintf("&xpvmg_list[%d], %lu, 0x%x", - $xpvmgsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xpvmgsect->index, $sv->REFCNT , $sv->FLAGS)); if (!$pv_copy_on_grow) { - $init->add(sprintf("xpvmg_list[%d].xpv_pv = savepvn(%s, %u);", - $xpvmgsect->index, cstring($pv), $len)); + $init->add(savepvn(sprintf("xpvmg_list[%d].xpv_pv", + $xpvmgsect->index), $pv)); } $sym = savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); $sv->save_magic; @@ -462,6 +561,7 @@ sub B::PVMG::save_magic { my ($sv) = @_; #warn sprintf("saving magic for %s (0x%x)\n", class($sv), $$sv); # debug my $stash = $sv->SvSTASH; + $stash->save; if ($$stash) { warn sprintf("xmg_stash = %s (0x%x)\n", $stash->NAME, $$stash) if $debug_mg; @@ -469,19 +569,27 @@ sub B::PVMG::save_magic { $init->add(sprintf("SvSTASH(s\\_%x) = s\\_%x;", $$sv, $$stash)); } my @mgchain = $sv->MAGIC; - my ($mg, $type, $obj, $ptr); + my ($mg, $type, $obj, $ptr,$len,$ptrsv); foreach $mg (@mgchain) { $type = $mg->TYPE; $obj = $mg->OBJ; $ptr = $mg->PTR; - my $len = defined($ptr) ? length($ptr) : 0; + $len=$mg->LENGTH; if ($debug_mg) { warn sprintf("magic %s (0x%x), obj %s (0x%x), type %s, ptr %s\n", class($sv), $$sv, class($obj), $$obj, cchar($type), cstring($ptr)); } - $init->add(sprintf("sv_magic((SV*)s\\_%x, (SV*)s\\_%x, %s, %s, %d);", + $obj->save; + if ($len == HEf_SVKEY){ + #The pointer is an SV* + $ptrsv=svref_2object($ptr)->save; + $init->add(sprintf("sv_magic((SV*)s\\_%x, (SV*)s\\_%x, %s,(char *) %s, %d);", + $$sv, $$obj, cchar($type),$ptrsv,$len)); + }else{ + $init->add(sprintf("sv_magic((SV*)s\\_%x, (SV*)s\\_%x, %s, %s, %d);", $$sv, $$obj, cchar($type),cstring($ptr),$len)); + } } } @@ -489,9 +597,11 @@ sub B::RV::save { my ($sv) = @_; my $sym = objsym($sv); return $sym if defined $sym; - $xrvsect->add($sv->RV->save); + my $rv = $sv->RV->save; + $rv =~ s/^\([AGHS]V\s*\*\)\s*(\&sv_list.*)$/$1/; + $xrvsect->add($rv); $svsect->add(sprintf("&xrv_list[%d], %lu, 0x%x", - $xrvsect->index, $sv->REFCNT + 1, $sv->FLAGS)); + $xrvsect->index, $sv->REFCNT , $sv->FLAGS)); return savesym($sv, sprintf("&sv_list[%d]", $svsect->index)); } @@ -516,7 +626,7 @@ sub try_autoload { } } } - +sub Dummy_initxs{}; sub B::CV::save { my ($cv) = @_; my $sym = objsym($cv); @@ -525,18 +635,43 @@ sub B::CV::save { return $sym; } # Reserve a place in svsect and xpvcvsect and record indices + my $gv = $cv->GV; + my ($cvname, $cvstashname); + if ($$gv){ + $cvname = $gv->NAME; + $cvstashname = $gv->STASH->NAME; + } + my $root = $cv->ROOT; + my $cvxsub = $cv->XSUB; + #INIT is removed from the symbol table, so this call must come + # from PL_initav->save. Re-bootstrapping will push INIT back in + # so nullop should be sent. + if ($cvxsub && ($cvname ne "INIT")) { + my $egv = $gv->EGV; + my $stashname = $egv->STASH->NAME; + if ($cvname eq "bootstrap") + { + my $file = $gv->FILE; + $decl->add("/* bootstrap $file */"); + warn "Bootstrap $stashname $file\n"; + $xsub{$stashname}='Dynamic'; + # $xsub{$stashname}='Static' unless $xsub{$stashname}; + return qq/NULL/; + } + warn sprintf("stub for XSUB $cvstashname\:\:$cvname CV 0x%x\n", $$cv) if $debug_cv; + return qq/(perl_get_cv("$stashname\:\:$cvname",TRUE))/; + } + if ($cvxsub && $cvname eq "INIT") { + no strict 'refs'; + return svref_2object(\&Dummy_initxs)->save; + } my $sv_ix = $svsect->index + 1; $svsect->add("svix$sv_ix"); my $xpvcv_ix = $xpvcvsect->index + 1; $xpvcvsect->add("xpvcvix$xpvcv_ix"); # Save symbol now so that GvCV() doesn't recurse back to us via CvGV() $sym = savesym($cv, "&sv_list[$sv_ix]"); - warn sprintf("saving CV 0x%x as $sym\n", $$cv) if $debug_cv; - my $gv = $cv->GV; - my $cvstashname = $gv->STASH->NAME; - my $cvname = $gv->NAME; - my $root = $cv->ROOT; - my $cvxsub = $cv->XSUB; + warn sprintf("saving $cvstashname\:\:$cvname CV 0x%x as $sym\n", $$cv) if $debug_cv; if (!$$root && !$cvxsub) { if (try_autoload($cvstashname, $cvname)) { # Recalculate root and xsub @@ -564,6 +699,10 @@ sub B::CV::save { $ppname .= ($stashname eq "main") ? $gvname : "$stashname\::$gvname"; $ppname =~ s/::/__/g; + if ($gvname eq "INIT"){ + $ppname .= "_$initsub_index"; + $initsub_index++; + } } } if (!$ppname) { @@ -581,28 +720,19 @@ sub B::CV::save { $$padlist, $$cv) if $debug_cv; } } - elsif ($cvxsub) { - $xsubany = sprintf("ANYINIT((void*)0x%x)", $cv->XSUBANY); - # Try to find out canonical name of XSUB function from EGV. - # XXX Doesn't work for XSUBs with PREFIX set (or anyone who - # calls newXS() manually with weird arguments). - my $egv = $gv->EGV; - my $stashname = $egv->STASH->NAME; - $stashname =~ s/::/__/g; - $xsub = sprintf("XS_%s_%s", $stashname, $egv->NAME); - $decl->add("void $xsub _((CV*));"); - } else { warn sprintf("No definition for sub %s::%s (unable to autoload)\n", $cvstashname, $cvname); # debug - } - $symsect->add(sprintf("xpvcvix%d\t%s, %u, 0, %d, %s, 0, Nullhv, Nullhv, %s, s\\_%x, $xsub, $xsubany, Nullgv, Nullgv, %d, s\\_%x, (CV*)s\\_%x, 0x%x", + } + $pv = '' unless defined $pv; # Avoid use of undef warnings + $symsect->add(sprintf("xpvcvix%d\t%s, %u, 0, %d, %s, 0, Nullhv, Nullhv, %s, s\\_%x, $xsub, $xsubany, Nullgv, \"\", %d, s\\_%x, (CV*)s\\_%x, 0x%x", $xpvcv_ix, cstring($pv), length($pv), $cv->IVX, $cv->NVX, $startfield, ${$cv->ROOT}, $cv->DEPTH, $$padlist, ${$cv->OUTSIDE}, $cv->CvFLAGS)); if (${$cv->OUTSIDE} == ${main_cv()}){ $init->add(sprintf("CvOUTSIDE(s\\_%x)=PL_main_cv;",$$cv)); + $init->add(sprintf("SvREFCNT_inc(PL_main_cv);")); } if ($$gv) { @@ -611,13 +741,7 @@ sub B::CV::save { warn sprintf("done saving GV 0x%x for CV 0x%x\n", $$gv, $$cv) if $debug_cv; } - my $filegv = $cv->FILEGV; - if ($$filegv) { - $filegv->save; - $init->add(sprintf("CvFILEGV(s\\_%x) = s\\_%x;", $$cv, $$filegv)); - warn sprintf("done saving FILEGV 0x%x for CV 0x%x\n", - $$filegv, $$cv) if $debug_cv; - } + $init->add(sprintf("CvFILE($sym) = %s;", cstring($cv->FILE))); my $stash = $cv->STASH; if ($$stash) { $stash->save; @@ -626,7 +750,7 @@ sub B::CV::save { $$stash, $$cv) if $debug_cv; } $symsect->add(sprintf("svix%d\t(XPVCV*)&xpvcv_list[%u], %lu, 0x%x", - $sv_ix, $xpvcv_ix, $cv->REFCNT + 1, $cv->FLAGS)); + $sv_ix, $xpvcv_ix, $cv->REFCNT +1 , $cv->FLAGS)); return $sym; } @@ -641,24 +765,31 @@ sub B::GV::save { $sym = savesym($gv, "gv_list[$ix]"); #warn sprintf("Saving GV 0x%x as $sym\n", $$gv); # debug } + my $is_empty = $gv->is_empty; my $gvname = $gv->NAME; my $name = cstring($gv->STASH->NAME . "::" . $gvname); #warn "GV name is $name\n"; # debug - my $egv = $gv->EGV; my $egvsym; - if ($$gv != $$egv) { - #warn(sprintf("EGV name is %s, saving it now\n", - # $egv->STASH->NAME . "::" . $egv->NAME)); # debug - $egvsym = $egv->save; + unless ($is_empty) { + my $egv = $gv->EGV; + if ($$gv != $$egv) { + #warn(sprintf("EGV name is %s, saving it now\n", + # $egv->STASH->NAME . "::" . $egv->NAME)); # debug + $egvsym = $egv->save; + } } $init->add(qq[$sym = gv_fetchpv($name, TRUE, SVt_PV);], sprintf("SvFLAGS($sym) = 0x%x;", $gv->FLAGS), - sprintf("GvFLAGS($sym) = 0x%x;", $gv->GvFLAGS), - sprintf("GvLINE($sym) = %u;", $gv->LINE)); + sprintf("GvFLAGS($sym) = 0x%x;", $gv->GvFLAGS)); + $init->add(sprintf("GvLINE($sym) = %u;", $gv->LINE)) unless $is_empty; + # Shouldn't need to do save_magic since gv_fetchpv handles that #$gv->save_magic; my $refcnt = $gv->REFCNT + 1; $init->add(sprintf("SvREFCNT($sym) += %u;", $refcnt - 1)) if $refcnt > 1; + + return $sym if $is_empty; + my $gvrefcnt = $gv->GvREFCNT; if ($gvrefcnt > 1) { $init->add(sprintf("GvREFCNT($sym) += %u;", $gvrefcnt - 1)); @@ -672,45 +803,51 @@ sub B::GV::save { # warn "GV::save saving subfields\n"; # debug my $gvsv = $gv->SV; if ($$gvsv) { + $gvsv->save; $init->add(sprintf("GvSV($sym) = s\\_%x;", $$gvsv)); # warn "GV::save \$$name\n"; # debug - $gvsv->save; } my $gvav = $gv->AV; if ($$gvav) { + $gvav->save; $init->add(sprintf("GvAV($sym) = s\\_%x;", $$gvav)); # warn "GV::save \@$name\n"; # debug - $gvav->save; } my $gvhv = $gv->HV; if ($$gvhv) { + $gvhv->save; $init->add(sprintf("GvHV($sym) = s\\_%x;", $$gvhv)); # warn "GV::save \%$name\n"; # debug - $gvhv->save; } my $gvcv = $gv->CV; - if ($$gvcv) { - $init->add(sprintf("GvCV($sym) = (CV*)s\\_%x;", $$gvcv)); -# warn "GV::save &$name\n"; # debug - $gvcv->save; - } - my $gvfilegv = $gv->FILEGV; - if ($$gvfilegv) { - $init->add(sprintf("GvFILEGV($sym) = (GV*)s\\_%x;",$$gvfilegv)); -# warn "GV::save GvFILEGV(*$name)\n"; # debug - $gvfilegv->save; - } + if ($$gvcv) { + my $origname=cstring($gvcv->GV->EGV->STASH->NAME . + "::" . $gvcv->GV->EGV->NAME); + if (0 && $gvcv->XSUB && $name ne $origname) { #XSUB alias + # must save as a 'stub' so newXS() has a CV to populate + $init->add("{ CV *cv;"); + $init->add("\tcv=perl_get_cv($origname,TRUE);"); + $init->add("\tGvCV($sym)=cv;"); + $init->add("\tSvREFCNT_inc((SV *)cv);"); + $init->add("}"); + } else { + $init->add(sprintf("GvCV($sym) = (CV*)(%s);", $gvcv->save)); +# warn "GV::save &$name\n"; # debug + } + } + $init->add(sprintf("GvFILE($sym) = %s;", cstring($gv->FILE))); +# warn "GV::save GvFILE(*$name)\n"; # debug my $gvform = $gv->FORM; if ($$gvform) { + $gvform->save; $init->add(sprintf("GvFORM($sym) = (CV*)s\\_%x;", $$gvform)); # warn "GV::save GvFORM(*$name)\n"; # debug - $gvform->save; } my $gvio = $gv->IO; if ($$gvio) { + $gvio->save; $init->add(sprintf("GvIOp($sym) = s\\_%x;", $$gvio)); # warn "GV::save GvIO(*$name)\n"; # debug - $gvio->save; } } return $sym; @@ -723,7 +860,7 @@ sub B::AV::save { $xpvavsect->add(sprintf("0, -1, -1, 0, 0.0, 0, Nullhv, 0, 0, 0x%x", $avflags)); $svsect->add(sprintf("&xpvav_list[%d], %lu, 0x%x", - $xpvavsect->index, $av->REFCNT + 1, $av->FLAGS)); + $xpvavsect->index, $av->REFCNT , $av->FLAGS)); my $sv_list_index = $svsect->index; my $fill = $av->FILL; $av->save_magic; @@ -789,7 +926,7 @@ sub B::HV::save { $xpvhvsect->add(sprintf("0, 0, %d, 0, 0.0, 0, Nullhv, %d, 0, 0, 0", $hv->MAX, $hv->RITER)); $svsect->add(sprintf("&xpvhv_list[%d], %lu, 0x%x", - $xpvhvsect->index, $hv->REFCNT + 1, $hv->FLAGS)); + $xpvhvsect->index, $hv->REFCNT , $hv->FLAGS)); my $sv_list_index = $svsect->index; my @contents = $hv->ARRAY; if (@contents) { @@ -802,9 +939,12 @@ sub B::HV::save { my ($key, $value) = splice(@contents, 0, 2); $init->add(sprintf("\thv_store(hv, %s, %u, %s, %s);", cstring($key),length($key),$value, hash($key))); +# $init->add(sprintf("\thv_store(hv, %s, %u, %s, %s);", +# cstring($key),length($key),$value, 0)); } $init->add("}"); } + $hv->save_magic(); return savesym($hv, "(HV*)&sv_list[$sv_list_index]"); } @@ -813,6 +953,7 @@ sub B::IO::save { my $sym = objsym($io); return $sym if defined $sym; my $pv = $io->PV; + $pv = '' unless defined $pv; my $len = length($pv); $xpviosect->add(sprintf("0, %u, %u, %d, %s, 0, 0, 0, 0, 0, %d, %d, %d, %d, %s, Nullgv, %s, Nullgv, %s, Nullgv, %d, %s, 0x%x", $len, $len+1, $io->IVX, $io->NVX, $io->LINES, @@ -821,7 +962,7 @@ sub B::IO::save { cstring($io->BOTTOM_NAME), $io->SUBPROCESS, cchar($io->IoTYPE), $io->IoFLAGS)); $svsect->add(sprintf("&xpvio_list[%d], %lu, 0x%x", - $xpviosect->index, $io->REFCNT + 1, $io->FLAGS)); + $xpviosect->index, $io->REFCNT , $io->FLAGS)); $sym = savesym($io, sprintf("(IO*)&sv_list[%d]", $svsect->index)); my ($field, $fsym); foreach $field (qw(TOP_GV FMT_GV BOTTOM_GV)) { @@ -848,11 +989,10 @@ sub output_all { my $init_name = shift; my $section; my @sections = ($opsect, $unopsect, $binopsect, $logopsect, $condopsect, - $listopsect, $pmopsect, $svopsect, $gvopsect, $pvopsect, - $cvopsect, $loopsect, $copsect, $svsect, $xpvsect, + $listopsect, $pmopsect, $svopsect, $padopsect, $pvopsect, + $loopsect, $copsect, $svsect, $xpvsect, $xpvavsect, $xpvhvsect, $xpvcvsect, $xpvivsect, $xpvnvsect, $xpvmgsect, $xpvlvsect, $xrvsect, $xpvbmsect, $xpviosect); - $bootstrap->output(\*STDOUT, "/* bootstrap %s */\n"); $symsect->output(\*STDOUT, "#define %s\n"); print "\n"; output_declarations(); @@ -881,6 +1021,8 @@ sub output_all { static int $init_name() { dTHR; + dTARG; + djSP; EOT $init->output(\*STDOUT, "\t%s\n"); print "\treturn 0;\n}\n"; @@ -915,18 +1057,18 @@ typedef struct { HV * xcv_stash; OP * xcv_start; OP * xcv_root; - void (*xcv_xsub) _((CV*)); + void (*xcv_xsub) (CV*); void * xcv_xsubany; GV * xcv_gv; - GV * xcv_filegv; - long xcv_depth; /* >= 2 indicates recursive call */ + char * xcv_file; + long xcv_depth; /* >= 2 indicates recursive call */ AV * xcv_padlist; CV * xcv_outside; #ifdef USE_THREADS perl_mutex *xcv_mutexp; struct perl_thread *xcv_owner; /* current owner thread */ #endif /* USE_THREADS */ - U8 xcv_flags; + cv_flags_t xcv_flags; } XPVCV_or_similar; #define ANYINIT(i) i #else @@ -948,15 +1090,16 @@ sub output_boilerplate { print <<'EOT'; #include "EXTERN.h" #include "perl.h" -#ifndef PATCHLEVEL -#include "patchlevel.h" -#endif +#include "XSUB.h" /* Workaround for mapstart: the only op which needs a different ppaddr */ -#undef pp_mapstart -#define pp_mapstart pp_grepstart +#undef Perl_pp_mapstart +#define Perl_pp_mapstart Perl_pp_grepstart +#define XS_DynaLoader_boot_DynaLoader boot_DynaLoader +EXTERN_C void boot_DynaLoader (pTHX_ CV* cv); -static void xs_init _((void)); +static void xs_init (pTHX); +static void dl_init (pTHX); static PerlInterpreter *my_perl; EOT } @@ -964,28 +1107,20 @@ EOT sub output_main { print <<'EOT'; int -#ifndef CAN_PROTOTYPE -main(argc, argv, env) -int argc; -char **argv; -char **env; -#else /* def(CAN_PROTOTYPE) */ main(int argc, char **argv, char **env) -#endif /* def(CAN_PROTOTYPE) */ { int exitstatus; int i; char **fakeargv; - PERL_SYS_INIT(&argc,&argv); + PERL_SYS_INIT3(&argc,&argv,&env); - perl_init_i18nl10n(1); - if (!PL_do_undump) { my_perl = perl_alloc(); if (!my_perl) exit(1); perl_construct( my_perl ); + PL_perl_destruct_level = 0; } #ifdef CSH @@ -1021,22 +1156,84 @@ main(int argc, char **argv, char **env) exitstatus = perl_init(); if (exitstatus) exit( exitstatus ); + dl_init(aTHX); exitstatus = perl_run( my_perl ); perl_destruct( my_perl ); perl_free( my_perl ); + PERL_SYS_TERM(); + exit( exitstatus ); } +/* yanked from perl.c */ static void -xs_init() +xs_init(pTHX) { -} + char *file = __FILE__; + dTARG; + djSP; +EOT + print "\n#ifdef USE_DYNAMIC_LOADING"; + print qq/\n\tnewXS("DynaLoader::boot_DynaLoader", boot_DynaLoader, file);/; + print "\n#endif\n" ; + # delete $xsub{'DynaLoader'}; + delete $xsub{'UNIVERSAL'}; + print("/* bootstrapping code*/\n\tSAVETMPS;\n"); + print("\ttarg=sv_newmortal();\n"); + print "#ifdef DYNALOADER_BOOTSTRAP\n"; + print "\tPUSHMARK(sp);\n"; + print qq/\tXPUSHp("DynaLoader",strlen("DynaLoader"));\n/; + print qq/\tPUTBACK;\n/; + print "\tboot_DynaLoader(aTHX_ NULL);\n"; + print qq/\tSPAGAIN;\n/; + print "#endif\n"; + foreach my $stashname (keys %xsub){ + if ($xsub{$stashname} ne 'Dynamic') { + my $stashxsub=$stashname; + $stashxsub =~ s/::/__/g; + print "\tPUSHMARK(sp);\n"; + print qq/\tXPUSHp("$stashname",strlen("$stashname"));\n/; + print qq/\tPUTBACK;\n/; + print "\tboot_$stashxsub(aTHX_ NULL);\n"; + print qq/\tSPAGAIN;\n/; + } + } + print("\tFREETMPS;\n/* end bootstrapping code */\n"); + print "}\n"; + +print <<'EOT'; +static void +dl_init(pTHX) +{ + char *file = __FILE__; + dTARG; + djSP; EOT + print("/* Dynamicboot strapping code*/\n\tSAVETMPS;\n"); + print("\ttarg=sv_newmortal();\n"); + foreach my $stashname (@DynaLoader::dl_modules) { + warn "Loaded $stashname\n"; + if (exists($xsub{$stashname}) && $xsub{$stashname} eq 'Dynamic') { + my $stashxsub=$stashname; + $stashxsub =~ s/::/__/g; + print "\tPUSHMARK(sp);\n"; + print qq/\tXPUSHp("$stashname",/,length($stashname),qq/);\n/; + print qq/\tPUTBACK;\n/; + print "#ifdef DYNALOADER_BOOTSTRAP\n"; + warn "bootstrapping $stashname added to xs_init\n"; + print qq/\tperl_call_method("bootstrap",G_DISCARD);\n/; + print "\n#else\n"; + print "\tboot_$stashxsub(aTHX_ NULL);\n"; + print "#endif\n"; + print qq/\tSPAGAIN;\n/; + } + } + print("\tFREETMPS;\n/* end Dynamic bootstrapping code */\n"); + print "}\n"; } - sub dump_symtable { # For debugging my ($sym, $val); @@ -1056,107 +1253,174 @@ sub save_object { sub Dummy_BootStrap { } -sub B::GV::savecv { - my $gv = shift; - my $cv = $gv->CV; - my $name = $gv->NAME; - if ($$cv) { - if ($name eq "bootstrap" && $cv->XSUB) { - my $file = $cv->FILEGV->SV->PV; - $bootstrap->add($file); - my $name = $gv->STASH->NAME.'::'.$name; - no strict 'refs'; - *{$name} = \&Dummy_BootStrap; - $cv = $gv->CV; - } - if ($debug_cv) { - warn sprintf("saving extra CV &%s::%s (0x%x) from GV 0x%x\n", - $gv->STASH->NAME, $name, $$cv, $$gv); - } - my $package=$gv->STASH->NAME; - # This seems to undo all the ->isa and prefix stuff we do below - # so disable again for now - if (0 && ! grep(/^$package$/,@unused_sub_packages)){ - warn sprintf("omitting cv in superclass %s", $gv->STASH->NAME) - if $debug_cv; - return ; +sub B::GV::savecv +{ + my $gv = shift; + my $package=$gv->STASH->NAME; + my $name = $gv->NAME; + my $cv = $gv->CV; + my $sv = $gv->SV; + my $av = $gv->AV; + my $hv = $gv->HV; + + # We may be looking at this package just because it is a branch in the + # symbol table which is on the path to a package which we need to save + # e.g. this is 'Getopt' and we need to save 'Getopt::Long' + # + return unless ($unused_sub_packages{$package}); + return unless ($$cv || $$av || $$sv || $$hv); + $gv->save; +} + +sub mark_package +{ + my $package = shift; + unless ($unused_sub_packages{$package}) + { + no strict 'refs'; + $unused_sub_packages{$package} = 1; + if (defined @{$package.'::ISA'}) + { + foreach my $isa (@{$package.'::ISA'}) + { + if ($isa eq 'DynaLoader') + { + unless (defined(&{$package.'::bootstrap'})) + { + warn "Forcing bootstrap of $package\n"; + eval { $package->bootstrap }; + } + } +# else + { + unless ($unused_sub_packages{$isa}) + { + warn "$isa saved (it is in $package\'s \@ISA)\n"; + mark_package($isa); + } + } } - $gv->save; } - elsif ($name eq 'ISA') - { - $gv->save; - } - + } + return 1; +} + +sub should_save +{ + no strict qw(vars refs); + my $package = shift; + $package =~ s/::$//; + return $unused_sub_packages{$package} = 0 if ($package =~ /::::/); # skip ::::ISA::CACHE etc. + # warn "Considering $package\n";#debug + foreach my $u (grep($unused_sub_packages{$_},keys %unused_sub_packages)) + { + # If this package is a prefix to something we are saving, traverse it + # but do not mark it for saving if it is not already + # e.g. to get to Getopt::Long we need to traverse Getopt but need + # not save Getopt + return 1 if ($u =~ /^$package\:\:/); + } + if (exists $unused_sub_packages{$package}) + { + # warn "Cached $package is ".$unused_sub_packages{$package}."\n"; + delete_unsaved_hashINC($package) unless $unused_sub_packages{$package} ; + return $unused_sub_packages{$package}; + } + # Omit the packages which we use (and which cause grief + # because of fancy "goto &$AUTOLOAD" stuff). + # XXX Surely there must be a nicer way to do this. + if ($package eq "FileHandle" || $package eq "Config" || + $package eq "SelectSaver" || $package =~/^(B|IO)::/) + { + delete_unsaved_hashINC($package); + return $unused_sub_packages{$package} = 0; + } + # Now see if current package looks like an OO class this is probably too strong. + foreach my $m (qw(new DESTROY TIESCALAR TIEARRAY TIEHASH TIEHANDLE)) + { + if ($package->can($m)) + { + warn "$package has method $m: saving package\n";#debug + return mark_package($package); + } + } + delete_unsaved_hashINC($package); + return $unused_sub_packages{$package} = 0; +} +sub delete_unsaved_hashINC{ + my $packname=shift; + $packname =~ s/\:\:/\//g; + $packname .= '.pm'; +# warn "deleting $packname" if $INC{$packname} ;# debug + delete $INC{$packname}; +} +sub walkpackages +{ + my ($symref, $recurse, $prefix) = @_; + my $sym; + my $ref; + no strict 'vars'; + local(*glob); + $prefix = '' unless defined $prefix; + while (($sym, $ref) = each %$symref) + { + *glob = $ref; + if ($sym =~ /::$/) + { + $sym = $prefix . $sym; + if ($sym ne "main::" && &$recurse($sym)) + { + walkpackages(\%glob, $recurse, $sym); + } + } + } } +sub save_unused_subs +{ + no strict qw(refs); + &descend_marked_unused; + warn "Prescan\n"; + walkpackages(\%{"main::"}, sub { should_save($_[0]); return 1 }); + warn "Saving methods\n"; + walksymtable(\%{"main::"}, "savecv", \&should_save); +} -sub save_unused_subs { - my %search_pack; - map { $search_pack{$_} = 1 } @_; - @unused_sub_packages=@_; - no strict qw(vars refs); - walksymtable(\%{"main::"}, "savecv", sub { - my $package = shift; - $package =~ s/::$//; - return 0 if ($package =~ /::::/); # skip ::::ISA::CACHE etc. - #warn "Considering $package\n";#debug - return 1 if exists $search_pack{$package}; - #sub try for a partial match - if (grep(/^$package\:\:/,@unused_sub_packages)){ - return 1; - } - #warn " (nothing explicit)\n";#debug - # Omit the packages which we use (and which cause grief - # because of fancy "goto &$AUTOLOAD" stuff). - # XXX Surely there must be a nicer way to do this. - if ($package eq "FileHandle" - || $package eq "Config" - || $package eq "SelectSaver") { - return 0; - } - foreach my $u (keys %search_pack) { - if ($package =~ /^${u}::/) { - warn "$package starts with $u\n"; - return 1 - } - if ($package->isa($u)) { - warn "$package isa $u\n"; - return 1 - } - return 1 if $package->isa($u); - } - foreach my $m (qw(new DESTROY TIESCALAR TIEARRAY TIEHASH)) { - if (defined(&{$package."::$m"})) { - warn "$package has method $m: -u$package assumed\n";#debug - push @unused_sub_package, $package; - return 1; - } - } - return 0; - }); +sub save_context +{ + my $curpad_nam = (comppadlist->ARRAY)[0]->save; + my $curpad_sym = (comppadlist->ARRAY)[1]->save; + my $inc_hv = svref_2object(\%INC)->save; + my $inc_av = svref_2object(\@INC)->save; + my $amagic_generate= amagic_generation; + $init->add( "PL_curpad = AvARRAY($curpad_sym);", + "GvHV(PL_incgv) = $inc_hv;", + "GvAV(PL_incgv) = $inc_av;", + "av_store(CvPADLIST(PL_main_cv),0,SvREFCNT_inc($curpad_nam));", + "av_store(CvPADLIST(PL_main_cv),1,SvREFCNT_inc($curpad_sym));", + "PL_amagic_generation= $amagic_generate;" ); } +sub descend_marked_unused { + foreach my $pack (keys %unused_sub_packages) + { + mark_package($pack); + } +} + sub save_main { + warn "Starting compile\n"; warn "Walking tree\n"; - my $curpad_nam = (comppadlist->ARRAY)[0]->save; - my $curpad_sym = (comppadlist->ARRAY)[1]->save; - my $init_av = init_av->save; - my $inc_hv = svref_2object(\%INC)->save; - my $inc_av = svref_2object(\@INC)->save; + seek(STDOUT,0,0); #exclude print statements in BEGIN{} into output walkoptree(main_root, "save"); warn "done main optree, walking symtable for extras\n" if $debug_cv; - save_unused_subs(@unused_sub_packages); - + save_unused_subs(); + my $init_av = init_av->save; $init->add(sprintf("PL_main_root = s\\_%x;", ${main_root()}), sprintf("PL_main_start = s\\_%x;", ${main_start()}), - "PL_curpad = AvARRAY($curpad_sym);", - "PL_initav = $init_av;", - "GvHV(PL_incgv) = $inc_hv;", - "GvAV(PL_incgv) = $inc_av;", - "av_store(CvPADLIST(PL_main_cv),0,SvREFCNT_inc($curpad_nam));", - "av_store(CvPADLIST(PL_main_cv),1,SvREFCNT_inc($curpad_sym));"); + "PL_initav = (AV *) $init_av;"); + save_context(); warn "Writing output\n"; output_boilerplate(); print "\n"; @@ -1168,7 +1432,7 @@ sub save_main { sub init_sections { my @sections = (init => \$init, decl => \$decl, sym => \$symsect, binop => \$binopsect, condop => \$condopsect, - cop => \$copsect, cvop => \$cvopsect, gvop => \$gvopsect, + cop => \$copsect, padop => \$padopsect, listop => \$listopsect, logop => \$logopsect, loop => \$loopsect, op => \$opsect, pmop => \$pmopsect, pvop => \$pvopsect, svop => \$svopsect, unop => \$unopsect, @@ -1177,11 +1441,17 @@ sub init_sections { xpviv => \$xpvivsect, xpvnv => \$xpvnvsect, xpvmg => \$xpvmgsect, xpvlv => \$xpvlvsect, xrv => \$xrvsect, xpvbm => \$xpvbmsect, - xpvio => \$xpviosect, bootstrap => \$bootstrap); + xpvio => \$xpviosect); my ($name, $sectref); while (($name, $sectref) = splice(@sections, 0, 2)) { - $$sectref = new B::Section $name, \%symtable, 0; + $$sectref = new B::C::Section $name, \%symtable, 0; } +} + +sub mark_unused +{ + my ($arg,$val) = @_; + $unused_sub_packages{$arg} = $val; } sub compile { @@ -1226,7 +1496,7 @@ sub compile { $verbose = 1; } elsif ($opt eq "u") { $arg ||= shift @options; - push(@unused_sub_packages, $arg); + mark_unused($arg,undef); } elsif ($opt eq "f") { $arg ||= shift @options; if ($arg eq "cog") { @@ -1241,6 +1511,8 @@ sub compile { # Optimisations for -O1 $pv_copy_on_grow = 1; } + } elsif ($opt eq "l") { + $max_string_len = $arg; } } init_sections(); @@ -1356,6 +1628,15 @@ No copy-on-grow. Optimisation level (n = 0, 1, 2, ...). B<-O> means B<-O1>. Currently, B<-O1> and higher set B<-fcog>. +=item B<-llimit> + +Some C compilers impose an arbitrary limit on the length of string +constants (e.g. 2048 characters for Microsoft Visual C++). The +B<-llimit> options tells the C backend not to generate string literals +exceeding that limit. + +=back + =head1 EXAMPLES perl -MO=C,-ofoo.c foo.pl @@ -1365,7 +1646,7 @@ Note that C<cc_harness> lives in the C<B> subdirectory of your perl library directory. The utility called C<perlcc> may also be used to help make use of this compiler. - perl -MO=C,-v,-DcA bar.pl > /dev/null + perl -MO=C,-v,-DcA,-l2048 bar.pl > /dev/null =head1 BUGS diff --git a/contrib/perl5/ext/B/B/CC.pm b/contrib/perl5/ext/B/B/CC.pm index d200d70..c5ca2a3 100644 --- a/contrib/perl5/ext/B/B/CC.pm +++ b/contrib/perl5/ext/B/B/CC.pm @@ -6,36 +6,22 @@ # License or the Artistic License, as specified in the README file. # package B::CC; +use Config; use strict; use B qw(main_start main_root class comppadlist peekop svref_2object - timing_info); -use B::C qw(save_unused_subs objsym init_sections + timing_info init_av sv_undef amagic_generation + OPf_WANT_LIST OPf_WANT OPf_MOD OPf_STACKED OPf_SPECIAL + OPpASSIGN_BACKWARDS OPpLVAL_INTRO OPpDEREF_AV OPpDEREF_HV + OPpDEREF OPpFLIP_LINENUM G_ARRAY G_SCALAR + CXt_NULL CXt_SUB CXt_EVAL CXt_LOOP CXt_SUBST CXt_BLOCK + ); +use B::C qw(save_unused_subs objsym init_sections mark_unused output_all output_boilerplate output_main); use B::Bblock qw(find_leaders); use B::Stackobj qw(:types :flags); # These should probably be elsewhere # Flags for $op->flags -sub OPf_LIST () { 1 } -sub OPf_KNOW () { 2 } -sub OPf_MOD () { 32 } -sub OPf_STACKED () { 64 } -sub OPf_SPECIAL () { 128 } -# op-specific flags for $op->private -sub OPpASSIGN_BACKWARDS () { 64 } -sub OPpLVAL_INTRO () { 128 } -sub OPpDEREF_AV () { 32 } -sub OPpDEREF_HV () { 64 } -sub OPpDEREF () { OPpDEREF_AV|OPpDEREF_HV } -sub OPpFLIP_LINENUM () { 64 } -sub G_ARRAY () { 1 } -# cop.h -sub CXt_NULL () { 0 } -sub CXt_SUB () { 1 } -sub CXt_EVAL () { 2 } -sub CXt_LOOP () { 3 } -sub CXt_SUBST () { 4 } -sub CXt_BLOCK () { 5 } my $module; # module name (when compiled with -m) my %done; # hash keyed by $$op of leaders of basic blocks @@ -66,6 +52,9 @@ my %skip_stack; # Hash of PP names which don't need write_back_stack my %skip_lexicals; # Hash of PP names which don't need write_back_lexicals my %skip_invalidate; # Hash of PP names which don't need invalidate_lexicals my %ignore_op; # Hash of ops which do nothing except returning op_next +my %need_curcop; # Hash of ops which need PL_curcop + +my %lexstate; #state of padsvs at the start of a bblock BEGIN { foreach (qw(pp_scalar pp_regcmaybe pp_lineseq pp_scope pp_null)) { @@ -73,11 +62,6 @@ BEGIN { } } -my @unused_sub_packages; # list of packages (given by -u options) to search - # explicitly and save every sub we find there, even - # if apparently unused (could be only referenced from - # an eval "" or from a $SIG{FOO} = "bar"). - my ($module_name); my ($debug_op, $debug_stack, $debug_cxstack, $debug_pad, $debug_runtime, $debug_shadow, $debug_queue, $debug_lineno, $debug_timings); @@ -111,12 +95,17 @@ sub init_hash { map { $_ => 1 } @_ } # %skip_lexicals = init_hash qw(pp_enter pp_enterloop); %skip_invalidate = init_hash qw(pp_enter pp_enterloop); +%need_curcop = init_hash qw(pp_rv2gv pp_bless pp_repeat pp_sort pp_caller + pp_reset pp_rv2cv pp_entereval pp_require pp_dofile + pp_entertry pp_enterloop pp_enteriter pp_entersub + pp_enter pp_method); sub debug { if ($debug_runtime) { warn(@_); } else { - runtime(map { chomp; "/* $_ */"} @_); + my @tmp=@_; + runtime(map { chomp; "/* $_ */"} @tmp); } } @@ -139,7 +128,7 @@ sub output_runtime { print qq(#include "cc_runtime.h"\n); foreach $ppdata (@pp_list) { my ($name, $runtime, $declare) = @$ppdata; - print "\nstatic\nPP($name)\n{\n"; + print "\nstatic\nCCPP($name)\n{\n"; my ($type, $varlist, $line); while (($type, $varlist) = each %$declare) { print "\t$type ", join(", ", @$varlist), ";\n"; @@ -167,7 +156,7 @@ sub init_pp { declare("SV", "**svp"); map { declare("SV", "*$_") } qw(sv src dst left right); declare("MAGIC", "*mg"); - $decl->add("static OP * $ppname _((ARGSproto));"); + $decl->add("static OP * $ppname (pTHX);"); debug "init_pp: $ppname\n" if $debug_queue; } @@ -200,7 +189,7 @@ sub top_int { @stack ? $stack[-1]->as_int : "TOPi" } sub top_double { @stack ? $stack[-1]->as_double : "TOPn" } sub top_numeric { @stack ? $stack[-1]->as_numeric : "TOPn" } sub top_sv { @stack ? $stack[-1]->as_sv : "TOPs" } -sub top_bool { @stack ? $stack[-1]->as_numeric : "SvTRUE(TOPs)" } +sub top_bool { @stack ? $stack[-1]->as_bool : "SvTRUE(TOPs)" } sub pop_int { @stack ? (pop @stack)->as_int : "POPi" } sub pop_double { @stack ? (pop @stack)->as_double : "POPn" } @@ -208,7 +197,7 @@ sub pop_numeric { @stack ? (pop @stack)->as_numeric : "POPn" } sub pop_sv { @stack ? (pop @stack)->as_sv : "POPs" } sub pop_bool { if (@stack) { - return ((pop @stack)->as_numeric); + return ((pop @stack)->as_bool); } else { # Careful: POPs has an auto-decrement and SvTRUE evaluates # its argument more than once. @@ -228,6 +217,32 @@ sub write_back_lexicals { } } +sub save_or_restore_lexical_state { + my $bblock=shift; + unless( exists $lexstate{$bblock}){ + foreach my $lex (@pad) { + next unless ref($lex); + ${$lexstate{$bblock}}{$lex->{iv}} = $lex->{flags} ; + } + } + else { + foreach my $lex (@pad) { + next unless ref($lex); + my $old_flags=${$lexstate{$bblock}}{$lex->{iv}} ; + next if ( $old_flags eq $lex->{flags}); + if (($old_flags & VALID_SV) && !($lex->{flags} & VALID_SV)){ + $lex->write_back; + } + if (($old_flags & VALID_DOUBLE) && !($lex->{flags} & VALID_DOUBLE)){ + $lex->load_double; + } + if (($old_flags & VALID_INT) && !($lex->{flags} & VALID_INT)){ + $lex->load_int; + } + } + } +} + sub write_back_stack { my $obj; return unless @stack; @@ -350,8 +365,9 @@ sub dopoptoloop { sub dopoptolabel { my $label = shift; my $cxix = $#cxstack; - while ($cxix >= 0 && $cxstack[$cxix]->{type} != CXt_LOOP - && $cxstack[$cxix]->{label} ne $label) { + while ($cxix >= 0 && + ($cxstack[$cxix]->{type} != CXt_LOOP || + $cxstack[$cxix]->{label} ne $label)) { $cxix--; } debug "dopoptolabel: returning $cxix" if $debug_cxstack; @@ -360,7 +376,7 @@ sub dopoptolabel { sub error { my $format = shift; - my $file = $curcop->[0]->filegv->SV->PV; + my $file = $curcop->[0]->file; my $line = $curcop->[0]->line; $errors++; if (@_) { @@ -416,12 +432,22 @@ sub load_pad { } $pad[$ix] = new B::Stackobj::Padsv ($type, $flags, $ix, "i_$name", "d_$name"); - declare("IV", $type == T_INT ? "i_$name = 0" : "i_$name"); - declare("double", $type == T_DOUBLE ? "d_$name = 0" : "d_$name"); + debug sprintf("PL_curpad[$ix] = %s\n", $pad[$ix]->peek) if $debug_pad; } } +sub declare_pad { + my $ix; + for ($ix = 1; $ix <= $#pad; $ix++) { + my $type = $pad[$ix]->{type}; + declare("IV", $type == T_INT ? + sprintf("%s=0",$pad[$ix]->{iv}):$pad[$ix]->{iv}) if $pad[$ix]->save_int; + declare("double", $type == T_DOUBLE ? + sprintf("%s = 0",$pad[$ix]->{nv}):$pad[$ix]->{nv} )if $pad[$ix]->save_double; + + } +} # # Debugging stuff # @@ -461,7 +487,7 @@ sub doop { sub gimme { my $op = shift; my $flags = $op->flags; - return (($flags & OPf_KNOW) ? ($flags & OPf_LIST) : "dowantarray()"); + return (($flags & OPf_WANT) ? (($flags & OPf_WANT)== OPf_WANT_LIST? G_ARRAY:G_SCALAR) : "dowantarray()"); } # @@ -476,10 +502,12 @@ sub pp_null { sub pp_stub { my $op = shift; my $gimme = gimme($op); - if ($gimme != 1) { + if ($gimme != G_ARRAY) { + my $obj= new B::Stackobj::Const(sv_undef); + push(@stack, $obj); # XXX Change to push a constant sv_undef Stackobj onto @stack - write_back_stack(); - runtime("if ($gimme != G_ARRAY) XPUSHs(&PL_sv_undef);"); + #write_back_stack(); + #runtime("if ($gimme != G_ARRAY) XPUSHs(&PL_sv_undef);"); } return $op->next; } @@ -499,8 +527,10 @@ sub pp_and { if (@stack >= 1) { my $bool = pop_bool(); write_back_stack(); - runtime(sprintf("if (!$bool) goto %s;", label($next))); + save_or_restore_lexical_state($$next); + runtime(sprintf("if (!$bool) {XPUSHs(&PL_sv_no); goto %s;}", label($next))); } else { + save_or_restore_lexical_state($$next); runtime(sprintf("if (!%s) goto %s;", top_bool(), label($next)), "*sp--;"); } @@ -513,11 +543,13 @@ sub pp_or { reload_lexicals(); unshift(@bblock_todo, $next); if (@stack >= 1) { - my $obj = pop @stack; + my $bool = pop_bool @stack; write_back_stack(); - runtime(sprintf("if (%s) { XPUSHs(%s); goto %s; }", - $obj->as_numeric, $obj->as_sv, label($next))); + save_or_restore_lexical_state($$next); + runtime(sprintf("if (%s) { XPUSHs(&PL_sv_yes); goto %s; }", + $bool, label($next))); } else { + save_or_restore_lexical_state($$next); runtime(sprintf("if (%s) goto %s;", top_bool(), label($next)), "*sp--;"); } @@ -526,13 +558,14 @@ sub pp_or { sub pp_cond_expr { my $op = shift; - my $false = $op->false; + my $false = $op->next; unshift(@bblock_todo, $false); reload_lexicals(); my $bool = pop_bool(); write_back_stack(); + save_or_restore_lexical_state($$false); runtime(sprintf("if (!$bool) goto %s;", label($false))); - return $op->true; + return $op->other; } sub pp_padsv { @@ -555,9 +588,16 @@ sub pp_padsv { sub pp_const { my $op = shift; my $sv = $op->sv; - my $obj = $constobj{$$sv}; - if (!defined($obj)) { - $obj = $constobj{$$sv} = new B::Stackobj::Const ($sv); + my $obj; + # constant could be in the pad (under useithreads) + if ($$sv) { + $obj = $constobj{$$sv}; + if (!defined($obj)) { + $obj = $constobj{$$sv} = new B::Stackobj::Const ($sv); + } + } + else { + $obj = $pad[$op->targ]; } push(@stack, $obj); return $op->next; @@ -567,7 +607,7 @@ sub pp_nextstate { my $op = shift; $curcop->load($op); @stack = (); - debug(sprintf("%s:%d\n", $op->filegv->SV->PV, $op->line)) if $debug_lineno; + debug(sprintf("%s:%d\n", $op->file, $op->line)) if $debug_lineno; runtime("TAINT_NOT;") unless $omit_taint; runtime("sp = PL_stack_base + cxstack[cxstack_ix].blk_oldsp;"); if ($freetmps_each_bblock || $freetmps_each_loop) { @@ -584,18 +624,58 @@ sub pp_dbstate { return default_pp($op); } -sub pp_rv2gv { $curcop->write_back; default_pp(@_) } -sub pp_bless { $curcop->write_back; default_pp(@_) } -sub pp_repeat { $curcop->write_back; default_pp(@_) } +#default_pp will handle this: +#sub pp_bless { $curcop->write_back; default_pp(@_) } +#sub pp_repeat { $curcop->write_back; default_pp(@_) } # The following subs need $curcop->write_back if we decide to support arybase: # pp_pos, pp_substr, pp_index, pp_rindex, pp_aslice, pp_lslice, pp_splice -sub pp_sort { $curcop->write_back; default_pp(@_) } -sub pp_caller { $curcop->write_back; default_pp(@_) } -sub pp_reset { $curcop->write_back; default_pp(@_) } +#sub pp_caller { $curcop->write_back; default_pp(@_) } +#sub pp_reset { $curcop->write_back; default_pp(@_) } + +sub pp_rv2gv{ + my $op =shift; + $curcop->write_back; + write_back_lexicals() unless $skip_lexicals{$ppname}; + write_back_stack() unless $skip_stack{$ppname}; + my $sym=doop($op); + if ($op->private & OPpDEREF) { + $init->add(sprintf("((UNOP *)$sym)->op_first = $sym;")); + $init->add(sprintf("((UNOP *)$sym)->op_type = %d;", + $op->first->type)); + } + return $op->next; +} +sub pp_sort { + my $op = shift; + my $ppname = $op->ppaddr; + if ( $op->flags & OPf_SPECIAL && $op->flags & OPf_STACKED){ + #this indicates the sort BLOCK Array case + #ugly surgery required. + my $root=$op->first->sibling->first; + my $start=$root->first; + $op->first->save; + $op->first->sibling->save; + $root->save; + my $sym=$start->save; + my $fakeop=cc_queue("pp_sort".$$op,$root,$start); + $init->add(sprintf("(%s)->op_next=%s;",$sym,$fakeop)); + } + $curcop->write_back; + write_back_lexicals(); + write_back_stack(); + doop($op); + return $op->next; +} sub pp_gv { my $op = shift; - my $gvsym = $op->gv->save; + my $gvsym; + if ($Config{useithreads}) { + $gvsym = $pad[$op->padix]->as_sv; + } + else { + $gvsym = $op->gv->save; + } write_back_stack(); runtime("XPUSHs((SV*)$gvsym);"); return $op->next; @@ -603,7 +683,13 @@ sub pp_gv { sub pp_gvsv { my $op = shift; - my $gvsym = $op->gv->save; + my $gvsym; + if ($Config{useithreads}) { + $gvsym = $pad[$op->padix]->as_sv; + } + else { + $gvsym = $op->gv->save; + } write_back_stack(); if ($op->private & OPpLVAL_INTRO) { runtime("XPUSHs(save_scalar($gvsym));"); @@ -615,7 +701,13 @@ sub pp_gvsv { sub pp_aelemfast { my $op = shift; - my $gvsym = $op->gv->save; + my $gvsym; + if ($Config{useithreads}) { + $gvsym = $pad[$op->padix]->as_sv; + } + else { + $gvsym = $op->gv->save; + } my $ix = $op->private; my $flag = $op->flags & OPf_MOD; write_back_stack(); @@ -666,11 +758,15 @@ sub numeric_binop { } } else { if ($force_int) { + my $rightruntime = new B::Pseudoreg ("IV", "riv"); + runtime(sprintf("$$rightruntime = %s;",$right)); runtime(sprintf("sv_setiv(TOPs, %s);", - &$operator("TOPi", $right))); + &$operator("TOPi", $$rightruntime))); } else { + my $rightruntime = new B::Pseudoreg ("double", "rnv"); + runtime(sprintf("$$rightruntime = %s;",$right)); runtime(sprintf("sv_setnv(TOPs, %s);", - &$operator("TOPn", $right))); + &$operator("TOPn",$$rightruntime))); } } } else { @@ -694,6 +790,60 @@ sub numeric_binop { return $op->next; } +sub pp_ncmp { + my ($op) = @_; + if ($op->flags & OPf_STACKED) { + my $right = pop_numeric(); + if (@stack >= 1) { + my $left = top_numeric(); + runtime sprintf("if (%s > %s){",$left,$right); + $stack[-1]->set_int(1); + $stack[-1]->write_back(); + runtime sprintf("}else if (%s < %s ) {",$left,$right); + $stack[-1]->set_int(-1); + $stack[-1]->write_back(); + runtime sprintf("}else if (%s == %s) {",$left,$right); + $stack[-1]->set_int(0); + $stack[-1]->write_back(); + runtime sprintf("}else {"); + $stack[-1]->set_sv("&PL_sv_undef"); + runtime "}"; + } else { + my $rightruntime = new B::Pseudoreg ("double", "rnv"); + runtime(sprintf("$$rightruntime = %s;",$right)); + runtime sprintf(qq/if ("TOPn" > %s){/,$rightruntime); + runtime sprintf("sv_setiv(TOPs,1);"); + runtime sprintf(qq/}else if ( "TOPn" < %s ) {/,$$rightruntime); + runtime sprintf("sv_setiv(TOPs,-1);"); + runtime sprintf(qq/} else if ("TOPn" == %s) {/,$$rightruntime); + runtime sprintf("sv_setiv(TOPs,0);"); + runtime sprintf(qq/}else {/); + runtime sprintf("sv_setiv(TOPs,&PL_sv_undef;"); + runtime "}"; + } + } else { + my $targ = $pad[$op->targ]; + my $right = new B::Pseudoreg ("double", "rnv"); + my $left = new B::Pseudoreg ("double", "lnv"); + runtime(sprintf("$$right = %s; $$left = %s;", + pop_numeric(), pop_numeric)); + runtime sprintf("if (%s > %s){",$$left,$$right); + $targ->set_int(1); + $targ->write_back(); + runtime sprintf("}else if (%s < %s ) {",$$left,$$right); + $targ->set_int(-1); + $targ->write_back(); + runtime sprintf("}else if (%s == %s) {",$$left,$$right); + $targ->set_int(0); + $targ->write_back(); + runtime sprintf("}else {"); + $targ->set_sv("&PL_sv_undef"); + runtime "}"; + push(@stack, $targ); + } + return $op->next; +} + sub sv_binop { my ($op, $operator, $flags) = @_; if ($op->flags & OPf_STACKED) { @@ -789,7 +939,6 @@ BEGIN { my $modulo_op = infix_op("%"); my $lshift_op = infix_op("<<"); my $rshift_op = infix_op(">>"); - my $ncmp_op = sub { "($_[0] > $_[1] ? 1 : ($_[0] < $_[1]) ? -1 : 0)" }; my $scmp_op = prefix_op("sv_cmp"); my $seq_op = prefix_op("sv_eq"); my $sne_op = prefix_op("!sv_eq"); @@ -808,12 +957,11 @@ BEGIN { # XXX The standard perl PP code has extra handling for # some special case arguments of these operators. # - sub pp_add { numeric_binop($_[0], $plus_op, INTS_CLOSED) } - sub pp_subtract { numeric_binop($_[0], $minus_op, INTS_CLOSED) } - sub pp_multiply { numeric_binop($_[0], $multiply_op, INTS_CLOSED) } + sub pp_add { numeric_binop($_[0], $plus_op) } + sub pp_subtract { numeric_binop($_[0], $minus_op) } + sub pp_multiply { numeric_binop($_[0], $multiply_op) } sub pp_divide { numeric_binop($_[0], $divide_op) } sub pp_modulo { int_binop($_[0], $modulo_op) } # differs from perl's - sub pp_ncmp { numeric_binop($_[0], $ncmp_op, INT_RESULT) } sub pp_left_shift { int_binop($_[0], $lshift_op) } sub pp_right_shift { int_binop($_[0], $rshift_op) } @@ -857,7 +1005,7 @@ sub pp_sassign { ($src, $dst) = ($dst, $src) if $backwards; my $type = $src->{type}; if ($type == T_INT) { - $dst->set_int($src->as_int); + $dst->set_int($src->as_int,$src->{flags} & VALID_UNSIGNED); } elsif ($type == T_DOUBLE) { $dst->set_numeric($src->as_numeric); } else { @@ -870,7 +1018,11 @@ sub pp_sassign { my $type = $src->{type}; runtime("if (PL_tainting && PL_tainted) TAINT_NOT;"); if ($type == T_INT) { - runtime sprintf("sv_setiv(TOPs, %s);", $src->as_int); + if ($src->{flags} & VALID_UNSIGNED){ + runtime sprintf("sv_setuv(TOPs, %s);", $src->as_int); + }else{ + runtime sprintf("sv_setiv(TOPs, %s);", $src->as_int); + } } elsif ($type == T_DOUBLE) { runtime sprintf("sv_setnv(TOPs, %s);", $src->as_double); } else { @@ -887,7 +1039,7 @@ sub pp_sassign { } elsif ($type == T_DOUBLE) { $dst->set_double("SvNV(sv)"); } else { - runtime("SvSetSV($dst->{sv}, sv);"); + runtime("SvSetMagicSV($dst->{sv}, sv);"); $dst->invalidate; } } @@ -922,6 +1074,7 @@ sub pp_preinc { return $op->next; } + sub pp_pushmark { my $op = shift; write_back_stack(); @@ -933,7 +1086,7 @@ sub pp_list { my $op = shift; write_back_stack(); my $gimme = gimme($op); - if ($gimme == 1) { # sic + if ($gimme == G_ARRAY) { # sic runtime("POPMARK;"); # need this even though not a "full" pp_list } else { runtime("PP_LIST($gimme);"); @@ -943,16 +1096,31 @@ sub pp_list { sub pp_entersub { my $op = shift; + $curcop->write_back; write_back_lexicals(REGISTER|TEMPORARY); write_back_stack(); my $sym = doop($op); runtime("while (PL_op != ($sym)->op_next && PL_op != (OP*)0 ){"); - runtime("PL_op = (*PL_op->op_ppaddr)(ARGS);"); + runtime("PL_op = (*PL_op->op_ppaddr)(aTHX);"); runtime("SPAGAIN;}"); $know_op = 0; invalidate_lexicals(REGISTER|TEMPORARY); return $op->next; } +sub pp_formline { + my $op = shift; + my $ppname = $op->ppaddr; + write_back_lexicals() unless $skip_lexicals{$ppname}; + write_back_stack() unless $skip_stack{$ppname}; + my $sym=doop($op); + # See comment in pp_grepwhile to see why! + $init->add("((LISTOP*)$sym)->op_first = $sym;"); + runtime("if (PL_op == ((LISTOP*)($sym))->op_first){"); + save_or_restore_lexical_state(${$op->first}); + runtime( sprintf("goto %s;",label($op->first))); + runtime("}"); + return $op->next; +} sub pp_goto{ @@ -969,7 +1137,16 @@ sub pp_enterwrite { my $op = shift; pp_entersub($op); } - +sub pp_leavesub{ + my $op = shift; + write_back_lexicals() unless $skip_lexicals{$ppname}; + write_back_stack() unless $skip_stack{$ppname}; + runtime("if (PL_curstackinfo->si_type == PERLSI_SORT){"); + runtime("\tPUTBACK;return 0;"); + runtime("}"); + doop($op); + return $op->next; +} sub pp_leavewrite { my $op = shift; write_back_lexicals(REGISTER|TEMPORARY); @@ -977,7 +1154,7 @@ sub pp_leavewrite { my $sym = doop($op); # XXX Is this the right way to distinguish between it returning # CvSTART(cv) (via doform) and pop_return()? - runtime("if (PL_op) PL_op = (*PL_op->op_ppaddr)(ARGS);"); + #runtime("if (PL_op) PL_op = (*PL_op->op_ppaddr)(aTHX);"); runtime("SPAGAIN;"); $know_op = 0; invalidate_lexicals(REGISTER|TEMPORARY); @@ -991,6 +1168,7 @@ sub doeval { write_back_stack(); my $sym = loadop($op); my $ppaddr = $op->ppaddr; + #runtime(qq/printf("$ppaddr type eval\n");/); runtime("PP_EVAL($ppaddr, ($sym)->op_next);"); $know_op = 1; invalidate_lexicals(REGISTER|TEMPORARY); @@ -998,9 +1176,24 @@ sub doeval { } sub pp_entereval { doeval(@_) } -sub pp_require { doeval(@_) } sub pp_dofile { doeval(@_) } +#pp_require is protected by pp_entertry, so no protection for it. +sub pp_require { + my $op = shift; + $curcop->write_back; + write_back_lexicals(REGISTER|TEMPORARY); + write_back_stack(); + my $sym = doop($op); + runtime("while (PL_op != ($sym)->op_next && PL_op != (OP*)0 ){"); + runtime("PL_op = (*PL_op->op_ppaddr)(ARGS);"); + runtime("SPAGAIN;}"); + $know_op = 1; + invalidate_lexicals(REGISTER|TEMPORARY); + return $op->next; +} + + sub pp_entertry { my $op = shift; $curcop->write_back; @@ -1008,12 +1201,19 @@ sub pp_entertry { write_back_stack(); my $sym = doop($op); my $jmpbuf = sprintf("jmpbuf%d", $jmpbuf_ix++); - declare("Sigjmp_buf", $jmpbuf); + declare("JMPENV", $jmpbuf); runtime(sprintf("PP_ENTERTRY(%s,%s);", $jmpbuf, label($op->other->next))); invalidate_lexicals(REGISTER|TEMPORARY); return $op->next; } +sub pp_leavetry{ + my $op=shift; + default_pp($op); + runtime("PP_LEAVETRY;"); + return $op->next; +} + sub pp_grepstart { my $op = shift; if ($need_freetmps && $freetmps_each_loop) { @@ -1021,7 +1221,14 @@ sub pp_grepstart { $need_freetmps = 0; } write_back_stack(); - doop($op); + my $sym= doop($op); + my $next=$op->next; + $next->save; + my $nexttonext=$next->next; + $nexttonext->save; + save_or_restore_lexical_state($$nexttonext); + runtime(sprintf("if (PL_op == (($sym)->op_next)->op_next) goto %s;", + label($nexttonext))); return $op->next->other; } @@ -1032,7 +1239,16 @@ sub pp_mapstart { $need_freetmps = 0; } write_back_stack(); - doop($op); + # pp_mapstart can return either op_next->op_next or op_next->op_other and + # we need to be able to distinguish the two at runtime. + my $sym= doop($op); + my $next=$op->next; + $next->save; + my $nexttonext=$next->next; + $nexttonext->save; + save_or_restore_lexical_state($$nexttonext); + runtime(sprintf("if (PL_op == (($sym)->op_next)->op_next) goto %s;", + label($nexttonext))); return $op->next->other; } @@ -1049,6 +1265,7 @@ sub pp_grepwhile { # around that, we hack op_next to be our own op (purely because we # know it's a non-NULL pointer and can't be the same as op_other). $init->add("((LOGOP*)$sym)->op_next = $sym;"); + save_or_restore_lexical_state($$next); runtime(sprintf("if (PL_op == ($sym)->op_next) goto %s;", label($next))); $know_op = 0; return $op->other; @@ -1063,7 +1280,7 @@ sub pp_return { write_back_lexicals(REGISTER|TEMPORARY); write_back_stack(); doop($op); - runtime("PUTBACK;", "return (PL_op)?PL_op->op_next:0;"); + runtime("PUTBACK;", "return PL_op;"); $know_op = 0; return $op->next; } @@ -1077,30 +1294,31 @@ sub nyi { sub pp_range { my $op = shift; my $flags = $op->flags; - if (!($flags & OPf_KNOW)) { + if (!($flags & OPf_WANT)) { error("context of range unknown at compile-time"); } write_back_lexicals(); write_back_stack(); - if (!($flags & OPf_LIST)) { + unless (($flags & OPf_WANT)== OPf_WANT_LIST) { # We need to save our UNOP structure since pp_flop uses # it to find and adjust out targ. We don't need it ourselves. $op->save; + save_or_restore_lexical_state(${$op->other}); runtime sprintf("if (SvTRUE(PL_curpad[%d])) goto %s;", - $op->targ, label($op->false)); - unshift(@bblock_todo, $op->false); + $op->targ, label($op->other)); + unshift(@bblock_todo, $op->other); } - return $op->true; + return $op->next; } sub pp_flip { my $op = shift; my $flags = $op->flags; - if (!($flags & OPf_KNOW)) { + if (!($flags & OPf_WANT)) { error("context of flip unknown at compile-time"); } - if ($flags & OPf_LIST) { - return $op->first->false; + if (($flags & OPf_WANT)==OPf_WANT_LIST) { + return $op->first->other; } write_back_lexicals(); write_back_stack(); @@ -1116,9 +1334,10 @@ sub pp_flip { if ($op->flags & OPf_SPECIAL) { runtime("sv_setiv(PL_curpad[$ix], 1);"); } else { + save_or_restore_lexical_state(${$op->first->other}); runtime("\tsv_setiv(PL_curpad[$ix], 0);", "\tsp--;", - sprintf("\tgoto %s;", label($op->first->false))); + sprintf("\tgoto %s;", label($op->first->other))); } runtime("}", qq{sv_setpv(PL_curpad[$ix], "");}, @@ -1187,6 +1406,7 @@ sub pp_next { default_pp($op); my $nextop = $cxstack[$cxix]->{nextop}; push(@bblock_todo, $nextop); + save_or_restore_lexical_state($$nextop); runtime(sprintf("goto %s;", label($nextop))); return $op->next; } @@ -1210,6 +1430,7 @@ sub pp_redo { default_pp($op); my $redoop = $cxstack[$cxix]->{redoop}; push(@bblock_todo, $redoop); + save_or_restore_lexical_state($$redoop); runtime(sprintf("goto %s;", label($redoop))); return $op->next; } @@ -1238,6 +1459,7 @@ sub pp_last { default_pp($op); my $lastop = $cxstack[$cxix]->{lastop}->next; push(@bblock_todo, $lastop); + save_or_restore_lexical_state($$lastop); runtime(sprintf("goto %s;", label($lastop))); return $op->next; } @@ -1249,6 +1471,7 @@ sub pp_subst { my $sym = doop($op); my $replroot = $op->pmreplroot; if ($$replroot) { + save_or_restore_lexical_state($$replroot); runtime sprintf("if (PL_op == ((PMOP*)(%s))->op_pmreplroot) goto %s;", $sym, label($replroot)); $op->pmreplstart->save; @@ -1264,11 +1487,12 @@ sub pp_substcont { write_back_stack(); doop($op); my $pmop = $op->other; - warn sprintf("substcont: op = %s, pmop = %s\n", - peekop($op), peekop($pmop));#debug -# my $pmopsym = objsym($pmop); + # warn sprintf("substcont: op = %s, pmop = %s\n", + # peekop($op), peekop($pmop));#debug +# my $pmopsym = objsym($pmop); my $pmopsym = $pmop->save; # XXX can this recurse? - warn "pmopsym = $pmopsym\n";#debug +# warn "pmopsym = $pmopsym\n";#debug + save_or_restore_lexical_state(${$pmop->pmreplstart}); runtime sprintf("if (PL_op == ((PMOP*)(%s))->op_pmreplstart) goto %s;", $pmopsym, label($pmop->pmreplstart)); invalidate_lexicals(); @@ -1277,7 +1501,10 @@ sub pp_substcont { sub default_pp { my $op = shift; - my $ppname = $op->ppaddr; + my $ppname = "pp_" . $op->name; + if ($curcop and $need_curcop{$ppname}){ + $curcop->write_back; + } write_back_lexicals() unless $skip_lexicals{$ppname}; write_back_stack() unless $skip_stack{$ppname}; doop($op); @@ -1291,7 +1518,7 @@ sub default_pp { sub compile_op { my $op = shift; - my $ppname = $op->ppaddr; + my $ppname = "pp_" . $op->name; if (exists $ignore_op{$ppname}) { return $op->next; } @@ -1313,6 +1540,7 @@ sub compile_op { sub compile_bblock { my $op = shift; #warn "compile_bblock: ", peekop($op), "\n"; # debug + save_or_restore_lexical_state($$op); write_label($op); $know_op = 0; do { @@ -1326,15 +1554,26 @@ sub compile_bblock { sub cc { my ($name, $root, $start, @padlist) = @_; my $op; + if($done{$$start}){ + #warn "repeat=>".ref($start)."$name,\n";#debug + $decl->add(sprintf("#define $name %s",$done{$$start})); + return; + } init_pp($name); load_pad(@padlist); + %lexstate=(); B::Pseudoreg->new_scope; @cxstack = (); if ($debug_timings) { warn sprintf("Basic block analysis at %s\n", timing_info); } $leaders = find_leaders($root, $start); - @bblock_todo = ($start, values %$leaders); + my @leaders= keys %$leaders; + if ($#leaders > -1) { + @bblock_todo = ($start, values %$leaders) ; + } else{ + runtime("return PL_op?PL_op->op_next:0;"); + } if ($debug_timings) { warn sprintf("Compilation at %s\n", timing_info); } @@ -1344,7 +1583,7 @@ sub cc { next if !defined($op) || !$$op || $done{$$op}; #warn "...compiling it\n"; # debug do { - $done{$$op} = 1; + $done{$$op} = $name; $op = compile_bblock($op); if ($need_freetmps && $freetmps_each_bblock) { runtime("FREETMPS;"); @@ -1356,14 +1595,16 @@ sub cc { $need_freetmps = 0; } if (!$$op) { - runtime("PUTBACK;","return (PL_op)?PL_op->op_next:0;"); + runtime("PUTBACK;","return PL_op;"); } elsif ($done{$$op}) { + save_or_restore_lexical_state($$op); runtime(sprintf("goto %s;", label($op))); } } if ($debug_timings) { warn sprintf("Saving runtime at %s\n", timing_info); } + declare_pad(@padlist) ; save_runtime(); } @@ -1387,20 +1628,32 @@ sub cc_obj { sub cc_main { my @comppadlist = comppadlist->ARRAY; - my $curpad_nam = $comppadlist[0]->save; - my $curpad_sym = $comppadlist[1]->save; + my $curpad_nam = $comppadlist[0]->save; + my $curpad_sym = $comppadlist[1]->save; + my $init_av = init_av->save; my $start = cc_recurse("pp_main", main_root, main_start, @comppadlist); - save_unused_subs(@unused_sub_packages); + # Do save_unused_subs before saving inc_hv + save_unused_subs(); cc_recurse(); + my $inc_hv = svref_2object(\%INC)->save; + my $inc_av = svref_2object(\@INC)->save; + my $amagic_generate= amagic_generation; return if $errors; if (!defined($module)) { $init->add(sprintf("PL_main_root = s\\_%x;", ${main_root()}), "PL_main_start = $start;", "PL_curpad = AvARRAY($curpad_sym);", + "PL_initav = (AV *) $init_av;", + "GvHV(PL_incgv) = $inc_hv;", + "GvAV(PL_incgv) = $inc_av;", "av_store(CvPADLIST(PL_main_cv),0,SvREFCNT_inc($curpad_nam));", - "av_store(CvPADLIST(PL_main_cv),1,SvREFCNT_inc($curpad_sym));"); + "av_store(CvPADLIST(PL_main_cv),1,SvREFCNT_inc($curpad_sym));", + "PL_amagic_generation= $amagic_generate;", + ); + } + seek(STDOUT,0,0); #prevent print statements from BEGIN{} into the output output_boilerplate(); print "\n"; output_all("perl_init"); @@ -1419,11 +1672,11 @@ XS(boot_$cmodule) perl_init(); ENTER; SAVETMPS; - SAVESPTR(PL_curpad); - SAVESPTR(PL_op); + SAVEVPTR(PL_curpad); + SAVEVPTR(PL_op); PL_curpad = AvARRAY($curpad_sym); PL_op = $start; - pp_main(ARGS); + pp_main(aTHX); FREETMPS; LEAVE; ST(0) = &PL_sv_yes; @@ -1459,7 +1712,7 @@ sub compile { $module_name = $arg; } elsif ($opt eq "u") { $arg ||= shift @options; - push(@unused_sub_packages, $arg); + mark_unused($arg,undef); } elsif ($opt eq "f") { $arg ||= shift @options; my $value = $arg !~ s/^no-//; @@ -1485,7 +1738,7 @@ sub compile { } elsif ($opt eq "m") { $arg ||= shift @options; $module = $arg; - push(@unused_sub_packages, $arg); + mark_unused($arg,undef); } elsif ($opt eq "p") { $arg ||= shift @options; $patchlevel = $arg; diff --git a/contrib/perl5/ext/B/B/Debug.pm b/contrib/perl5/ext/B/B/Debug.pm index 7754a5a..ae7a973 100644 --- a/contrib/perl5/ext/B/B/Debug.pm +++ b/contrib/perl5/ext/B/B/Debug.pm @@ -39,13 +39,6 @@ sub B::LOGOP::debug { printf "\top_other\t0x%x\n", ${$op->other}; } -sub B::CONDOP::debug { - my ($op) = @_; - $op->B::UNOP::debug(); - printf "\top_true\t0x%x\n", ${$op->true}; - printf "\top_false\t0x%x\n", ${$op->false}; -} - sub B::LISTOP::debug { my ($op) = @_; $op->B::BINOP::debug(); @@ -67,16 +60,15 @@ sub B::PMOP::debug { sub B::COP::debug { my ($op) = @_; $op->B::OP::debug(); - my ($filegv) = $op->filegv; - printf <<'EOT', $op->label, ${$op->stash}, $$filegv, $op->seq, $op->arybase, $op->line; + printf <<'EOT', $op->label, $op->stashpv, $op->file, $op->seq, $op->arybase, $op->line, ${$op->warnings}; cop_label %s - cop_stash 0x%x - cop_filegv 0x%x + cop_stashpv %s + cop_file %s cop_seq %d cop_arybase %d cop_line %d + cop_warnings 0x%x EOT - $filegv->debug; } sub B::SVOP::debug { @@ -92,11 +84,10 @@ sub B::PVOP::debug { printf "\top_pv\t\t0x%x\n", $op->pv; } -sub B::GVOP::debug { +sub B::PADOP::debug { my ($op) = @_; $op->B::OP::debug(); - printf "\top_gv\t\t0x%x\n", ${$op->gv}; - $op->gv->debug; + printf "\top_padix\t\t%ld\n", $op->padix; } sub B::CVOP::debug { @@ -184,14 +175,14 @@ sub B::CV::debug { my ($start) = $sv->START; my ($root) = $sv->ROOT; my ($padlist) = $sv->PADLIST; + my ($file) = $sv->FILE; my ($gv) = $sv->GV; - my ($filegv) = $sv->FILEGV; - printf <<'EOT', $$stash, $$start, $$root, $$gv, $$filegv, $sv->DEPTH, $padlist, ${$sv->OUTSIDE}; + printf <<'EOT', $$stash, $$start, $$root, $$gv, $file, $sv->DEPTH, $padlist, ${$sv->OUTSIDE}; STASH 0x%x START 0x%x ROOT 0x%x GV 0x%x - FILEGV 0x%x + FILE %s DEPTH %d PADLIST 0x%x OUTSIDE 0x%x @@ -199,7 +190,6 @@ EOT $start->debug if $start; $root->debug if $root; $gv->debug if $gv; - $filegv->debug if $filegv; $padlist->debug if $padlist; } @@ -226,7 +216,7 @@ sub B::GV::debug { my ($av) = $gv->AV; my ($cv) = $gv->CV; $gv->B::SV::debug; - printf <<'EOT', $gv->NAME, $gv->STASH->NAME, $gv->STASH, $$sv, $gv->GvREFCNT, $gv->FORM, $$av, ${$gv->HV}, ${$gv->EGV}, $$cv, $gv->CVGEN, $gv->LINE, $gv->FILEGV, $gv->GvFLAGS; + printf <<'EOT', $gv->NAME, $gv->STASH->NAME, $gv->STASH, $$sv, $gv->GvREFCNT, $gv->FORM, $$av, ${$gv->HV}, ${$gv->EGV}, $$cv, $gv->CVGEN, $gv->LINE, $gv->FILE, $gv->GvFLAGS; NAME %s STASH %s (0x%x) SV 0x%x @@ -238,7 +228,7 @@ sub B::GV::debug { CV 0x%x CVGEN %d LINE %d - FILEGV 0x%x + FILE %s GvFLAGS 0x%x EOT $sv->debug if $sv; @@ -253,6 +243,7 @@ sub B::SPECIAL::debug { sub compile { my $order = shift; + B::clearsym(); if ($order eq "exec") { return sub { walkoptree_exec(main_start, "debug") } } else { diff --git a/contrib/perl5/ext/B/B/Deparse.pm b/contrib/perl5/ext/B/B/Deparse.pm index 5e0bd1d..cd53c11 100644 --- a/contrib/perl5/ext/B/B/Deparse.pm +++ b/contrib/perl5/ext/B/B/Deparse.pm @@ -1,5 +1,5 @@ # B::Deparse.pm -# Copyright (c) 1998 Stephen McCamant. All rights reserved. +# Copyright (c) 1998, 1999 Stephen McCamant. All rights reserved. # This module is free software; you can redistribute and/or modify # it under the same terms as Perl itself. @@ -7,9 +7,17 @@ # but essentially none of his code remains. package B::Deparse; -use Carp 'cluck'; -use B qw(class main_root main_start main_cv svref_2object); -$VERSION = 0.56; +use Carp 'cluck', 'croak'; +use Config; +use B qw(class main_root main_start main_cv svref_2object opnumber + OPf_WANT OPf_WANT_VOID OPf_WANT_SCALAR OPf_WANT_LIST + OPf_KIDS OPf_REF OPf_STACKED OPf_SPECIAL + OPpLVAL_INTRO OPpENTERSUB_AMPER OPpSLICE OPpCONST_BARE + OPpTRANS_SQUASH OPpTRANS_DELETE OPpTRANS_COMPLEMENT OPpTARGET_MY + SVf_IOK SVf_NOK SVf_ROK SVf_POK + PMf_KEEP PMf_GLOBAL PMf_CONTINUE PMf_EVAL PMf_ONCE + PMf_MULTILINE PMf_SINGLELINE PMf_FOLD PMf_EXTENDED); +$VERSION = 0.59; use strict; # Changes between 0.50 and 0.51: @@ -26,17 +34,17 @@ use strict; # Changes between 0.51 and 0.52: # - added pp_threadsv (special variables under USE_THREADS) # - added documentation -# Changes between 0.52 and 0.53 +# Changes between 0.52 and 0.53: # - many changes adding precedence contexts and associativity # - added `-p' and `-s' output style options # - various other minor fixes -# Changes between 0.53 and 0.54 +# Changes between 0.53 and 0.54: # - added support for new `for (1..100)' optimization, # thanks to Gisle Aas -# Changes between 0.54 and 0.55 +# Changes between 0.54 and 0.55: # - added support for new qr// construct # - added support for new pp_regcreset OP -# Changes between 0.55 and 0.56 +# Changes between 0.55 and 0.56: # - tested on base/*.t, cmd/*.t, comp/*.t, io/*.t # - fixed $# on non-lexicals broken in last big rewrite # - added temporary fix for change in opcode of OP_STRINGIFY @@ -50,17 +58,51 @@ use strict; # - print doubled rv2gv (a bug) as `*{*GV}' instead of illegal `**GV' # - added semicolons at the ends of blocks # - added -l `#line' declaration option -- fixes cmd/subval.t 27,28 +# Changes between 0.56 and 0.561: +# - fixed multiply-declared my var in pp_truncate (thanks to Sarathy) +# - used new B.pm symbolic constants (done by Nick Ing-Simmons) +# Changes between 0.561 and 0.57: +# - stylistic changes to symbolic constant stuff +# - handled scope in s///e replacement code +# - added unquote option for expanding "" into concats, etc. +# - split method and proto parts of pp_entersub into separate functions +# - various minor cleanups +# Changes after 0.57: +# - added parens in \&foo (patch by Albert Dvornik) +# Changes between 0.57 and 0.58: +# - fixed `0' statements that weren't being printed +# - added methods for use from other programs +# (based on patches from James Duncan and Hugo van der Sanden) +# - added -si and -sT to control indenting (also based on a patch from Hugo) +# - added -sv to print something else instead of '???' +# - preliminary version of utf8 tr/// handling +# Changes after 0.58: +# - uses of $op->ppaddr changed to new $op->name (done by Sarathy) +# - added support for Hugo's new OP_SETSTATE (like nextstate) +# Changes between 0.58 and 0.59 +# - added support for Chip's OP_METHOD_NAMED +# - added support for Ilya's OPpTARGET_MY optimization +# - elided arrows before `()' subscripts when possible # Todo: +# - finish tr/// changes +# - add option for even more parens (generalize \&foo change) # - {} around variables in strings ("${var}letters") # base/lex.t 25-27 # comp/term.t 11 -# - generate symbolic constants directly from core source # - left/right context +# - recognize `use utf8', `use integer', etc +# - treat top-level block specially for incremental output +# - interpret in high bit chars in string as utf8 \x{...} (when?) +# - copy comments (look at real text with $^P?) # - avoid semis in one-statement blocks # - associativity of &&=, ||=, ?: # - ',' => '=>' (auto-unquote?) # - break long lines ("\r" as discretionary break?) +# - configurable syntax highlighting: ANSI color, HTML, TeX, etc. +# - more style options: brace style, hex vs. octal, quotes, ... +# - print big ints as hex/octal instead of decimal (heuristic?) +# - handle `my $x if 0'? # - include values of variables (e.g. set in BEGIN) # - coordinate with Data::Dumper (both directions? see previous) # - version using op_next instead of op_first/sibling? @@ -103,7 +145,11 @@ use strict; # # parens: -p # linenums: -l +# unquote: -q # cuddle: ` ' or `\n', depending on -sC +# indent_size: -si +# use_tabs: -sT +# ex_const: -sv # A little explanation of how precedence contexts and associativity # work: @@ -182,13 +228,10 @@ sub next_todo { return "format $name =\n" . $self->deparse_format($ent->[1]->FORM). "\n"; } else { - return "sub $name " . - $self->deparse_sub($ent->[1]->CV); + return "sub $name " . $self->deparse_sub($ent->[1]->CV); } } -sub OPf_KIDS () { 4 } - sub walk_tree { my($op, $sub) = @_; $sub->($op); @@ -208,19 +251,20 @@ sub walk_sub { return if !$op or null $op; walk_tree($op, sub { my $op = shift; - if ($op->ppaddr eq "pp_gv") { - if ($op->next->ppaddr eq "pp_entersub") { - next if $self->{'subs_done'}{$ {$op->gv}}++; - next if class($op->gv->CV) eq "SPECIAL"; - $self->todo($op->gv, $op->gv->CV, 0); - $self->walk_sub($op->gv->CV); - } elsif ($op->next->ppaddr eq "pp_enterwrite" - or ($op->next->ppaddr eq "pp_rv2gv" - and $op->next->next->ppaddr eq "pp_enterwrite")) { - next if $self->{'forms_done'}{$ {$op->gv}}++; - next if class($op->gv->FORM) eq "SPECIAL"; - $self->todo($op->gv, $op->gv->FORM, 1); - $self->walk_sub($op->gv->FORM); + if ($op->name eq "gv") { + my $gv = $self->maybe_padgv($op); + if ($op->next->name eq "entersub") { + next if $self->{'subs_done'}{$$gv}++; + next if class($gv->CV) eq "SPECIAL"; + $self->todo($gv, $gv->CV, 0); + $self->walk_sub($gv->CV); + } elsif ($op->next->name eq "enterwrite" + or ($op->next->name eq "rv2gv" + and $op->next->next->name eq "enterwrite")) { + next if $self->{'forms_done'}{$$gv}++; + next if class($gv->FORM) eq "SPECIAL"; + $self->todo($gv, $gv->FORM, 1); + $self->walk_sub($gv->FORM); } } }); @@ -279,37 +323,57 @@ sub style_opts { while (length($opt = substr($opts, 0, 1))) { if ($opt eq "C") { $self->{'cuddle'} = " "; + $opts = substr($opts, 1); + } elsif ($opt eq "i") { + $opts =~ s/^i(\d+)//; + $self->{'indent_size'} = $1; + } elsif ($opt eq "T") { + $self->{'use_tabs'} = 1; + $opts = substr($opts, 1); + } elsif ($opt eq "v") { + $opts =~ s/^v([^.]*)(.|$)//; + $self->{'ex_const'} = $1; } - $opts = substr($opts, 1); } } +sub new { + my $class = shift; + my $self = bless {}, $class; + $self->{'subs_todo'} = []; + $self->{'curstash'} = "main"; + $self->{'cuddle'} = "\n"; + $self->{'indent_size'} = 4; + $self->{'use_tabs'} = 0; + $self->{'ex_const'} = "'???'"; + while (my $arg = shift @_) { + if (substr($arg, 0, 2) eq "-u") { + $self->stash_subs(substr($arg, 2)); + } elsif ($arg eq "-p") { + $self->{'parens'} = 1; + } elsif ($arg eq "-l") { + $self->{'linenums'} = 1; + } elsif ($arg eq "-q") { + $self->{'unquote'} = 1; + } elsif (substr($arg, 0, 2) eq "-s") { + $self->style_opts(substr $arg, 2); + } + } + return $self; +} + sub compile { my(@args) = @_; return sub { - my $self = bless {}; - my $arg; - $self->{'subs_todo'} = []; + my $self = B::Deparse->new(@args); $self->stash_subs("main"); $self->{'curcv'} = main_cv; - $self->{'curstash'} = "main"; - $self->{'cuddle'} = "\n"; - while ($arg = shift @args) { - if (substr($arg, 0, 2) eq "-u") { - $self->stash_subs(substr($arg, 2)); - } elsif ($arg eq "-p") { - $self->{'parens'} = 1; - } elsif ($arg eq "-l") { - $self->{'linenums'} = 1; - } elsif (substr($arg, 0, 2) eq "-s") { - $self->style_opts(substr $arg, 2); - } - } $self->walk_sub(main_cv, main_start); print $self->print_protos; @{$self->{'subs_todo'}} = - sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}}; - print indent($self->deparse(main_root, 0)), "\n" unless null main_root; + sort {$a->[0] <=> $b->[0]} @{$self->{'subs_todo'}}; + print $self->indent($self->deparse(main_root, 0)), "\n" + unless null main_root; my @text; while (scalar(@{$self->{'subs_todo'}})) { push @text, $self->next_todo; @@ -318,25 +382,38 @@ sub compile { } } +sub coderef2text { + my $self = shift; + my $sub = shift; + croak "Usage: ->coderef2text(CODEREF)" unless ref($sub) eq "CODE"; + return $self->indent($self->deparse_sub(svref_2object($sub))); +} + sub deparse { my $self = shift; my($op, $cx) = @_; # cluck if class($op) eq "NULL"; - my $meth = $op->ppaddr; +# return $self->$ {\("pp_" . $op->name)}($op, $cx); + my $meth = "pp_" . $op->name; return $self->$meth($op, $cx); } sub indent { + my $self = shift; my $txt = shift; my @lines = split(/\n/, $txt); my $leader = ""; + my $level = 0; my $line; for $line (@lines) { - if (substr($line, 0, 1) eq "\t") { - $leader = $leader . " "; - $line = substr($line, 1); - } elsif (substr($line, 0, 1) eq "\b") { - $leader = substr($leader, 0, length($leader) - 4); + my $cmd = substr($line, 0, 1); + if ($cmd eq "\t" or $cmd eq "\b") { + $level += ($cmd eq "\t" ? 1 : -1) * $self->{'indent_size'}; + if ($self->{'use_tabs'}) { + $leader = "\t" x ($level / 8) . " " x ($level % 8); + } else { + $leader = " " x $level; + } $line = substr($line, 1); } if (substr($line, 0, 1) eq "\f") { @@ -349,8 +426,6 @@ sub indent { return join("\n", @lines); } -sub SVf_POK () {0x40000} - sub deparse_sub { my $self = shift; my $cv = shift; @@ -382,7 +457,7 @@ sub deparse_format { $op = $op->sibling; # skip nextstate my @exprs; $kid = $op->first->sibling; # skip pushmark - push @text, $kid->sv->PV; + push @text, $self->const_sv($kid)->PV; $kid = $kid->sibling; for (; not null $kid; $kid = $kid->sibling) { push @exprs, $self->deparse($kid, 0); @@ -393,47 +468,38 @@ sub deparse_format { return join("", @text) . "."; } -# the aassign in-common check messes up SvCUR (always setting it -# to a value >= 100), but it's probably safe to assume there -# won't be any NULs in the names of my() variables. (with -# stash variables, I wouldn't be so sure) -sub padname_fix { - my $str = shift; - $str = substr($str, 0, index($str, "\0")) if index($str, "\0") != -1; - return $str; -} - sub is_scope { my $op = shift; - return $op->ppaddr eq "pp_leave" || $op->ppaddr eq "pp_scope" - || $op->ppaddr eq "pp_lineseq" - || ($op->ppaddr eq "pp_null" && class($op) eq "UNOP" - && (is_scope($op->first) || $op->first->ppaddr eq "pp_enter")); + return $op->name eq "leave" || $op->name eq "scope" + || $op->name eq "lineseq" + || ($op->name eq "null" && class($op) eq "UNOP" + && (is_scope($op->first) || $op->first->name eq "enter")); } sub is_state { - my $name = $_[0]->ppaddr; - return $name eq "pp_nextstate" || $name eq "pp_dbstate"; + my $name = $_[0]->name; + return $name eq "nextstate" || $name eq "dbstate" || $name eq "setstate"; } sub is_miniwhile { # check for one-line loop (`foo() while $y--') my $op = shift; return (!null($op) and null($op->sibling) - and $op->ppaddr eq "pp_null" and class($op) eq "UNOP" - and (($op->first->ppaddr =~ /^pp_(and|or)$/ - and $op->first->first->sibling->ppaddr eq "pp_lineseq") - or ($op->first->ppaddr eq "pp_lineseq" + and $op->name eq "null" and class($op) eq "UNOP" + and (($op->first->name =~ /^(and|or)$/ + and $op->first->first->sibling->name eq "lineseq") + or ($op->first->name eq "lineseq" and not null $op->first->first->sibling - and $op->first->first->sibling->ppaddr eq "pp_unstack") + and $op->first->first->sibling->name eq "unstack") )); } sub is_scalar { my $op = shift; - return ($op->ppaddr eq "pp_rv2sv" or - $op->ppaddr eq "pp_padsv" or - $op->ppaddr eq "pp_gv" or # only in array/hash constructs - !null($op->first) && $op->first->ppaddr eq "pp_gvsv"); + return ($op->name eq "rv2sv" or + $op->name eq "padsv" or + $op->name eq "gv" or # only in array/hash constructs + $op->flags & OPf_KIDS && !null($op->first) + && $op->first->name eq "gvsv"); } sub maybe_parens { @@ -483,18 +549,28 @@ sub maybe_parens_func { } } -sub OPp_LVAL_INTRO () { 128 } - sub maybe_local { my $self = shift; my($op, $cx, $text) = @_; - if ($op->private & OPp_LVAL_INTRO and not $self->{'avoid_local'}{$$op}) { + if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) { return $self->maybe_parens_func("local", $text, $cx, 16); } else { return $text; } } +sub maybe_targmy { + my $self = shift; + my($op, $cx, $func, @args) = @_; + if ($op->private & OPpTARGET_MY) { + my $var = $self->padname($op->targ); + my $val = $func->($self, $op, 7, @args); + return $self->maybe_parens("$var = $val", $cx, 7); + } else { + return $func->($self, $op, $cx, @args); + } +} + sub padname_sv { my $self = shift; my $targ = shift; @@ -504,7 +580,7 @@ sub padname_sv { sub maybe_my { my $self = shift; my($op, $cx, $text) = @_; - if ($op->private & OPp_LVAL_INTRO and not $self->{'avoid_local'}{$$op}) { + if ($op->private & OPpLVAL_INTRO and not $self->{'avoid_local'}{$$op}) { return $self->maybe_parens_func("my", $text, $cx, 16); } else { return $text; @@ -606,10 +682,10 @@ sub pp_leave { $kid = $op->first->sibling; # skip enter if (is_miniwhile($kid)) { my $top = $kid->first; - my $name = $top->ppaddr; - if ($name eq "pp_and") { + my $name = $top->name; + if ($name eq "and") { $name = "while"; - } elsif ($name eq "pp_or") { + } elsif ($name eq "or") { $name = "until"; } else { # no conditional -> while 1 or until 0 return $self->deparse($top->first, 1) . " while 1"; @@ -628,7 +704,7 @@ sub pp_leave { last if null $kid; } $expr .= $self->deparse($kid, 0); - push @exprs, $expr if $expr; + push @exprs, $expr if length $expr; } if ($cx > 0) { # inside an expression return "do { " . join(";\n", @exprs) . " }"; @@ -650,7 +726,7 @@ sub pp_scope { last if null $kid; } $expr .= $self->deparse($kid, 0); - push @exprs, $expr if $expr; + push @exprs, $expr if length $expr; } if ($cx > 0) { # inside an expression, (a do {} while for lineseq) return "do { " . join(";\n", @exprs) . " }"; @@ -696,19 +772,20 @@ sub pp_nextstate { and $seq > $self->{'subs_todo'}[0][0]) { push @text, $self->next_todo; } - my $stash = $op->stash->NAME; + my $stash = $op->stashpv; if ($stash ne $self->{'curstash'}) { push @text, "package $stash;\n"; $self->{'curstash'} = $stash; } if ($self->{'linenums'}) { push @text, "\f#line " . $op->line . - ' "' . substr($op->filegv->NAME, 2), qq'"\n'; + ' "' . $op->file, qq'"\n'; } return join("", @text); } sub pp_dbstate { pp_nextstate(@_) } +sub pp_setstate { pp_nextstate(@_) } sub pp_unstack { return "" } # see also leaveloop @@ -721,9 +798,9 @@ sub baseop { sub pp_stub { baseop(@_, "()") } sub pp_wantarray { baseop(@_, "wantarray") } sub pp_fork { baseop(@_, "fork") } -sub pp_wait { baseop(@_, "wait") } -sub pp_getppid { baseop(@_, "getppid") } -sub pp_time { baseop(@_, "time") } +sub pp_wait { maybe_targmy(@_, \&baseop, "wait") } +sub pp_getppid { maybe_targmy(@_, \&baseop, "getppid") } +sub pp_time { maybe_targmy(@_, \&baseop, "time") } sub pp_tms { baseop(@_, "times") } sub pp_ghostent { baseop(@_, "gethostent") } sub pp_gnetent { baseop(@_, "getnetent") } @@ -757,18 +834,19 @@ sub pfixop { sub pp_preinc { pfixop(@_, "++", 23) } sub pp_predec { pfixop(@_, "--", 23) } -sub pp_postinc { pfixop(@_, "++", 23, POSTFIX) } -sub pp_postdec { pfixop(@_, "--", 23, POSTFIX) } +sub pp_postinc { maybe_targmy(@_, \&pfixop, "++", 23, POSTFIX) } +sub pp_postdec { maybe_targmy(@_, \&pfixop, "--", 23, POSTFIX) } sub pp_i_preinc { pfixop(@_, "++", 23) } sub pp_i_predec { pfixop(@_, "--", 23) } -sub pp_i_postinc { pfixop(@_, "++", 23, POSTFIX) } -sub pp_i_postdec { pfixop(@_, "--", 23, POSTFIX) } -sub pp_complement { pfixop(@_, "~", 21) } +sub pp_i_postinc { maybe_targmy(@_, \&pfixop, "++", 23, POSTFIX) } +sub pp_i_postdec { maybe_targmy(@_, \&pfixop, "--", 23, POSTFIX) } +sub pp_complement { maybe_targmy(@_. \&pfixop, "~", 21) } -sub pp_negate { +sub pp_negate { maybe_targmy(@_, \&real_negate) } +sub real_negate { my $self = shift; my($op, $cx) = @_; - if ($op->first->ppaddr =~ /^pp_(i_)?negate$/) { + if ($op->first->name =~ /^(i_)?negate$/) { # avoid --$x $self->pfixop($op, $cx, "-", 21.5); } else { @@ -787,11 +865,9 @@ sub pp_not { } } -sub OPf_SPECIAL () { 128 } - sub unop { my $self = shift; - my($op, $cx, $name, $prec, $flags) = (@_, 0, 0); + my($op, $cx, $name) = @_; my $kid; if ($op->flags & OPf_KIDS) { $kid = $op->first; @@ -801,36 +877,31 @@ sub unop { } } -sub pp_chop { unop(@_, "chop") } -sub pp_chomp { unop(@_, "chomp") } -sub pp_schop { unop(@_, "chop") } -sub pp_schomp { unop(@_, "chomp") } +sub pp_chop { maybe_targmy(@_, \&unop, "chop") } +sub pp_chomp { maybe_targmy(@_, \&unop, "chomp") } +sub pp_schop { maybe_targmy(@_, \&unop, "chop") } +sub pp_schomp { maybe_targmy(@_, \&unop, "chomp") } sub pp_defined { unop(@_, "defined") } sub pp_undef { unop(@_, "undef") } sub pp_study { unop(@_, "study") } sub pp_ref { unop(@_, "ref") } sub pp_pos { maybe_local(@_, unop(@_, "pos")) } -sub pp_sin { unop(@_, "sin") } -sub pp_cos { unop(@_, "cos") } -sub pp_rand { unop(@_, "rand") } +sub pp_sin { maybe_targmy(@_, \&unop, "sin") } +sub pp_cos { maybe_targmy(@_, \&unop, "cos") } +sub pp_rand { maybe_targmy(@_, \&unop, "rand") } sub pp_srand { unop(@_, "srand") } -sub pp_exp { unop(@_, "exp") } -sub pp_log { unop(@_, "log") } -sub pp_sqrt { unop(@_, "sqrt") } -sub pp_int { unop(@_, "int") } -sub pp_hex { unop(@_, "hex") } -sub pp_oct { unop(@_, "oct") } -sub pp_abs { unop(@_, "abs") } - -sub pp_length { unop(@_, "length") } -sub pp_ord { unop(@_, "ord") } -sub pp_chr { unop(@_, "chr") } -sub pp_ucfirst { unop(@_, "ucfirst") } -sub pp_lcfirst { unop(@_, "lcfirst") } -sub pp_uc { unop(@_, "uc") } -sub pp_lc { unop(@_, "lc") } -sub pp_quotemeta { unop(@_, "quotemeta") } +sub pp_exp { maybe_targmy(@_, \&unop, "exp") } +sub pp_log { maybe_targmy(@_, \&unop, "log") } +sub pp_sqrt { maybe_targmy(@_, \&unop, "sqrt") } +sub pp_int { maybe_targmy(@_, \&unop, "int") } +sub pp_hex { maybe_targmy(@_, \&unop, "hex") } +sub pp_oct { maybe_targmy(@_, \&unop, "oct") } +sub pp_abs { maybe_targmy(@_, \&unop, "abs") } + +sub pp_length { maybe_targmy(@_, \&unop, "length") } +sub pp_ord { maybe_targmy(@_, \&unop, "ord") } +sub pp_chr { maybe_targmy(@_, \&unop, "chr") } sub pp_each { unop(@_, "each") } sub pp_values { unop(@_, "values") } @@ -856,19 +927,19 @@ sub pp_tell { unop(@_, "tell") } sub pp_getsockname { unop(@_, "getsockname") } sub pp_getpeername { unop(@_, "getpeername") } -sub pp_chdir { unop(@_, "chdir") } -sub pp_chroot { unop(@_, "chroot") } +sub pp_chdir { maybe_targmy(@_, \&unop, "chdir") } +sub pp_chroot { maybe_targmy(@_, \&unop, "chroot") } sub pp_readlink { unop(@_, "readlink") } -sub pp_rmdir { unop(@_, "rmdir") } +sub pp_rmdir { maybe_targmy(@_, \&unop, "rmdir") } sub pp_readdir { unop(@_, "readdir") } sub pp_telldir { unop(@_, "telldir") } sub pp_rewinddir { unop(@_, "rewinddir") } sub pp_closedir { unop(@_, "closedir") } -sub pp_getpgrp { unop(@_, "getpgrp") } +sub pp_getpgrp { maybe_targmy(@_, \&unop, "getpgrp") } sub pp_localtime { unop(@_, "localtime") } sub pp_gmtime { unop(@_, "gmtime") } sub pp_alarm { unop(@_, "alarm") } -sub pp_sleep { unop(@_, "sleep") } +sub pp_sleep { maybe_targmy(@_, \&unop, "sleep") } sub pp_dofile { unop(@_, "do") } sub pp_entereval { unop(@_, "eval") } @@ -894,8 +965,6 @@ sub pp_exists { $cx, 16); } -sub OPpSLICE () { 64 } - sub pp_delete { my $self = shift; my($op, $cx) = @_; @@ -911,15 +980,13 @@ sub pp_delete { } } -sub OPp_CONST_BARE () { 64 } - sub pp_require { my $self = shift; my($op, $cx) = @_; - if (class($op) eq "UNOP" and $op->first->ppaddr eq "pp_const" - and $op->first->private & OPp_CONST_BARE) + if (class($op) eq "UNOP" and $op->first->name eq "const" + and $op->first->private & OPpCONST_BARE) { - my $name = $op->first->sv->PV; + my $name = $self->const_sv($op->first)->PV; $name =~ s[/][::]g; $name =~ s/\.pm//g; return "require($name)"; @@ -943,20 +1010,19 @@ sub pp_scalar { sub padval { my $self = shift; my $targ = shift; + #cluck "curcv was undef" unless $self->{curcv}; return (($self->{'curcv'}->PADLIST->ARRAY)[1]->ARRAY)[$targ]; } -sub OPf_REF () { 16 } - sub pp_refgen { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; - if ($kid->ppaddr eq "pp_null") { + if ($kid->name eq "null") { $kid = $kid->first; - if ($kid->ppaddr eq "pp_anonlist" || $kid->ppaddr eq "pp_anonhash") { - my($pre, $post) = @{{"pp_anonlist" => ["[","]"], - "pp_anonhash" => ["{","}"]}->{$kid->ppaddr}}; + if ($kid->name eq "anonlist" || $kid->name eq "anonhash") { + my($pre, $post) = @{{"anonlist" => ["[","]"], + "anonhash" => ["{","}"]}->{$kid->name}}; my($expr, @exprs); $kid = $kid->first->sibling; # skip pushmark for (; !null($kid); $kid = $kid->sibling) { @@ -965,16 +1031,25 @@ sub pp_refgen { } return $pre . join(", ", @exprs) . $post; } elsif (!null($kid->sibling) and - $kid->sibling->ppaddr eq "pp_anoncode") { + $kid->sibling->name eq "anoncode") { return "sub " . $self->deparse_sub($self->padval($kid->sibling->targ)); - } elsif ($kid->ppaddr eq "pp_pushmark" - and $kid->sibling->ppaddr =~ /^pp_(pad|rv2)[ah]v$/ - and not $kid->sibling->flags & OPf_REF) { - # The @a in \(@a) isn't in ref context, but only when the - # parens are there. - return "\\(" . $self->deparse($kid->sibling, 1) . ")"; - } + } elsif ($kid->name eq "pushmark") { + my $sib_name = $kid->sibling->name; + if ($sib_name =~ /^(pad|rv2)[ah]v$/ + and not $kid->sibling->flags & OPf_REF) + { + # The @a in \(@a) isn't in ref context, but only when the + # parens are there. + return "\\(" . $self->deparse($kid->sibling, 1) . ")"; + } elsif ($sib_name eq 'entersub') { + my $text = $self->deparse($kid->sibling, 1); + # Always show parens for \(&func()), but only with -p otherwise + $text = "($text)" if $self->{'parens'} + or $kid->sibling->private & OPpENTERSUB_AMPER; + return "\\$text"; + } + } } $self->pfixop($op, $cx, "\\", 20); } @@ -985,13 +1060,31 @@ sub pp_readline { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; - $kid = $kid->first if $kid->ppaddr eq "pp_rv2gv"; # <$fh> - if ($kid->ppaddr eq "pp_rv2gv") { - $kid = $kid->first; - } + $kid = $kid->first if $kid->name eq "rv2gv"; # <$fh> return "<" . $self->deparse($kid, 1) . ">"; } +# Unary operators that can occur as pseudo-listops inside double quotes +sub dq_unop { + my $self = shift; + my($op, $cx, $name, $prec, $flags) = (@_, 0, 0); + my $kid; + if ($op->flags & OPf_KIDS) { + $kid = $op->first; + # If there's more than one kid, the first is an ex-pushmark. + $kid = $kid->sibling if not null $kid->sibling; + return $self->maybe_parens_unop($name, $kid, $cx); + } else { + return $name . ($op->flags & OPf_SPECIAL ? "()" : ""); + } +} + +sub pp_ucfirst { dq_unop(@_, "ucfirst") } +sub pp_lcfirst { dq_unop(@_, "lcfirst") } +sub pp_uc { dq_unop(@_, "uc") } +sub pp_lc { dq_unop(@_, "lc") } +sub pp_quotemeta { maybe_targmy(@_, \&dq_unop, "quotemeta") } + sub loopex { my $self = shift; my ($op, $cx, $name) = @_; @@ -1019,7 +1112,7 @@ sub ftst { # Genuine `-X' filetests are exempt from the LLAFR, but not # l?stat(); for the sake of clarity, give'em all parens return $self->maybe_parens_unop($name, $op->first, $cx); - } elsif (class($op) eq "GVOP") { + } elsif (class($op) eq "SVOP") { return $self->maybe_parens_func($name, $self->pp_gv($op, 1), $cx, 16); } else { # I don't think baseop filetests ever survive ck_ftst, but... return $name; @@ -1059,19 +1152,17 @@ sub pp_ftbinary { ftst(@_, "-B") } sub SWAP_CHILDREN () { 1 } sub ASSIGN () { 2 } # has OP= variant -sub OPf_STACKED () { 64 } - my(%left, %right); sub assoc_class { my $op = shift; - my $name = $op->ppaddr; - if ($name eq "pp_concat" and $op->first->ppaddr eq "pp_concat") { + my $name = $op->name; + if ($name eq "concat" and $op->first->name eq "concat") { # avoid spurious `=' -- see comment in pp_concat - return "pp_concat"; + return "concat"; } - if ($name eq "pp_null" and class($op) eq "UNOP" - and $op->first->ppaddr =~ /^pp_(and|x?or)$/ + if ($name eq "null" and class($op) eq "UNOP" + and $op->first->name =~ /^(and|x?or)$/ and null $op->first->sibling) { # Like all conditional constructs, OP_ANDs and OP_ORs are topped @@ -1088,25 +1179,25 @@ sub assoc_class { # $a + $b + $c is equivalent to ($a + $b) + $c BEGIN { - %left = ('pp_multiply' => 19, 'pp_i_multiply' => 19, - 'pp_divide' => 19, 'pp_i_divide' => 19, - 'pp_modulo' => 19, 'pp_i_modulo' => 19, - 'pp_repeat' => 19, - 'pp_add' => 18, 'pp_i_add' => 18, - 'pp_subtract' => 18, 'pp_i_subtract' => 18, - 'pp_concat' => 18, - 'pp_left_shift' => 17, 'pp_right_shift' => 17, - 'pp_bit_and' => 13, - 'pp_bit_or' => 12, 'pp_bit_xor' => 12, - 'pp_and' => 3, - 'pp_or' => 2, 'pp_xor' => 2, + %left = ('multiply' => 19, 'i_multiply' => 19, + 'divide' => 19, 'i_divide' => 19, + 'modulo' => 19, 'i_modulo' => 19, + 'repeat' => 19, + 'add' => 18, 'i_add' => 18, + 'subtract' => 18, 'i_subtract' => 18, + 'concat' => 18, + 'left_shift' => 17, 'right_shift' => 17, + 'bit_and' => 13, + 'bit_or' => 12, 'bit_xor' => 12, + 'and' => 3, + 'or' => 2, 'xor' => 2, ); } sub deparse_binop_left { my $self = shift; my($op, $left, $prec) = @_; - if ($left{assoc_class($op)} + if ($left{assoc_class($op)} && $left{assoc_class($left)} and $left{assoc_class($op)} == $left{assoc_class($left)}) { return $self->deparse($left, $prec - .00001); @@ -1119,27 +1210,27 @@ sub deparse_binop_left { # $a = $b = $c is equivalent to $a = ($b = $c) BEGIN { - %right = ('pp_pow' => 22, - 'pp_sassign=' => 7, 'pp_aassign=' => 7, - 'pp_multiply=' => 7, 'pp_i_multiply=' => 7, - 'pp_divide=' => 7, 'pp_i_divide=' => 7, - 'pp_modulo=' => 7, 'pp_i_modulo=' => 7, - 'pp_repeat=' => 7, - 'pp_add=' => 7, 'pp_i_add=' => 7, - 'pp_subtract=' => 7, 'pp_i_subtract=' => 7, - 'pp_concat=' => 7, - 'pp_left_shift=' => 7, 'pp_right_shift=' => 7, - 'pp_bit_and=' => 7, - 'pp_bit_or=' => 7, 'pp_bit_xor=' => 7, - 'pp_andassign' => 7, - 'pp_orassign' => 7, + %right = ('pow' => 22, + 'sassign=' => 7, 'aassign=' => 7, + 'multiply=' => 7, 'i_multiply=' => 7, + 'divide=' => 7, 'i_divide=' => 7, + 'modulo=' => 7, 'i_modulo=' => 7, + 'repeat=' => 7, + 'add=' => 7, 'i_add=' => 7, + 'subtract=' => 7, 'i_subtract=' => 7, + 'concat=' => 7, + 'left_shift=' => 7, 'right_shift=' => 7, + 'bit_and=' => 7, + 'bit_or=' => 7, 'bit_xor=' => 7, + 'andassign' => 7, + 'orassign' => 7, ); } sub deparse_binop_right { my $self = shift; my($op, $right, $prec) = @_; - if ($right{assoc_class($op)} + if ($right{assoc_class($op)} && $right{assoc_class($right)} and $right{assoc_class($op)} == $right{assoc_class($right)}) { return $self->deparse($right, $prec - .00001); @@ -1166,23 +1257,23 @@ sub binop { return $self->maybe_parens("$left $opname$eq $right", $cx, $prec); } -sub pp_add { binop(@_, "+", 18, ASSIGN) } -sub pp_multiply { binop(@_, "*", 19, ASSIGN) } -sub pp_subtract { binop(@_, "-",18, ASSIGN) } -sub pp_divide { binop(@_, "/", 19, ASSIGN) } -sub pp_modulo { binop(@_, "%", 19, ASSIGN) } -sub pp_i_add { binop(@_, "+", 18, ASSIGN) } -sub pp_i_multiply { binop(@_, "*", 19, ASSIGN) } -sub pp_i_subtract { binop(@_, "-", 18, ASSIGN) } -sub pp_i_divide { binop(@_, "/", 19, ASSIGN) } -sub pp_i_modulo { binop(@_, "%", 19, ASSIGN) } -sub pp_pow { binop(@_, "**", 22, ASSIGN) } - -sub pp_left_shift { binop(@_, "<<", 17, ASSIGN) } -sub pp_right_shift { binop(@_, ">>", 17, ASSIGN) } -sub pp_bit_and { binop(@_, "&", 13, ASSIGN) } -sub pp_bit_or { binop(@_, "|", 12, ASSIGN) } -sub pp_bit_xor { binop(@_, "^", 12, ASSIGN) } +sub pp_add { maybe_targmy(@_, \&binop, "+", 18, ASSIGN) } +sub pp_multiply { maybe_targmy(@_, \&binop, "*", 19, ASSIGN) } +sub pp_subtract { maybe_targmy(@_, \&binop, "-",18, ASSIGN) } +sub pp_divide { maybe_targmy(@_, \&binop, "/", 19, ASSIGN) } +sub pp_modulo { maybe_targmy(@_, \&binop, "%", 19, ASSIGN) } +sub pp_i_add { maybe_targmy(@_, \&binop, "+", 18, ASSIGN) } +sub pp_i_multiply { maybe_targmy(@_, \&binop, "*", 19, ASSIGN) } +sub pp_i_subtract { maybe_targmy(@_, \&binop, "-", 18, ASSIGN) } +sub pp_i_divide { maybe_targmy(@_, \&binop, "/", 19, ASSIGN) } +sub pp_i_modulo { maybe_targmy(@_, \&binop, "%", 19, ASSIGN) } +sub pp_pow { maybe_targmy(@_, \&binop, "**", 22, ASSIGN) } + +sub pp_left_shift { maybe_targmy(@_, \&binop, "<<", 17, ASSIGN) } +sub pp_right_shift { maybe_targmy(@_, \&binop, ">>", 17, ASSIGN) } +sub pp_bit_and { maybe_targmy(@_, \&binop, "&", 13, ASSIGN) } +sub pp_bit_or { maybe_targmy(@_, \&binop, "|", 12, ASSIGN) } +sub pp_bit_xor { maybe_targmy(@_, \&binop, "^", 12, ASSIGN) } sub pp_eq { binop(@_, "==", 14) } sub pp_ne { binop(@_, "!=", 14) } @@ -1213,14 +1304,15 @@ sub pp_aassign { binop(@_, "=", 7, SWAP_CHILDREN) } # `.' is special because concats-of-concats are optimized to save copying # by making all but the first concat stacked. The effect is as if the # programmer had written `($a . $b) .= $c', except legal. -sub pp_concat { +sub pp_concat { maybe_targmy(@_, \&real_concat) } +sub real_concat { my $self = shift; my($op, $cx) = @_; my $left = $op->first; my $right = $op->last; my $eq = ""; my $prec = 18; - if ($op->flags & OPf_STACKED and $op->first->ppaddr ne "pp_concat") { + if ($op->flags & OPf_STACKED and $op->first->name ne "concat") { $eq = "="; $prec = 7; } @@ -1301,7 +1393,10 @@ sub logop { } sub pp_and { logop(@_, "and", 3, "&&", 11, "if") } -sub pp_or { logop(@_, "or", 2, "||", 10, "unless") } +sub pp_or { logop(@_, "or", 2, "||", 10, "unless") } + +# xor is syntactically a logop, but it's really a binop (contrary to +# old versions of opcode.pl). Syntax is what matters here. sub pp_xor { logop(@_, "xor", 2, "", 0, "") } sub logassignop { @@ -1339,20 +1434,20 @@ sub listop { } sub pp_bless { listop(@_, "bless") } -sub pp_atan2 { listop(@_, "atan2") } +sub pp_atan2 { maybe_targmy(@_, \&listop, "atan2") } sub pp_substr { maybe_local(@_, listop(@_, "substr")) } sub pp_vec { maybe_local(@_, listop(@_, "vec")) } -sub pp_index { listop(@_, "index") } -sub pp_rindex { listop(@_, "rindex") } -sub pp_sprintf { listop(@_, "sprintf") } +sub pp_index { maybe_targmy(@_, \&listop, "index") } +sub pp_rindex { maybe_targmy(@_, \&listop, "rindex") } +sub pp_sprintf { maybe_targmy(@_, \&listop, "sprintf") } sub pp_formline { listop(@_, "formline") } # see also deparse_format -sub pp_crypt { listop(@_, "crypt") } +sub pp_crypt { maybe_targmy(@_, \&listop, "crypt") } sub pp_unpack { listop(@_, "unpack") } sub pp_pack { listop(@_, "pack") } -sub pp_join { listop(@_, "join") } +sub pp_join { maybe_targmy(@_, \&listop, "join") } sub pp_splice { listop(@_, "splice") } -sub pp_push { listop(@_, "push") } -sub pp_unshift { listop(@_, "unshift") } +sub pp_push { maybe_targmy(@_, \&listop, "push") } +sub pp_unshift { maybe_targmy(@_, \&listop, "unshift") } sub pp_reverse { listop(@_, "reverse") } sub pp_warn { listop(@_, "warn") } sub pp_die { listop(@_, "die") } @@ -1375,7 +1470,7 @@ sub pp_recv { listop(@_, "recv") } sub pp_seek { listop(@_, "seek") } sub pp_fcntl { listop(@_, "fcntl") } sub pp_ioctl { listop(@_, "ioctl") } -sub pp_flock { listop(@_, "flock") } +sub pp_flock { maybe_targmy(@_, \&listop, "flock") } sub pp_socket { listop(@_, "socket") } sub pp_sockpair { listop(@_, "sockpair") } sub pp_bind { listop(@_, "bind") } @@ -1385,23 +1480,23 @@ sub pp_accept { listop(@_, "accept") } sub pp_shutdown { listop(@_, "shutdown") } sub pp_gsockopt { listop(@_, "getsockopt") } sub pp_ssockopt { listop(@_, "setsockopt") } -sub pp_chown { listop(@_, "chown") } -sub pp_unlink { listop(@_, "unlink") } -sub pp_chmod { listop(@_, "chmod") } -sub pp_utime { listop(@_, "utime") } -sub pp_rename { listop(@_, "rename") } -sub pp_link { listop(@_, "link") } -sub pp_symlink { listop(@_, "symlink") } -sub pp_mkdir { listop(@_, "mkdir") } +sub pp_chown { maybe_targmy(@_, \&listop, "chown") } +sub pp_unlink { maybe_targmy(@_, \&listop, "unlink") } +sub pp_chmod { maybe_targmy(@_, \&listop, "chmod") } +sub pp_utime { maybe_targmy(@_, \&listop, "utime") } +sub pp_rename { maybe_targmy(@_, \&listop, "rename") } +sub pp_link { maybe_targmy(@_, \&listop, "link") } +sub pp_symlink { maybe_targmy(@_, \&listop, "symlink") } +sub pp_mkdir { maybe_targmy(@_, \&listop, "mkdir") } sub pp_open_dir { listop(@_, "opendir") } sub pp_seekdir { listop(@_, "seekdir") } -sub pp_waitpid { listop(@_, "waitpid") } -sub pp_system { listop(@_, "system") } -sub pp_exec { listop(@_, "exec") } -sub pp_kill { listop(@_, "kill") } -sub pp_setpgrp { listop(@_, "setpgrp") } -sub pp_getpriority { listop(@_, "getpriority") } -sub pp_setpriority { listop(@_, "setpriority") } +sub pp_waitpid { maybe_targmy(@_, \&listop, "waitpid") } +sub pp_system { maybe_targmy(@_, \&listop, "system") } +sub pp_exec { maybe_targmy(@_, \&listop, "exec") } +sub pp_kill { maybe_targmy(@_, \&listop, "kill") } +sub pp_setpgrp { maybe_targmy(@_, \&listop, "setpgrp") } +sub pp_getpriority { maybe_targmy(@_, \&listop, "getpriority") } +sub pp_setpriority { maybe_targmy(@_, \&listop, "setpriority") } sub pp_shmget { listop(@_, "shmget") } sub pp_shmctl { listop(@_, "shmctl") } sub pp_shmread { listop(@_, "shmread") } @@ -1442,10 +1537,10 @@ sub pp_truncate { my(@exprs); my $parens = ($cx >= 5) || $self->{'parens'}; my $kid = $op->first->sibling; - my($fh, $len); + my $fh; if ($op->flags & OPf_SPECIAL) { # $kid is an OP_CONST - $fh = $kid->sv->PV; + $fh = $self->const_sv($kid)->PV; } else { $fh = $self->deparse($kid, 6); $fh = "+$fh" if not $parens and substr($fh, 0, 1) eq "("; @@ -1456,7 +1551,6 @@ sub pp_truncate { } else { return "truncate $fh, $len"; } - } sub indirop { @@ -1480,8 +1574,7 @@ sub indirop { $expr = $self->deparse($kid, 6); push @exprs, $expr; } - return $self->maybe_parens_func($name, - $indir . join(", ", @exprs), + return $self->maybe_parens_func($name, $indir . join(", ", @exprs), $cx, 5); } @@ -1497,7 +1590,7 @@ sub mapop { $kid = $kid->first->sibling; # skip a pushmark my $code = $kid->first; # skip a null if (is_scope $code) { - $code = "{" . $self->deparse($code, 1) . "} "; + $code = "{" . $self->deparse($code, 0) . "} "; } else { $code = $self->deparse($code, 24) . ", "; } @@ -1523,15 +1616,15 @@ sub pp_list { # This assumes that no other private flags equal 128, and that # OPs that store things other than flags in their op_private, # like OP_AELEMFAST, won't be immediate children of a list. - unless ($lop->private & OPp_LVAL_INTRO or $lop->ppaddr eq "pp_undef") + unless ($lop->private & OPpLVAL_INTRO or $lop->name eq "undef") { $local = ""; # or not last; } - if ($lop->ppaddr =~ /^pp_pad[ash]v$/) { # my() + if ($lop->name =~ /^pad[ash]v$/) { # my() ($local = "", last) if $local eq "local"; $local = "my"; - } elsif ($lop->ppaddr ne "pp_undef") { # local() + } elsif ($lop->name ne "undef") { # local() ($local = "", last) if $local eq "my"; $local = "local"; } @@ -1540,7 +1633,7 @@ sub pp_list { return $self->deparse($kid, $cx) if null $kid->sibling and not $local; for (; !null($kid); $kid = $kid->sibling) { if ($local) { - if (class($kid) eq "UNOP" and $kid->first->ppaddr eq "pp_gvsv") { + if (class($kid) eq "UNOP" and $kid->first->name eq "gvsv") { $lop = $kid->first; } else { $lop = $kid; @@ -1575,10 +1668,10 @@ sub pp_cond_expr { } $cond = $self->deparse($cond, 1); $true = $self->deparse($true, 0); - if ($false->ppaddr eq "pp_lineseq") { # braces w/o scope => elsif + if ($false->name eq "lineseq") { # braces w/o scope => elsif my $head = "if ($cond) {\n\t$true\n\b}"; my @elsifs; - while (!null($false) and $false->ppaddr eq "pp_lineseq") { + while (!null($false) and $false->name eq "lineseq") { my $newop = $false->first->sibling->first; my $newcond = $newop->first; my $newtrue = $newcond->sibling; @@ -1607,13 +1700,13 @@ sub pp_leaveloop { local($self->{'curstash'}) = $self->{'curstash'}; my $head = ""; my $bare = 0; - if ($kid->ppaddr eq "pp_lineseq") { # bare or infinite loop + if ($kid->name eq "lineseq") { # bare or infinite loop if (is_state $kid->last) { # infinite $head = "for (;;) "; # shorter than while (1) } else { $bare = 1; } - } elsif ($enter->ppaddr eq "pp_enteriter") { # foreach + } elsif ($enter->name eq "enteriter") { # foreach my $ary = $enter->first->sibling; # first was pushmark my $var = $ary->sibling; if ($enter->flags & OPf_STACKED @@ -1638,20 +1731,20 @@ sub pp_leaveloop { $var = "my " . $var; } } - } elsif ($var->ppaddr eq "pp_rv2gv") { + } elsif ($var->name eq "rv2gv") { $var = $self->pp_rv2sv($var, 1); - } elsif ($var->ppaddr eq "pp_gv") { + } elsif ($var->name eq "gv") { $var = "\$" . $self->deparse($var, 1); } $head = "foreach $var ($ary) "; $kid = $kid->first->first->sibling; # skip OP_AND and OP_ITER - } elsif ($kid->ppaddr eq "pp_null") { # while/until + } elsif ($kid->name eq "null") { # while/until $kid = $kid->first; - my $name = {"pp_and" => "while", "pp_or" => "until"} - ->{$kid->ppaddr}; + my $name = {"and" => "while", "or" => "until"} + ->{$kid->name}; $head = "$name (" . $self->deparse($kid->first, 1) . ") "; $kid = $kid->first->sibling; - } elsif ($kid->ppaddr eq "pp_stub") { # bare and empty + } elsif ($kid->name eq "stub") { # bare and empty return "{;}"; # {} could be a hashref } # The third-to-last kid is the continue block if the pointer used @@ -1663,15 +1756,14 @@ sub pp_leaveloop { # (because it's a nulled out nextstate in a scope), in which # case the head's next is advanced past the null but the nextop's # isn't, so we need to try nextop->next. - my($cont, $precont); + my $precont; + my $cont = $kid->first; if ($bare) { - $cont = $kid->first; while (!null($cont->sibling)) { $precont = $cont; $cont = $cont->sibling; } } else { - $cont = $kid->first; while (!null($cont->sibling->sibling->sibling)) { $precont = $cont; $cont = $cont->sibling; @@ -1708,30 +1800,29 @@ sub pp_leavetry { return "eval {\n\t" . $self->pp_leave(@_) . "\n\b}"; } -sub OP_CONST () { 5 } - -# XXX need a better way to do this -sub OP_STRINGIFY () { $] > 5.004_72 ? 67 : 65 } +BEGIN { eval "sub OP_CONST () {" . opnumber("const") . "}" } +BEGIN { eval "sub OP_STRINGIFY () {" . opnumber("stringify") . "}" } sub pp_null { my $self = shift; my($op, $cx) = @_; if (class($op) eq "OP") { - return "'???'" if $op->targ == OP_CONST; # old value is lost - } elsif ($op->first->ppaddr eq "pp_pushmark") { + # old value is lost + return $self->{'ex_const'} if $op->targ == OP_CONST; + } elsif ($op->first->name eq "pushmark") { return $self->pp_list($op, $cx); - } elsif ($op->first->ppaddr eq "pp_enter") { + } elsif ($op->first->name eq "enter") { return $self->pp_leave($op, $cx); } elsif ($op->targ == OP_STRINGIFY) { return $self->dquote($op); } elsif (!null($op->first->sibling) and - $op->first->sibling->ppaddr eq "pp_readline" and + $op->first->sibling->name eq "readline" and $op->first->sibling->flags & OPf_STACKED) { return $self->maybe_parens($self->deparse($op->first, 7) . " = " . $self->deparse($op->first->sibling, 7), $cx, 7); } elsif (!null($op->first->sibling) and - $op->first->sibling->ppaddr eq "pp_trans" and + $op->first->sibling->name eq "trans" and $op->first->sibling->flags & OPf_STACKED) { return $self->maybe_parens($self->deparse($op->first, 20) . " =~ " . $self->deparse($op->first->sibling, 20), @@ -1741,6 +1832,16 @@ sub pp_null { } } +# the aassign in-common check messes up SvCUR (always setting it +# to a value >= 100), but it's probably safe to assume there +# won't be any NULs in the names of my() variables. (with +# stash variables, I wouldn't be so sure) +sub padname_fix { + my $str = shift; + $str = substr($str, 0, index($str, "\0")) if index($str, "\0") != -1; + return $str; +} + sub padname { my $self = shift; my $targ = shift; @@ -1778,22 +1879,37 @@ sub pp_threadsv { return $self->maybe_local($op, $cx, "\$" . $threadsv_names[$op->targ]); } +sub maybe_padgv { + my $self = shift; + my $op = shift; + my $gv; + if ($Config{useithreads}) { + $gv = $self->padval($op->padix); + } + else { + $gv = $op->gv; + } + return $gv; +} + sub pp_gvsv { my $self = shift; my($op, $cx) = @_; - return $self->maybe_local($op, $cx, "\$" . $self->gv_name($op->gv)); + my $gv = $self->maybe_padgv($op); + return $self->maybe_local($op, $cx, "\$" . $self->gv_name($gv)); } sub pp_gv { my $self = shift; my($op, $cx) = @_; - return $self->gv_name($op->gv); + my $gv = $self->maybe_padgv($op); + return $self->gv_name($gv); } sub pp_aelemfast { my $self = shift; my($op, $cx) = @_; - my $gv = $op->gv; + my $gv = $self->maybe_padgv($op); return "\$" . $self->gv_name($gv) . "[" . $op->private . "]"; } @@ -1813,7 +1929,7 @@ sub pp_rv2gv { maybe_local(@_, rv2x(@_, "*")) } sub pp_av2arylen { my $self = shift; my($op, $cx) = @_; - if ($op->first->ppaddr eq "pp_padav") { + if ($op->first->name eq "padav") { return $self->maybe_local($op, $cx, '$#' . $self->padany($op->first)); } else { return $self->maybe_local($op, $cx, @@ -1828,23 +1944,41 @@ sub pp_rv2av { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; - if ($kid->ppaddr eq "pp_const") { # constant list - my $av = $kid->sv; + if ($kid->name eq "const") { # constant list + my $av = $self->const_sv($kid); return "(" . join(", ", map(const($_), $av->ARRAY)) . ")"; } else { return $self->maybe_local($op, $cx, $self->rv2x($op, $cx, "\@")); } } +sub is_subscriptable { + my $op = shift; + if ($op->name =~ /^[ahg]elem/) { + return 1; + } elsif ($op->name eq "entersub") { + my $kid = $op->first; + return 0 unless null $kid->sibling; + $kid = $kid->first; + $kid = $kid->sibling until null $kid->sibling; + return 0 if is_scope($kid); + $kid = $kid->first; + return 0 if $kid->name eq "gv"; + return 0 if is_scalar($kid); + return is_subscriptable($kid); + } else { + return 0; + } +} sub elem { my $self = shift; my ($op, $cx, $left, $right, $padname) = @_; my($array, $idx) = ($op->first, $op->first->sibling); - unless ($array->ppaddr eq $padname) { # Maybe this has been fixed + unless ($array->name eq $padname) { # Maybe this has been fixed $array = $array->first; # skip rv2av (or ex-rv2av in _53+) } - if ($array->ppaddr eq $padname) { + if ($array->name eq $padname) { $array = $self->padany($array); } elsif (is_scope($array)) { # ${expr}[0] $array = "{" . $self->deparse($array, 0) . "}"; @@ -1852,8 +1986,7 @@ sub elem { $array = $self->deparse($array, 24); } else { # $x[20][3]{hi} or expr->[20] - my $arrow; - $arrow = "->" if $array->ppaddr !~ /^pp_[ah]elem$/; + my $arrow = is_subscriptable($array) ? "" : "->"; return $self->deparse($array, 24) . $arrow . $left . $self->deparse($idx, 1) . $right; } @@ -1861,15 +1994,15 @@ sub elem { return "\$" . $array . $left . $idx . $right; } -sub pp_aelem { maybe_local(@_, elem(@_, "[", "]", "pp_padav")) } -sub pp_helem { maybe_local(@_, elem(@_, "{", "}", "pp_padhv")) } +sub pp_aelem { maybe_local(@_, elem(@_, "[", "]", "padav")) } +sub pp_helem { maybe_local(@_, elem(@_, "{", "}", "padhv")) } sub pp_gelem { my $self = shift; my($op, $cx) = @_; my($glob, $part) = ($op->first, $op->last); $glob = $glob->first; # skip rv2gv - $glob = $glob->first if $glob->ppaddr eq "pp_rv2gv"; # this one's a bug + $glob = $glob->first if $glob->name eq "rv2gv"; # this one's a bug my $scope = is_scope($glob); $glob = $self->deparse($glob, 0); $part = $self->deparse($part, 1); @@ -1889,16 +2022,16 @@ sub slice { } $array = $last; $array = $array->first - if $array->ppaddr eq $regname or $array->ppaddr eq "pp_null"; + if $array->name eq $regname or $array->name eq "null"; if (is_scope($array)) { $array = "{" . $self->deparse($array, 0) . "}"; - } elsif ($array->ppaddr eq $padname) { + } elsif ($array->name eq $padname) { $array = $self->padany($array); } else { $array = $self->deparse($array, 24); } $kid = $op->first->sibling; # skip pushmark - if ($kid->ppaddr eq "pp_list") { + if ($kid->name eq "list") { $kid = $kid->first->sibling; # skip list, pushmark for (; !null $kid; $kid = $kid->sibling) { push @elems, $self->deparse($kid, 6); @@ -1910,10 +2043,8 @@ sub slice { return "\@" . $array . $left . $list . $right; } -sub pp_aslice { maybe_local(@_, slice(@_, "[", "]", - "pp_rv2av", "pp_padav")) } -sub pp_hslice { maybe_local(@_, slice(@_, "{", "}", - "pp_rv2hv", "pp_padhv")) } +sub pp_aslice { maybe_local(@_, slice(@_, "[", "]", "rv2av", "padav")) } +sub pp_hslice { maybe_local(@_, slice(@_, "{", "}", "rv2hv", "padhv")) } sub pp_lslice { my $self = shift; @@ -1926,48 +2057,153 @@ sub pp_lslice { return "($list)" . "[$idx]"; } -sub OPpENTERSUB_AMPER () { 8 } - -sub OPf_WANT () { 3 } -sub OPf_WANT_VOID () { 1 } -sub OPf_WANT_SCALAR () { 2 } -sub OPf_WANT_LIST () { 2 } - sub want_scalar { my $op = shift; return ($op->flags & OPf_WANT) == OPf_WANT_SCALAR; } -sub pp_entersub { +sub want_list { + my $op = shift; + return ($op->flags & OPf_WANT) == OPf_WANT_LIST; +} + +sub method { my $self = shift; my($op, $cx) = @_; - my $prefix = ""; - my $amper = ""; - my $proto = undef; - my $simple = 0; - my($kid, $args, @exprs); - if (not null $op->first->sibling) { # method - $kid = $op->first->sibling; # skip pushmark - my $obj = $self->deparse($kid, 24); + my $kid = $op->first->sibling; # skip pushmark + my($meth, $obj, @exprs); + if ($kid->name eq "list" and want_list $kid) { + # When an indirect object isn't a bareword but the args are in + # parens, the parens aren't part of the method syntax (the LLAFR + # doesn't apply), but they make a list with OPf_PARENS set that + # doesn't get flattened by the append_elem that adds the method, + # making a (object, arg1, arg2, ...) list where the object + # usually is. This can be distinguished from + # `($obj, $arg1, $arg2)->meth()' (which is legal if $arg2 is an + # object) because in the later the list is in scalar context + # as the left side of -> always is, while in the former + # the list is in list context as method arguments always are. + # (Good thing there aren't method prototypes!) + $meth = $kid->sibling; + $kid = $kid->first->sibling; # skip pushmark + $obj = $kid; + $kid = $kid->sibling; + for (; not null $kid; $kid = $kid->sibling) { + push @exprs, $self->deparse($kid, 6); + } + } else { + $obj = $kid; $kid = $kid->sibling; for (; not null $kid->sibling; $kid = $kid->sibling) { push @exprs, $self->deparse($kid, 6); } - my $meth = $kid->first; - if ($meth->ppaddr eq "pp_const") { - $meth = $meth->sv->PV; # needs to be bare + $meth = $kid; + } + $obj = $self->deparse($obj, 24); + if ($meth->name eq "method_named") { + $meth = $self->const_sv($meth)->PV; + } else { + $meth = $meth->first; + if ($meth->name eq "const") { + # As of 5.005_58, this case is probably obsoleted by the + # method_named case above + $meth = $self->const_sv($meth)->PV; # needs to be bare } else { $meth = $self->deparse($meth, 1); } - $args = join(", ", @exprs); - $kid = $obj . "->" . $meth; - if ($args) { - return $kid . "(" . $args . ")"; # parens mandatory + } + my $args = join(", ", @exprs); + $kid = $obj . "->" . $meth; + if ($args) { + return $kid . "(" . $args . ")"; # parens mandatory + } else { + return $kid; + } +} + +# returns "&" if the prototype doesn't match the args, +# or ("", $args_after_prototype_demunging) if it does. +sub check_proto { + my $self = shift; + my($proto, @args) = @_; + my($arg, $real); + my $doneok = 0; + my @reals; + # An unbackslashed @ or % gobbles up the rest of the args + $proto =~ s/([^\\]|^)([@%])(.*)$/$1$2/; + while ($proto) { + $proto =~ s/^ *([\\]?[\$\@&%*]|;)//; + my $chr = $1; + if ($chr eq "") { + return "&" if @args; + } elsif ($chr eq ";") { + $doneok = 1; + } elsif ($chr eq "@" or $chr eq "%") { + push @reals, map($self->deparse($_, 6), @args); + @args = (); } else { - return $kid; # toke.c fakes parens - } + $arg = shift @args; + last unless $arg; + if ($chr eq "\$") { + if (want_scalar $arg) { + push @reals, $self->deparse($arg, 6); + } else { + return "&"; + } + } elsif ($chr eq "&") { + if ($arg->name =~ /^(s?refgen|undef)$/) { + push @reals, $self->deparse($arg, 6); + } else { + return "&"; + } + } elsif ($chr eq "*") { + if ($arg->name =~ /^s?refgen$/ + and $arg->first->first->name eq "rv2gv") + { + $real = $arg->first->first; # skip refgen, null + if ($real->first->name eq "gv") { + push @reals, $self->deparse($real, 6); + } else { + push @reals, $self->deparse($real->first, 6); + } + } else { + return "&"; + } + } elsif (substr($chr, 0, 1) eq "\\") { + $chr = substr($chr, 1); + if ($arg->name =~ /^s?refgen$/ and + !null($real = $arg->first) and + ($chr eq "\$" && is_scalar($real->first) + or ($chr eq "\@" + && $real->first->sibling->name + =~ /^(rv2|pad)av$/) + or ($chr eq "%" + && $real->first->sibling->name + =~ /^(rv2|pad)hv$/) + #or ($chr eq "&" # This doesn't work + # && $real->first->name eq "rv2cv") + or ($chr eq "*" + && $real->first->name eq "rv2gv"))) + { + push @reals, $self->deparse($real, 6); + } else { + return "&"; + } + } + } } - # else, not a method + return "&" if $proto and !$doneok; # too few args and no `;' + return "&" if @args; # too many args + return ("", join ", ", @reals); +} + +sub pp_entersub { + my $self = shift; + my($op, $cx) = @_; + return $self->method($op, $cx) unless null $op->first->sibling; + my $prefix = ""; + my $amper = ""; + my($kid, @exprs); if ($op->flags & OPf_SPECIAL) { $prefix = "do "; } elsif ($op->private & OPpENTERSUB_AMPER) { @@ -1978,97 +2214,30 @@ sub pp_entersub { for (; not null $kid->sibling; $kid = $kid->sibling) { push @exprs, $kid; } + my $simple = 0; + my $proto = undef; if (is_scope($kid)) { $amper = "&"; $kid = "{" . $self->deparse($kid, 0) . "}"; - } elsif ($kid->first->ppaddr eq "pp_gv") { - my $gv = $kid->first->gv; + } elsif ($kid->first->name eq "gv") { + my $gv = $self->maybe_padgv($kid->first); if (class($gv->CV) ne "SPECIAL") { $proto = $gv->CV->PV if $gv->CV->FLAGS & SVf_POK; } - $simple = 1; + $simple = 1; # only calls of named functions can be prototyped $kid = $self->deparse($kid, 24); } elsif (is_scalar $kid->first) { $amper = "&"; $kid = $self->deparse($kid, 24); } else { $prefix = ""; - $kid = $self->deparse($kid, 24) . "->"; + my $arrow = is_subscriptable($kid->first) ? "" : "->"; + $kid = $self->deparse($kid, 24) . $arrow; } + my $args; if (defined $proto and not $amper) { - my($arg, $real); - my $doneok = 0; - my @args = @exprs; - my @reals; - my $p = $proto; - $p =~ s/([^\\]|^)([@%])(.*)$/$1$2/; - while ($p) { - $p =~ s/^ *([\\]?[\$\@&%*]|;)//; - my $chr = $1; - if ($chr eq "") { - undef $proto if @args; - } elsif ($chr eq ";") { - $doneok = 1; - } elsif ($chr eq "@" or $chr eq "%") { - push @reals, map($self->deparse($_, 6), @args); - @args = (); - } else { - $arg = shift @args; - last unless $arg; - if ($chr eq "\$") { - if (want_scalar $arg) { - push @reals, $self->deparse($arg, 6); - } else { - undef $proto; - } - } elsif ($chr eq "&") { - if ($arg->ppaddr =~ /pp_(s?refgen|undef)/) { - push @reals, $self->deparse($arg, 6); - } else { - undef $proto; - } - } elsif ($chr eq "*") { - if ($arg->ppaddr =~ /^pp_s?refgen$/ - and $arg->first->first->ppaddr eq "pp_rv2gv") - { - $real = $arg->first->first; # skip refgen, null - if ($real->first->ppaddr eq "pp_gv") { - push @reals, $self->deparse($real, 6); - } else { - push @reals, $self->deparse($real->first, 6); - } - } else { - undef $proto; - } - } elsif (substr($chr, 0, 1) eq "\\") { - $chr = substr($chr, 1); - if ($arg->ppaddr =~ /^pp_s?refgen$/ and - !null($real = $arg->first) and - ($chr eq "\$" && is_scalar($real->first) - or ($chr eq "\@" - && $real->first->sibling->ppaddr - =~ /^pp_(rv2|pad)av$/) - or ($chr eq "%" - && $real->first->sibling->ppaddr - =~ /^pp_(rv2|pad)hv$/) - #or ($chr eq "&" # This doesn't work - # && $real->first->ppaddr eq "pp_rv2cv") - or ($chr eq "*" - && $real->first->ppaddr eq "pp_rv2gv"))) - { - push @reals, $self->deparse($real, 6); - } else { - undef $proto; - } - } - } - } - undef $proto if $p and !$doneok; - undef $proto if @args; - $args = join(", ", @reals); - $amper = ""; - unless (defined $proto) { - $amper = "&"; + ($amper, $args) = $self->check_proto($proto, @exprs); + if ($amper eq "&") { $args = join(", ", map($self->deparse($_, 6), @exprs)); } } else { @@ -2146,6 +2315,7 @@ sub balanced_delim { } elsif ($c eq $close) { $cnt--; if ($cnt < 0) { + # qq()() isn't ")(" $fail = 1; last; } @@ -2175,14 +2345,10 @@ sub single_delim { } } -sub SVf_IOK () {0x10000} -sub SVf_NOK () {0x20000} -sub SVf_ROK () {0x80000} - sub const { my $sv = shift; if (class($sv) eq "SPECIAL") { - return ('undef', '1', '0')[$$sv-1]; + return ('undef', '1', '0')[$$sv-1]; # sv_undef, sv_yes, sv_no } elsif ($sv->FLAGS & SVf_IOK) { return $sv->IV; } elsif ($sv->FLAGS & SVf_NOK) { @@ -2191,43 +2357,52 @@ sub const { return "\\(" . const($sv->RV) . ")"; # constant folded } else { my $str = $sv->PV; - if ($str =~ /[^ -~]/) { # ASCII + if ($str =~ /[^ -~]/) { # ASCII for non-printing return single_delim("qq", '"', uninterp escape_str unback $str); } else { - $str =~ s/\\/\\\\/g; - return single_delim("q", "'", $str); + return single_delim("q", "'", unback $str); } } } +sub const_sv { + my $self = shift; + my $op = shift; + my $sv = $op->sv; + # the constant could be in the pad (under useithreads) + $sv = $self->padval($op->targ) unless $$sv; + return $sv; +} + sub pp_const { my $self = shift; my($op, $cx) = @_; -# if ($op->private & OPp_CONST_BARE) { # trouble with `=>' autoquoting -# return $op->sv->PV; +# if ($op->private & OPpCONST_BARE) { # trouble with `=>' autoquoting +# return $self->const_sv($op)->PV; # } - return const($op->sv); + my $sv = $self->const_sv($op); + return const($sv); } sub dq { my $self = shift; my $op = shift; - my $type = $op->ppaddr; - if ($type eq "pp_const") { - return uninterp(escape_str(unback($op->sv->PV))); - } elsif ($type eq "pp_concat") { + my $type = $op->name; + if ($type eq "const") { + return uninterp(escape_str(unback($self->const_sv($op)->PV))); + } elsif ($type eq "concat") { return $self->dq($op->first) . $self->dq($op->last); - } elsif ($type eq "pp_uc") { + } elsif ($type eq "uc") { return '\U' . $self->dq($op->first->sibling) . '\E'; - } elsif ($type eq "pp_lc") { + } elsif ($type eq "lc") { return '\L' . $self->dq($op->first->sibling) . '\E'; - } elsif ($type eq "pp_ucfirst") { + } elsif ($type eq "ucfirst") { return '\u' . $self->dq($op->first->sibling); - } elsif ($type eq "pp_lcfirst") { + } elsif ($type eq "lcfirst") { return '\l' . $self->dq($op->first->sibling); - } elsif ($type eq "pp_quotemeta") { + } elsif ($type eq "quotemeta") { return '\Q' . $self->dq($op->first->sibling) . '\E'; - } elsif ($type eq "pp_join") { + } elsif ($type eq "join") { return $self->deparse($op->last, 26); # was join($", @ary) } else { return $self->deparse($op, 26); @@ -2243,13 +2418,15 @@ sub pp_backtick { sub dquote { my $self = shift; - my $op = shift; - # skip ex-stringify, pushmark - return single_delim("qq", '"', $self->dq($op->first->sibling)); + my($op, $cx) = shift; + my $kid = $op->first->sibling; # skip ex-stringify, pushmark + return $self->deparse($kid, $cx) if $self->{'unquote'}; + $self->maybe_targmy($kid, $cx, + sub {single_delim("qq", '"', $self->dq($_[1]))}); } -# OP_STRINGIFY is a listop, but it only ever has one arg (?) -sub pp_stringify { dquote(@_) } +# OP_STRINGIFY is a listop, but it only ever has one arg +sub pp_stringify { maybe_targmy(@_, \&dquote) } # tr/// and s/// (and tr[][], tr[]//, tr###, etc) # note that tr(from)/to/ is OK, but not tr/from/(to) @@ -2316,7 +2493,8 @@ sub collapse { if ($c <= $#chars - 2 and $chars[$c + 1] == $tr + 1 and $chars[$c + 2] == $tr + 2) { - for (; $c <= $#chars and $chars[$c + 1] == $chars[$c] + 1; $c++) {} + for (; $c <= $#chars-1 and $chars[$c + 1] == $chars[$c] + 1; $c++) + {} $str .= "-"; $str .= pchr($chars[$c]); } @@ -2324,14 +2502,12 @@ sub collapse { return $str; } -sub OPpTRANS_SQUASH () { 16 } -sub OPpTRANS_DELETE () { 32 } -sub OPpTRANS_COMPLEMENT () { 64 } +# XXX This has trouble with hyphens in the replacement (tr/bac/-AC/), +# and backslashes. -sub pp_trans { - my $self = shift; - my($op, $cx) = @_; - my(@table) = unpack("s256", $op->pv); +sub tr_decode_byte { + my($table, $flags) = @_; + my(@table) = unpack("s256", $table); my($c, $tr, @from, @to, @delfrom, $delhyphen); if ($table[ord "-"] != -1 and $table[ord("-") - 1] == -1 || $table[ord("-") + 1] == -1) @@ -2353,10 +2529,8 @@ sub pp_trans { push @delfrom, $c; } } - my $flags; @from = (@from, @delfrom); - if ($op->private & OPpTRANS_COMPLEMENT) { - $flags .= "c"; + if ($flags & OPpTRANS_COMPLEMENT) { my @newfrom = (); my %from; @from{@from} = (1) x @from; @@ -2365,16 +2539,136 @@ sub pp_trans { } @from = @newfrom; } - if ($op->private & OPpTRANS_DELETE) { - $flags .= "d"; - } else { + unless ($flags & OPpTRANS_DELETE) { pop @to while $#to and $to[$#to] == $to[$#to -1]; } - $flags .= "s" if $op->private & OPpTRANS_SQUASH; my($from, $to); $from = collapse(@from); $to = collapse(@to); $from .= "-" if $delhyphen; + return ($from, $to); +} + +sub tr_chr { + my $x = shift; + if ($x == ord "-") { + return "\\-"; + } else { + return chr $x; + } +} + +# XXX This doesn't yet handle all cases correctly either + +sub tr_decode_utf8 { + my($swash_hv, $flags) = @_; + my %swash = $swash_hv->ARRAY; + my $final = undef; + $final = $swash{'FINAL'}->IV if exists $swash{'FINAL'}; + my $none = $swash{"NONE"}->IV; + my $extra = $none + 1; + my(@from, @delfrom, @to); + my $line; + foreach $line (split /\n/, $swash{'LIST'}->PV) { + my($min, $max, $result) = split(/\t/, $line); + $min = hex $min; + if (length $max) { + $max = hex $max; + } else { + $max = $min; + } + $result = hex $result; + if ($result == $extra) { + push @delfrom, [$min, $max]; + } else { + push @from, [$min, $max]; + push @to, [$result, $result + $max - $min]; + } + } + for my $i (0 .. $#from) { + if ($from[$i][0] == ord '-') { + unshift @from, splice(@from, $i, 1); + unshift @to, splice(@to, $i, 1); + last; + } elsif ($from[$i][1] == ord '-') { + $from[$i][1]--; + $to[$i][1]--; + unshift @from, ord '-'; + unshift @to, ord '-'; + last; + } + } + for my $i (0 .. $#delfrom) { + if ($delfrom[$i][0] == ord '-') { + push @delfrom, splice(@delfrom, $i, 1); + last; + } elsif ($delfrom[$i][1] == ord '-') { + $delfrom[$i][1]--; + push @delfrom, ord '-'; + last; + } + } + if (defined $final and $to[$#to][1] != $final) { + push @to, [$final, $final]; + } + push @from, @delfrom; + if ($flags & OPpTRANS_COMPLEMENT) { + my @newfrom; + my $next = 0; + for my $i (0 .. $#from) { + push @newfrom, [$next, $from[$i][0] - 1]; + $next = $from[$i][1] + 1; + } + @from = (); + for my $range (@newfrom) { + if ($range->[0] <= $range->[1]) { + push @from, $range; + } + } + } + my($from, $to, $diff); + for my $chunk (@from) { + $diff = $chunk->[1] - $chunk->[0]; + if ($diff > 1) { + $from .= tr_chr($chunk->[0]) . "-" . tr_chr($chunk->[1]); + } elsif ($diff == 1) { + $from .= tr_chr($chunk->[0]) . tr_chr($chunk->[1]); + } else { + $from .= tr_chr($chunk->[0]); + } + } + for my $chunk (@to) { + $diff = $chunk->[1] - $chunk->[0]; + if ($diff > 1) { + $to .= tr_chr($chunk->[0]) . "-" . tr_chr($chunk->[1]); + } elsif ($diff == 1) { + $to .= tr_chr($chunk->[0]) . tr_chr($chunk->[1]); + } else { + $to .= tr_chr($chunk->[0]); + } + } + #$final = sprintf("%04x", $final) if defined $final; + #$none = sprintf("%04x", $none) if defined $none; + #$extra = sprintf("%04x", $extra) if defined $extra; + #print STDERR "final: $final\n none: $none\nextra: $extra\n"; + #print STDERR $swash{'LIST'}->PV; + return (escape_str($from), escape_str($to)); +} + +sub pp_trans { + my $self = shift; + my($op, $cx) = @_; + my($from, $to); + if (class($op) eq "PVOP") { + ($from, $to) = tr_decode_byte($op->pv, $op->private); + } else { # class($op) eq "SVOP" + ($from, $to) = tr_decode_utf8($op->sv->RV, $op->private); + } + my $flags = ""; + $flags .= "c" if $op->private & OPpTRANS_COMPLEMENT; + $flags .= "d" if $op->private & OPpTRANS_DELETE; + $to = "" if $from eq $to and $flags eq ""; + $flags .= "s" if $op->private & OPpTRANS_SQUASH; return "tr" . double_delim($from, $to) . $flags; } @@ -2382,22 +2676,22 @@ sub pp_trans { sub re_dq { my $self = shift; my $op = shift; - my $type = $op->ppaddr; - if ($type eq "pp_const") { - return uninterp($op->sv->PV); - } elsif ($type eq "pp_concat") { + my $type = $op->name; + if ($type eq "const") { + return uninterp($self->const_sv($op)->PV); + } elsif ($type eq "concat") { return $self->re_dq($op->first) . $self->re_dq($op->last); - } elsif ($type eq "pp_uc") { + } elsif ($type eq "uc") { return '\U' . $self->re_dq($op->first->sibling) . '\E'; - } elsif ($type eq "pp_lc") { + } elsif ($type eq "lc") { return '\L' . $self->re_dq($op->first->sibling) . '\E'; - } elsif ($type eq "pp_ucfirst") { + } elsif ($type eq "ucfirst") { return '\u' . $self->re_dq($op->first->sibling); - } elsif ($type eq "pp_lcfirst") { + } elsif ($type eq "lcfirst") { return '\l' . $self->re_dq($op->first->sibling); - } elsif ($type eq "pp_quotemeta") { + } elsif ($type eq "quotemeta") { return '\Q' . $self->re_dq($op->first->sibling) . '\E'; - } elsif ($type eq "pp_join") { + } elsif ($type eq "join") { return $self->deparse($op->last, 26); # was join($", @ary) } else { return $self->deparse($op, 26); @@ -2408,26 +2702,11 @@ sub pp_regcomp { my $self = shift; my($op, $cx) = @_; my $kid = $op->first; - $kid = $kid->first if $kid->ppaddr eq "pp_regcmaybe"; - $kid = $kid->first if $kid->ppaddr eq "pp_regcreset"; + $kid = $kid->first if $kid->name eq "regcmaybe"; + $kid = $kid->first if $kid->name eq "regcreset"; return $self->re_dq($kid); } -sub OPp_RUNTIME () { 64 } - -sub PMf_ONCE () { 0x2 } -sub PMf_SKIPWHITE () { 0x10 } -sub PMf_CONST () { 0x40 } -sub PMf_KEEP () { 0x80 } -sub PMf_GLOBAL () { 0x100 } -sub PMf_CONTINUE () { 0x200 } -sub PMf_EVAL () { 0x400 } -sub PMf_LOCALE () { 0x800 } -sub PMf_MULTILINE () { 0x1000 } -sub PMf_SINGLELINE () { 0x2000 } -sub PMf_FOLD () { 0x4000 } -sub PMf_EXTENDED () { 0x8000 } - # osmic acid -- see osmium tetroxide my %matchwords; @@ -2522,11 +2801,15 @@ sub pp_subst { $kid = $kid->sibling; } else { $repl = $op->pmreplroot->first; # skip substcont - while ($repl->ppaddr eq "pp_entereval") { + while ($repl->name eq "entereval") { $repl = $repl->first; $flags .= "e"; } - $repl = $self->dq($repl); + if ($op->pmflags & PMf_EVAL) { + $repl = $self->deparse($repl, 0); + } else { + $repl = $self->dq($repl); + } } if (null $kid) { $re = re_uninterp(escape_str($op->precomp)); @@ -2559,7 +2842,8 @@ B::Deparse - Perl compiler backend to produce perl code =head1 SYNOPSIS -B<perl> B<-MO=Deparse>[B<,-u>I<PACKAGE>][B<,-p>][B<,-l>][B<,-s>I<LETTERS>] I<prog.pl> +B<perl> B<-MO=Deparse>[B<,-u>I<PACKAGE>][B<,-p>][B<,-q>][B<,-l>][B<,-s>I<LETTERS>] + I<prog.pl> =head1 DESCRIPTION @@ -2584,6 +2868,11 @@ the '-MO=Deparse', separated by a comma but not any white space. =over 4 +=item B<-l> + +Add '#line' declarations to the output based on the line and file +locations of the original code. + =item B<-p> Print extra parentheses. Without this option, B::Deparse includes @@ -2607,29 +2896,44 @@ C<B::Deparse,-p> will print which probably isn't what you intended (the C<'???'> is a sign that perl optimized away a constant value). +=item B<-q> + +Expand double-quoted strings into the corresponding combinations of +concatenation, uc, ucfirst, lc, lcfirst, quotemeta, and join. For +instance, print + + print "Hello, $world, @ladies, \u$gentlemen\E, \u\L$me!"; + +as + + print 'Hello, ' . $world . ', ' . join($", @ladies) . ', ' + . ucfirst($gentlemen) . ', ' . ucfirst(lc $me . '!'); + +Note that the expanded form represents the way perl handles such +constructions internally -- this option actually turns off the reverse +translation that B::Deparse usually does. On the other hand, note that +C<$x = "$y"> is not the same as C<$x = $y>: the former makes the value +of $y into a string before doing the assignment. + =item B<-u>I<PACKAGE> Normally, B::Deparse deparses the main code of a program, all the subs called by the main program (and all the subs called by them, recursively), and any other subs in the main:: package. To include subs in other packages that aren't called directly, such as AUTOLOAD, -DESTROY, other subs called automatically by perl, and methods, which -aren't resolved to subs until runtime, use the B<-u> option. The +DESTROY, other subs called automatically by perl, and methods (which +aren't resolved to subs until runtime), use the B<-u> option. The argument to B<-u> is the name of a package, and should follow directly after the 'u'. Multiple B<-u> options may be given, separated by commas. Note that unlike some other backends, B::Deparse doesn't (yet) try to guess automatically when B<-u> is needed -- you must invoke it yourself. -=item B<-l> - -Add '#line' declarations to the output based on the line and file -locations of the original code. - =item B<-s>I<LETTERS> -Tweak the style of B::Deparse's output. At the moment, only one style -option is implemented: +Tweak the style of B::Deparse's output. The letters should follow +directly after the 's', with no space or punctuation. The following +options are available: =over 4 @@ -2654,17 +2958,85 @@ instead of The default is not to cuddle. +=item B<i>I<NUMBER> + +Indent lines by multiples of I<NUMBER> columns. The default is 4 columns. + +=item B<T> + +Use tabs for each 8 columns of indent. The default is to use only spaces. +For instance, if the style options are B<-si4T>, a line that's indented +3 times will be preceded by one tab and four spaces; if the options were +B<-si8T>, the same line would be preceded by three tabs. + +=item B<v>I<STRING>B<.> + +Print I<STRING> for the value of a constant that can't be determined +because it was optimized away (mnemonic: this happens when a constant +is used in B<v>oid context). The end of the string is marked by a period. +The string should be a valid perl expression, generally a constant. +Note that unless it's a number, it probably needs to be quoted, and on +a command line quotes need to be protected from the shell. Some +conventional values include 0, 1, 42, '', 'foo', and +'Useless use of constant omitted' (which may need to be +B<-sv"'Useless use of constant omitted'."> +or something similar depending on your shell). The default is '???'. +If you're using B::Deparse on a module or other file that's require'd, +you shouldn't use a value that evaluates to false, since the customary +true constant at the end of a module will be in void context when the +file is compiled as a main program. + =back =back +=head1 USING B::Deparse AS A MODULE + +=head2 Synopsis + + use B::Deparse; + $deparse = B::Deparse->new("-p", "-sC"); + $body = $deparse->coderef2text(\&func); + eval "sub func $body"; # the inverse operation + +=head2 Description + +B::Deparse can also be used on a sub-by-sub basis from other perl +programs. + +=head2 new + + $deparse = B::Deparse->new(OPTIONS) + +Create an object to store the state of a deparsing operation and any +options. The options are the same as those that can be given on the +command line (see L</OPTIONS>); options that are separated by commas +after B<-MO=Deparse> should be given as separate strings. Some +options, like B<-u>, don't make sense for a single subroutine, so +don't pass them. + +=head2 coderef2text + + $body = $deparse->coderef2text(\&func) + $body = $deparse->coderef2text(sub ($$) { ... }) + +Return source code for the body of a subroutine (a block, optionally +preceded by a prototype in parens), given a reference to the +sub. Because a subroutine can have no names, or more than one name, +this method doesn't return a complete subroutine definition -- if you +want to eval the result, you should prepend "sub subname ", or "sub " +for an anonymous function constructor. Unless the sub was defined in +the main:: package, the code will include a package declaration. + =head1 BUGS See the 'to do' list at the beginning of the module file. =head1 AUTHOR -Stephen McCamant <alias@mcs.com>, based on an earlier version by -Malcolm Beattie <mbeattie@sable.ox.ac.uk>. +Stephen McCamant <smccam@uclink4.berkeley.edu>, based on an earlier +version by Malcolm Beattie <mbeattie@sable.ox.ac.uk>, with +contributions from Gisle Aas, James Duncan, Albert Dvornik, Hugo van +der Sanden, Gurusamy Sarathy, and Nick Ing-Simmons. =cut diff --git a/contrib/perl5/ext/B/B/Disassembler.pm b/contrib/perl5/ext/B/B/Disassembler.pm index 4a008a3..d054a2d 100644 --- a/contrib/perl5/ext/B/B/Disassembler.pm +++ b/contrib/perl5/ext/B/B/Disassembler.pm @@ -52,6 +52,20 @@ sub GET_objindex { return unpack("N", $str); } +sub GET_opindex { + my $fh = shift; + my $str = $fh->readn(4); + croak "reached EOF while reading opindex" unless length($str) == 4; + return unpack("N", $str); +} + +sub GET_svindex { + my $fh = shift; + my $str = $fh->readn(4); + croak "reached EOF while reading svindex" unless length($str) == 4; + return unpack("N", $str); +} + sub GET_strconst { my $fh = shift; my ($str, $c); diff --git a/contrib/perl5/ext/B/B/Lint.pm b/contrib/perl5/ext/B/B/Lint.pm index d34bd77..ed0d07d 100644 --- a/contrib/perl5/ext/B/B/Lint.pm +++ b/contrib/perl5/ext/B/B/Lint.pm @@ -116,13 +116,9 @@ Malcolm Beattie, mbeattie@sable.ox.ac.uk. =cut use strict; -use B qw(walkoptree_slow main_root walksymtable svref_2object parents); - -# Constants (should probably be elsewhere) -sub G_ARRAY () { 1 } -sub OPf_LIST () { 1 } -sub OPf_KNOW () { 2 } -sub OPf_STACKED () { 64 } +use B qw(walkoptree_slow main_root walksymtable svref_2object parents + OPf_WANT_LIST OPf_WANT OPf_STACKED G_ARRAY + ); my $file = "unknown"; # shadows current filename my $line = 0; # shadows current line number @@ -133,8 +129,8 @@ my %check; my %implies_ok_context; BEGIN { map($implies_ok_context{$_}++, - qw(pp_scalar pp_av2arylen pp_aelem pp_aslice pp_helem pp_hslice - pp_keys pp_values pp_hslice pp_defined pp_undef pp_delete)); + qw(scalar av2arylen aelem aslice helem hslice + keys values hslice defined undef delete)); } # Lint checks turned on by default @@ -165,8 +161,8 @@ sub warning { sub gimme { my $op = shift; my $flags = $op->flags; - if ($flags & OPf_KNOW) { - return(($flags & OPf_LIST) ? 1 : 0); + if ($flags & OPf_WANT) { + return(($flags & OPf_WANT_LIST) ? 1 : 0); } return undef; } @@ -175,8 +171,8 @@ sub B::OP::lint {} sub B::COP::lint { my $op = shift; - if ($op->ppaddr eq "pp_nextstate") { - $file = $op->filegv->SV->PV; + if ($op->name eq "nextstate") { + $file = $op->file; $line = $op->line; $curstash = $op->stash->NAME; } @@ -184,24 +180,24 @@ sub B::COP::lint { sub B::UNOP::lint { my $op = shift; - my $ppaddr = $op->ppaddr; - if ($check{context} && ($ppaddr eq "pp_rv2av" || $ppaddr eq "pp_rv2hv")) { + my $opname = $op->name; + if ($check{context} && ($opname eq "rv2av" || $opname eq "rv2hv")) { my $parent = parents->[0]; - my $pname = $parent->ppaddr; + my $pname = $parent->name; return if gimme($op) || $implies_ok_context{$pname}; # Two special cases to deal with: "foreach (@foo)" and "delete $a{$b}" # null out the parent so we have to check for a parent of pp_null and # a grandparent of pp_enteriter or pp_delete - if ($pname eq "pp_null") { - my $gpname = parents->[1]->ppaddr; - return if $gpname eq "pp_enteriter" || $gpname eq "pp_delete"; + if ($pname eq "null") { + my $gpname = parents->[1]->name; + return if $gpname eq "enteriter" || $gpname eq "delete"; } warning("Implicit scalar context for %s in %s", - $ppaddr eq "pp_rv2av" ? "array" : "hash", $parent->desc); + $opname eq "rv2av" ? "array" : "hash", $parent->desc); } - if ($check{private_names} && $ppaddr eq "pp_method") { + if ($check{private_names} && $opname eq "method") { my $methop = $op->first; - if ($methop->ppaddr eq "pp_const") { + if ($methop->name eq "const") { my $method = $methop->sv->PV; if ($method =~ /^_/ && !defined(&{"$curstash\::$method"})) { warning("Illegal reference to private method name $method"); @@ -213,14 +209,12 @@ sub B::UNOP::lint { sub B::PMOP::lint { my $op = shift; if ($check{implicit_read}) { - my $ppaddr = $op->ppaddr; - if ($ppaddr eq "pp_match" && !($op->flags & OPf_STACKED)) { + if ($op->name eq "match" && !($op->flags & OPf_STACKED)) { warning('Implicit match on $_'); } } if ($check{implicit_write}) { - my $ppaddr = $op->ppaddr; - if ($ppaddr eq "pp_subst" && !($op->flags & OPf_STACKED)) { + if ($op->name eq "subst" && !($op->flags & OPf_STACKED)) { warning('Implicit substitution on $_'); } } @@ -229,34 +223,35 @@ sub B::PMOP::lint { sub B::LOOP::lint { my $op = shift; if ($check{implicit_read} || $check{implicit_write}) { - my $ppaddr = $op->ppaddr; - if ($ppaddr eq "pp_enteriter") { + if ($op->name eq "enteriter") { my $last = $op->last; - if ($last->ppaddr eq "pp_gv" && $last->gv->NAME eq "_") { + if ($last->name eq "gv" && $last->gv->NAME eq "_") { warning('Implicit use of $_ in foreach'); } } } } -sub B::GVOP::lint { +sub B::SVOP::lint { my $op = shift; - if ($check{dollar_underscore} && $op->ppaddr eq "pp_gvsv" + if ($check{dollar_underscore} && $op->name eq "gvsv" && $op->gv->NAME eq "_") { warning('Use of $_'); } if ($check{private_names}) { - my $ppaddr = $op->ppaddr; - my $gv = $op->gv; - if (($ppaddr eq "pp_gv" || $ppaddr eq "pp_gvsv") - && $gv->NAME =~ /^_./ && $gv->STASH->NAME ne $curstash) - { - warning('Illegal reference to private name %s', $gv->NAME); + my $opname = $op->name; + if ($opname eq "gv" || $opname eq "gvsv") { + my $gv = $op->gv; + if ($gv->NAME =~ /^_./ && $gv->STASH->NAME ne $curstash) { + warning('Illegal reference to private name %s', $gv->NAME); + } } } if ($check{undefined_subs}) { - if ($op->ppaddr eq "pp_gv" && $op->next->ppaddr eq "pp_entersub") { + if ($op->name eq "gv" + && $op->next->name eq "entersub") + { my $gv = $op->gv; my $subname = $gv->STASH->NAME . "::" . $gv->NAME; no strict 'refs'; @@ -266,7 +261,7 @@ sub B::GVOP::lint { } } } - if ($check{regexp_variables} && $op->ppaddr eq "pp_gvsv") { + if ($check{regexp_variables} && $op->name eq "gvsv") { my $name = $op->gv->NAME; if ($name =~ /^[&'`]$/) { warning('Use of regexp variable $%s', $name); diff --git a/contrib/perl5/ext/B/B/Stackobj.pm b/contrib/perl5/ext/B/B/Stackobj.pm index eea966c..0db3e33 100644 --- a/contrib/perl5/ext/B/B/Stackobj.pm +++ b/contrib/perl5/ext/B/B/Stackobj.pm @@ -5,34 +5,35 @@ # You may distribute under the terms of either the GNU General Public # License or the Artistic License, as specified in the README file. # -package B::Stackobj; +package B::Stackobj; use Exporter (); @ISA = qw(Exporter); -@EXPORT_OK = qw(set_callback T_UNKNOWN T_DOUBLE T_INT +@EXPORT_OK = qw(set_callback T_UNKNOWN T_DOUBLE T_INT VALID_UNSIGNED VALID_INT VALID_DOUBLE VALID_SV REGISTER TEMPORARY); %EXPORT_TAGS = (types => [qw(T_UNKNOWN T_DOUBLE T_INT)], flags => [qw(VALID_INT VALID_DOUBLE VALID_SV - REGISTER TEMPORARY)]); + VALID_UNSIGNED REGISTER TEMPORARY)]); use Carp qw(confess); use strict; -use B qw(class); - -# Perl internal constants that I should probably define elsewhere. -sub SVf_IOK () { 0x10000 } -sub SVf_NOK () { 0x20000 } +use B qw(class SVf_IOK SVf_NOK SVf_IVisUV); # Types sub T_UNKNOWN () { 0 } sub T_DOUBLE () { 1 } sub T_INT () { 2 } +sub T_SPECIAL () { 3 } # Flags sub VALID_INT () { 0x01 } -sub VALID_DOUBLE () { 0x02 } -sub VALID_SV () { 0x04 } -sub REGISTER () { 0x08 } # no implicit write-back when calling subs -sub TEMPORARY () { 0x10 } # no implicit write-back needed at all +sub VALID_UNSIGNED () { 0x02 } +sub VALID_DOUBLE () { 0x04 } +sub VALID_SV () { 0x08 } +sub REGISTER () { 0x10 } # no implicit write-back when calling subs +sub TEMPORARY () { 0x20 } # no implicit write-back needed at all +sub SAVE_INT () { 0x40 } #if int part needs to be saved at all +sub SAVE_DOUBLE () { 0x80 } #if double part needs to be saved at all + # # Callback for runtime code generation @@ -47,7 +48,7 @@ sub runtime { &$runtime_callback(@_) } sub write_back { confess "stack object does not implement write_back" } -sub invalidate { shift->{flags} &= ~(VALID_INT | VALID_DOUBLE) } +sub invalidate { shift->{flags} &= ~(VALID_INT |VALID_UNSIGNED | VALID_DOUBLE) } sub as_sv { my $obj = shift; @@ -62,7 +63,7 @@ sub as_int { my $obj = shift; if (!($obj->{flags} & VALID_INT)) { $obj->load_int; - $obj->{flags} |= VALID_INT; + $obj->{flags} |= VALID_INT|SAVE_INT; } return $obj->{iv}; } @@ -71,7 +72,7 @@ sub as_double { my $obj = shift; if (!($obj->{flags} & VALID_DOUBLE)) { $obj->load_double; - $obj->{flags} |= VALID_DOUBLE; + $obj->{flags} |= VALID_DOUBLE|SAVE_DOUBLE; } return $obj->{nv}; } @@ -81,6 +82,17 @@ sub as_numeric { return $obj->{type} == T_INT ? $obj->as_int : $obj->as_double; } +sub as_bool { + my $obj=shift; + if ($obj->{flags} & VALID_INT ){ + return $obj->{iv}; + } + if ($obj->{flags} & VALID_DOUBLE ){ + return $obj->{nv}; + } + return sprintf("(SvTRUE(%s))", $obj->as_sv) ; +} + # # Debugging methods # @@ -126,17 +138,18 @@ sub minipeek { # set_numeric and set_sv are only invoked on legal lvalues. # sub set_int { - my ($obj, $expr) = @_; + my ($obj, $expr,$unsigned) = @_; runtime("$obj->{iv} = $expr;"); $obj->{flags} &= ~(VALID_SV | VALID_DOUBLE); - $obj->{flags} |= VALID_INT; + $obj->{flags} |= VALID_INT|SAVE_INT; + $obj->{flags} |= VALID_UNSIGNED if $unsigned; } sub set_double { my ($obj, $expr) = @_; runtime("$obj->{nv} = $expr;"); $obj->{flags} &= ~(VALID_SV | VALID_INT); - $obj->{flags} |= VALID_DOUBLE; + $obj->{flags} |= VALID_DOUBLE|SAVE_DOUBLE; } sub set_numeric { @@ -162,6 +175,8 @@ sub set_sv { @B::Stackobj::Padsv::ISA = 'B::Stackobj'; sub B::Stackobj::Padsv::new { my ($class, $type, $extra_flags, $ix, $iname, $dname) = @_; + $extra_flags |= SAVE_INT if $extra_flags & VALID_INT; + $extra_flags |= SAVE_DOUBLE if $extra_flags & VALID_DOUBLE; bless { type => $type, flags => VALID_SV | $extra_flags, @@ -178,14 +193,23 @@ sub B::Stackobj::Padsv::load_int { } else { runtime("$obj->{iv} = SvIV($obj->{sv});"); } - $obj->{flags} |= VALID_INT; + $obj->{flags} |= VALID_INT|SAVE_INT; } sub B::Stackobj::Padsv::load_double { my $obj = shift; $obj->write_back; runtime("$obj->{nv} = SvNV($obj->{sv});"); - $obj->{flags} |= VALID_DOUBLE; + $obj->{flags} |= VALID_DOUBLE|SAVE_DOUBLE; +} +sub B::Stackobj::Padsv::save_int { + my $obj = shift; + return $obj->{flags} & SAVE_INT; +} + +sub B::Stackobj::Padsv::save_double { + my $obj = shift; + return $obj->{flags} & SAVE_DOUBLE; } sub B::Stackobj::Padsv::write_back { @@ -193,7 +217,11 @@ sub B::Stackobj::Padsv::write_back { my $flags = $obj->{flags}; return if $flags & VALID_SV; if ($flags & VALID_INT) { - runtime("sv_setiv($obj->{sv}, $obj->{iv});"); + if ($flags & VALID_UNSIGNED ){ + runtime("sv_setuv($obj->{sv}, $obj->{iv});"); + }else{ + runtime("sv_setiv($obj->{sv}, $obj->{iv});"); + } } elsif ($flags & VALID_DOUBLE) { runtime("sv_setnv($obj->{sv}, $obj->{nv});"); } else { @@ -213,17 +241,26 @@ sub B::Stackobj::Const::new { flags => 0, sv => $sv # holds the SV object until write_back happens }, $class; - my $svflags = $sv->FLAGS; - if ($svflags & SVf_IOK) { - $obj->{flags} = VALID_INT|VALID_DOUBLE; - $obj->{type} = T_INT; - $obj->{nv} = $obj->{iv} = $sv->IV; - } elsif ($svflags & SVf_NOK) { - $obj->{flags} = VALID_INT|VALID_DOUBLE; - $obj->{type} = T_DOUBLE; - $obj->{iv} = $obj->{nv} = $sv->NV; - } else { - $obj->{type} = T_UNKNOWN; + if ( ref($sv) eq "B::SPECIAL" ){ + $obj->{type}= T_SPECIAL; + }else{ + my $svflags = $sv->FLAGS; + if ($svflags & SVf_IOK) { + $obj->{flags} = VALID_INT|VALID_DOUBLE; + $obj->{type} = T_INT; + if ($svflags & SVf_IVisUV){ + $obj->{flags} |= VALID_UNSIGNED; + $obj->{nv} = $obj->{iv} = $sv->UVX; + }else{ + $obj->{nv} = $obj->{iv} = $sv->IV; + } + } elsif ($svflags & SVf_NOK) { + $obj->{flags} = VALID_INT|VALID_DOUBLE; + $obj->{type} = T_DOUBLE; + $obj->{iv} = $obj->{nv} = $sv->NV; + } else { + $obj->{type} = T_UNKNOWN; + } } return $obj; } @@ -238,13 +275,21 @@ sub B::Stackobj::Const::write_back { sub B::Stackobj::Const::load_int { my $obj = shift; - $obj->{iv} = int($obj->{sv}->PV); + if (ref($obj->{sv}) eq "B::RV"){ + $obj->{iv} = int($obj->{sv}->RV->PV); + }else{ + $obj->{iv} = int($obj->{sv}->PV); + } $obj->{flags} |= VALID_INT; } sub B::Stackobj::Const::load_double { my $obj = shift; - $obj->{nv} = $obj->{sv}->PV + 0.0; + if (ref($obj->{sv}) eq "B::RV"){ + $obj->{nv} = $obj->{sv}->RV->PV + 0.0; + }else{ + $obj->{nv} = $obj->{sv}->PV + 0.0; + } $obj->{flags} |= VALID_DOUBLE; } diff --git a/contrib/perl5/ext/B/B/Stash.pm b/contrib/perl5/ext/B/B/Stash.pm new file mode 100644 index 0000000..0a3543e --- /dev/null +++ b/contrib/perl5/ext/B/B/Stash.pm @@ -0,0 +1,42 @@ +# Stash.pm -- show what stashes are loaded +# vishalb@hotmail.com +package B::Stash; + +BEGIN { %Seen = %INC } + +CHECK { + my @arr=scan($main::{"main::"}); + @arr=map{s/\:\:$//;$_;} @arr; + print "-umain,-u", join (",-u",@arr) ,"\n"; +} +sub scan{ + my $start=shift; + my $prefix=shift; + $prefix = '' unless defined $prefix; + my @return; + foreach my $key ( keys %{$start}){ +# print $prefix,$key,"\n"; + if ($key =~ /::$/){ + unless ($start eq ${$start}{$key} or $key eq "B::" ){ + push @return, $key unless omit($prefix.$key); + foreach my $subscan ( scan(${$start}{$key},$prefix.$key)){ + push @return, "$key".$subscan; + } + } + } + } + return @return; +} +sub omit{ + my $module = shift; + my %omit=("DynaLoader::" => 1 , "XSLoader::" => 1, "CORE::" => 1 , + "CORE::GLOBAL::" => 1, "UNIVERSAL::" => 1 ); + return 1 if $omit{$module}; + if ($module eq "IO::" or $module eq "IO::Handle::"){ + $module =~ s/::/\//g; + return 1 unless $INC{$module}; + } + + return 0; +} +1; diff --git a/contrib/perl5/ext/B/B/Terse.pm b/contrib/perl5/ext/B/B/Terse.pm index 93757f3..66b5cfc 100644 --- a/contrib/perl5/ext/B/B/Terse.pm +++ b/contrib/perl5/ext/B/B/Terse.pm @@ -17,6 +17,7 @@ sub terse { sub compile { my $order = shift; my @options = @_; + B::clearsym(); if (@options) { return sub { my $objname; @@ -53,10 +54,9 @@ sub B::SVOP::terse { $op->sv->terse(0); } -sub B::GVOP::terse { +sub B::PADOP::terse { my ($op, $level) = @_; - print indent($level), peekop($op), " "; - $op->gv->terse(0); + print indent($level), peekop($op), " ", $op->padix, "\n"; } sub B::PMOP::terse { @@ -78,7 +78,7 @@ sub B::COP::terse { if ($label) { $label = " label ".cstring($label); } - print indent($level), peekop($op), $label, "\n"; + print indent($level), peekop($op), $label || "", "\n"; } sub B::PV::terse { diff --git a/contrib/perl5/ext/B/B/Xref.pm b/contrib/perl5/ext/B/B/Xref.pm index 0102856..b4078b8 100644 --- a/contrib/perl5/ext/B/B/Xref.pm +++ b/contrib/perl5/ext/B/B/Xref.pm @@ -85,11 +85,10 @@ Malcolm Beattie, mbeattie@sable.ox.ac.uk. =cut use strict; -use B qw(peekop class comppadlist main_start svref_2object walksymtable); - -# Constants (should probably be elsewhere) -sub OPpLVAL_INTRO () { 128 } -sub SVf_POK () { 0x40000 } +use Config; +use B qw(peekop class comppadlist main_start svref_2object walksymtable + OPpLVAL_INTRO SVf_POK + ); sub UNKNOWN { ["?", "?", "?"] } @@ -135,17 +134,28 @@ sub process { sub load_pad { my $padlist = shift; - my ($namelistav, @namelist, $ix); + my ($namelistav, $vallistav, @namelist, $ix); @pad = (); return if class($padlist) eq "SPECIAL"; - ($namelistav) = $padlist->ARRAY; + ($namelistav,$vallistav) = $padlist->ARRAY; @namelist = $namelistav->ARRAY; for ($ix = 1; $ix < @namelist; $ix++) { my $namesv = $namelist[$ix]; next if class($namesv) eq "SPECIAL"; - my ($type, $name) = $namesv->PV =~ /^(.)(.*)$/; + my ($type, $name) = $namesv->PV =~ /^(.)([^\0]*)(\0.*)?$/; $pad[$ix] = ["(lexical)", $type, $name]; } + if ($Config{useithreads}) { + my (@vallist); + @vallist = $vallistav->ARRAY; + for ($ix = 1; $ix < @vallist; $ix++) { + my $valsv = $vallist[$ix]; + next unless class($valsv) eq "GV"; + # these pad GVs don't have corresponding names, so same @pad + # array can be used without collisions + $pad[$ix] = [$valsv->STASH->NAME, "*", $valsv->NAME]; + } + } } sub xref { @@ -155,28 +165,24 @@ sub xref { last if $done{$$op}++; warn sprintf("top = [%s, %s, %s]\n", @$top) if $debug_top; warn peekop($op), "\n" if $debug_op; - my $ppname = $op->ppaddr; - if ($ppname =~ /^pp_(or|and|mapwhile|grepwhile)$/) { + my $opname = $op->name; + if ($opname =~ /^(or|and|mapwhile|grepwhile|range|cond_expr)$/) { xref($op->other); - } elsif ($ppname eq "pp_match" || $ppname eq "pp_subst") { + } elsif ($opname eq "match" || $opname eq "subst") { xref($op->pmreplstart); - } elsif ($ppname eq "pp_substcont") { + } elsif ($opname eq "substcont") { xref($op->other->pmreplstart); $op = $op->other; redo; - } elsif ($ppname eq "pp_cond_expr") { - # pp_cond_expr never returns op_next - xref($op->true); - $op = $op->false; - redo; - } elsif ($ppname eq "pp_enterloop") { + } elsif ($opname eq "enterloop") { xref($op->redoop); xref($op->nextop); xref($op->lastop); - } elsif ($ppname eq "pp_subst") { + } elsif ($opname eq "subst") { xref($op->pmreplstart); } else { no strict 'refs'; + my $ppname = "pp_$opname"; &$ppname($op) if defined(&$ppname); } } @@ -207,7 +213,7 @@ sub xref_main { sub pp_nextstate { my $op = shift; - $file = $op->filegv->SV->PV; + $file = $op->file; $line = $op->line; $top = UNKNOWN; } @@ -235,23 +241,45 @@ sub pp_rv2gv { deref($top, "*"); } sub pp_gvsv { my $op = shift; - my $gv = $op->gv; - $top = [$gv->STASH->NAME, '$', $gv->NAME]; + my $gv; + if ($Config{useithreads}) { + $top = $pad[$op->padix]; + $top = UNKNOWN unless $top; + $top->[1] = '$'; + } + else { + $gv = $op->gv; + $top = [$gv->STASH->NAME, '$', $gv->NAME]; + } process($top, $op->private & OPpLVAL_INTRO ? "intro" : "used"); } sub pp_gv { my $op = shift; - my $gv = $op->gv; - $top = [$gv->STASH->NAME, "*", $gv->NAME]; + my $gv; + if ($Config{useithreads}) { + $top = $pad[$op->padix]; + $top = UNKNOWN unless $top; + $top->[1] = '*'; + } + else { + $gv = $op->gv; + $top = [$gv->STASH->NAME, "*", $gv->NAME]; + } process($top, $op->private & OPpLVAL_INTRO ? "intro" : "used"); } sub pp_const { my $op = shift; my $sv = $op->sv; - $top = ["?", "", - (class($sv) ne "SPECIAL" && $sv->FLAGS & SVf_POK) ? $sv->PV : "?"]; + # constant could be in the pad (under useithreads) + if ($$sv) { + $top = ["?", "", + (class($sv) ne "SPECIAL" && $sv->FLAGS & SVf_POK) ? $sv->PV : "?"]; + } + else { + $top = $pad[$op->targ]; + } } sub pp_method { @@ -278,7 +306,7 @@ sub B::GV::xref { my $cv = $gv->CV; if ($$cv) { #return if $done{$$cv}++; - $file = $gv->FILEGV->SV->PV; + $file = $gv->FILE; $line = $gv->LINE; process([$gv->STASH->NAME, "&", $gv->NAME], "subdef"); push(@todo, $cv); @@ -286,7 +314,7 @@ sub B::GV::xref { my $form = $gv->FORM; if ($$form) { return if $done{$$form}++; - $file = $gv->FILEGV->SV->PV; + $file = $gv->FILE; $line = $gv->LINE; process([$gv->STASH->NAME, "", $gv->NAME], "formdef"); } @@ -296,7 +324,7 @@ sub xref_definitions { my ($pack, %exclude); return if $nodefs; $subname = "(definitions)"; - foreach $pack (qw(B O AutoLoader DynaLoader Config DB VMS + foreach $pack (qw(B O AutoLoader DynaLoader XSLoader Config DB VMS strict vars FileHandle Exporter Carp)) { $exclude{$pack."::"} = 1; } diff --git a/contrib/perl5/ext/B/Makefile.PL b/contrib/perl5/ext/B/Makefile.PL index 80e5e1b..cb9696b 100644 --- a/contrib/perl5/ext/B/Makefile.PL +++ b/contrib/perl5/ext/B/Makefile.PL @@ -16,31 +16,21 @@ if ($^O eq 'MSWin32') { WriteMakefile( NAME => "B", VERSION => "a5", - MAN3PODS => {}, + PL_FILES => { 'defsubs_h.PL' => 'defsubs.h' }, + MAN3PODS => {}, clean => { - FILES => "perl$e byteperl$e *$o B.c *~" + FILES => "perl$e *$o B.c defsubs.h *~" } -); +); -sub MY::post_constants { - "\nLIBS = $Config{libs}\n" -} +package MY; -# Leave out doing byteperl for now. Probably should be built in the -# core directory or somewhere else rather than here -#sub MY::top_targets { -# my $self = shift; -# my $targets = $self->MM::top_targets(); -# $targets =~ s/^(all ::.*)$/$1 byteperl$e/m; -# return <<"EOT" . $targets; +sub post_constants { + "\nLIBS = $Config::Config{libs}\n" +} -# -# byteperl is *not* a standard perl+XSUB executable. It's a special -# program for running standalone bytecode executables. It isn't an XSUB -# at the moment because a standlone Perl program needs to set up curpad -# which is overwritten on exit from an XSUB. -# -#byteperl$e : byteperl$o B$o \$(PERL_SRC)/byterun$o -# \$(CC) ${exeout_flag}byteperl$e byteperl$o B$o byterun$o \$(LDFLAGS) \$(PERL_ARCHLIB)/CORE/$Config{libperl} \$(LIBS) -#EOT -#} +sub postamble { +' +B$(OBJ_EXT) : defsubs.h +' +} diff --git a/contrib/perl5/ext/B/NOTES b/contrib/perl5/ext/B/NOTES index ee10ba0..89d03ba 100644 --- a/contrib/perl5/ext/B/NOTES +++ b/contrib/perl5/ext/B/NOTES @@ -161,8 +161,8 @@ O module it should return a sub ref (usually a closure) to perform the actual compilation. When O regains control, it ensures that the "-c" option is forced (so that the program being compiled doesn't - end up running) and registers an END block to call back the sub ref + end up running) and registers a CHECK block to call back the sub ref returned from the backend's compile(). Perl then continues by parsing prog.pl (just as it would with "perl -c prog.pl") and after - doing so, assuming there are no parse-time errors, the END block + doing so, assuming there are no parse-time errors, the CHECK block of O gets called and the actual backend compilation happens. Phew. diff --git a/contrib/perl5/ext/B/O.pm b/contrib/perl5/ext/B/O.pm index ad391a3..352f8d4 100644 --- a/contrib/perl5/ext/B/O.pm +++ b/contrib/perl5/ext/B/O.pm @@ -11,7 +11,7 @@ sub import { my $compilesub = &{"B::${backend}::compile"}(@options); if (ref($compilesub) eq "CODE") { minus_c; - eval 'END { &$compilesub() }'; + eval 'CHECK { &$compilesub() }'; } else { die $compilesub; } @@ -59,7 +59,7 @@ C<B::Backend> module and calls the C<compile> function in that package, passing it OPTIONS. That function is expected to return a sub reference which we'll call CALLBACK. Next, the "compile-only" flag is switched on (equivalent to the command-line option C<-c>) -and an END block is registered which calls CALLBACK. Thus the main +and a CHECK block is registered which calls CALLBACK. Thus the main Perl program mentioned on the command-line is read in, parsed and compiled into internal syntax tree form. Since the C<-c> flag is set, the program does not start running (excepting BEGIN blocks of diff --git a/contrib/perl5/ext/B/defsubs_h.PL b/contrib/perl5/ext/B/defsubs_h.PL new file mode 100644 index 0000000..80ef936 --- /dev/null +++ b/contrib/perl5/ext/B/defsubs_h.PL @@ -0,0 +1,35 @@ +# Do not remove the following line; MakeMaker relies on it to identify +# this file as a template for defsubs.h +# Extracting defsubs.h (with variable substitutions) +#!perl +my ($out) = __FILE__ =~ /(^.*)\.PL/i; +$out =~ s/_h$/.h/; +open(OUT,">$out") || die "Cannot open $file:$!"; +print "Extracting $out...\n"; +foreach my $const (qw(AVf_REAL + HEf_SVKEY + SVf_IOK SVf_IVisUV SVf_NOK SVf_POK + SVf_ROK SVp_IOK SVp_POK )) + { + doconst($const); + } +foreach my $file (qw(op.h cop.h)) + { + open(OPH,"../../$file") || die "Cannot open ../../$file:$!"; + while (<OPH>) + { + doconst($1) if (/#define\s+(\w+)\s+([\(\)\|\dx]+)\s*(?:$|\/\*)/); + } + close(OPH); + } +close(OUT); + +sub doconst +{ + my $sym = shift; + my $l = length($sym); + print OUT <<"END"; + newCONSTSUB(stash,"$sym",newSViv($sym)); + av_push(export_ok,newSVpvn("$sym",$l)); +END +} diff --git a/contrib/perl5/ext/B/ramblings/flip-flop b/contrib/perl5/ext/B/ramblings/flip-flop index 183d541..e0cb8ff 100644 --- a/contrib/perl5/ext/B/ramblings/flip-flop +++ b/contrib/perl5/ext/B/ramblings/flip-flop @@ -1,21 +1,24 @@ PP(pp_range) { if (GIMME == G_ARRAY) - return cCONDOP->op_true; - return SvTRUEx(PAD_SV(op->op_targ)) ? cCONDOP->op_false : cCONDOP->op_true; + return NORMAL; + if (SvTRUEx(PAD_SV(PL_op->op_targ))) + return cLOGOP->op_other; + else + return NORMAL; } -pp_range is a CONDOP. -In array context, it just returns op_true. +pp_range is a LOGOP. +In array context, it just returns op_next. In scalar context it checks the truth of targ and returns -op_false if true, op_true if false. +op_other if true, op_next if false. flip is an UNOP. -It "looks after" its child which is always a pp_range CONDOP. -In array context, it just returns the child's op_false. +It "looks after" its child which is always a pp_range LOGOP. +In array context, it just returns the child's op_other. In scalar context, there are three possible outcomes: (1) set child's targ to 1, our targ to 1 and return op_next. - (2) set child's targ to 1, our targ to 0, sp-- and return child's op_false. + (2) set child's targ to 1, our targ to 0, sp-- and return child's op_other. (3) Blank targ and TOPs and return op_next. Case 1 happens for a "..." with a matching lineno... or true TOPs. Case 2 happens for a ".." with a matching lineno... or true TOPs. @@ -37,14 +40,14 @@ Case 3 happens for a non-matching lineno or false TOPs. /* range */ if (SvTRUE(curpad[op->op_targ])) - goto label(op_false); -/* op_true */ + goto label(op_other); +/* op_next */ ... /* flip */ -/* For "..." returns op_next. For ".." returns op_next or op_first->op_false */ +/* For "..." returns op_next. For ".." returns op_next or op_first->op_other */ /* end of basic block */ goto out; -label(range op_false): +label(range op_other): ... /* flop */ out: diff --git a/contrib/perl5/ext/B/ramblings/runtime.porting b/contrib/perl5/ext/B/ramblings/runtime.porting index 4699b25..d58b011 100644 --- a/contrib/perl5/ext/B/ramblings/runtime.porting +++ b/contrib/perl5/ext/B/ramblings/runtime.porting @@ -33,8 +33,10 @@ glob 5 2 do_readline readline 8 2 do_readline rcatline 8 2 regcmaybe 8 1 +regcreset 8 1 regcomp 8 9 pregcomp match 8 10 +qr 8 1 subst 8 10 substcont 8 7 trans 7 4 do_trans @@ -170,6 +172,7 @@ orassign 7 3 modifies flow of control method 8 5 entersub 10 7 leavesub 10 5 +leavesublv caller 2 8 warn 9 3 die 9 3 @@ -212,6 +215,7 @@ leavewrite 4 5 prtf 4 4 do_sprintf print 8 6 sysopen 8 2 +sysseek 8 2 sysread 8 4 syswrite 8 4 pp_send send 8 4 @@ -347,4 +351,7 @@ sgrent egrent getlogin syscall -
\ No newline at end of file +lock 6 1 +threadsv 6 2 unused if not USE_THREADS +setstate 1 1 currently unused anywhere +method_named 10 2 diff --git a/contrib/perl5/ext/B/typemap b/contrib/perl5/ext/B/typemap index 7206a6a..bafba1c 100644 --- a/contrib/perl5/ext/B/typemap +++ b/contrib/perl5/ext/B/typemap @@ -4,11 +4,10 @@ B::OP T_OP_OBJ B::UNOP T_OP_OBJ B::BINOP T_OP_OBJ B::LOGOP T_OP_OBJ -B::CONDOP T_OP_OBJ B::LISTOP T_OP_OBJ B::PMOP T_OP_OBJ B::SVOP T_OP_OBJ -B::GVOP T_OP_OBJ +B::PADOP T_OP_OBJ B::PVOP T_OP_OBJ B::CVOP T_OP_OBJ B::LOOP T_OP_OBJ @@ -31,12 +30,13 @@ B::IO T_SV_OBJ B::MAGIC T_MG_OBJ SSize_t T_IV STRLEN T_IV +PADOFFSET T_UV INPUT T_OP_OBJ if (SvROK($arg)) { IV tmp = SvIV((SV*)SvRV($arg)); - $var = ($type) tmp; + $var = INT2PTR($type,tmp); } else croak(\"$var is not a reference\") @@ -44,7 +44,7 @@ T_OP_OBJ T_SV_OBJ if (SvROK($arg)) { IV tmp = SvIV((SV*)SvRV($arg)); - $var = ($type) tmp; + $var = INT2PTR($type,tmp); } else croak(\"$var is not a reference\") @@ -52,18 +52,18 @@ T_SV_OBJ T_MG_OBJ if (SvROK($arg)) { IV tmp = SvIV((SV*)SvRV($arg)); - $var = ($type) tmp; + $var = INT2PTR($type,tmp); } else croak(\"$var is not a reference\") OUTPUT T_OP_OBJ - sv_setiv(newSVrv($arg, cc_opclassname((OP*)$var)), (IV)$var); + sv_setiv(newSVrv($arg, cc_opclassname(aTHX_ (OP*)$var)), PTR2IV($var)); T_SV_OBJ - make_sv_object(($arg), (SV*)($var)); + make_sv_object(aTHX_ ($arg), (SV*)($var)); T_MG_OBJ - sv_setiv(newSVrv($arg, "B::MAGIC"), (IV)$var); + sv_setiv(newSVrv($arg, "B::MAGIC"), PTR2IV($var)); |