static opclass
cc_opclass(pTHX_ const OP *o)
{
+ bool custom = 0;
+
if (!o)
return OPc_NULL;
return OPc_PADOP;
#endif
- switch (PL_opargs[o->op_type] & OA_CLASS_MASK) {
+ if (o->op_type == OP_CUSTOM)
+ custom = 1;
+
+ switch (OP_CLASS(o)) {
case OA_BASEOP:
return OPc_BASEOP;
* 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))
+ return (!custom &&
+ (o->op_private & (OPpTRANS_TO_UTF|OPpTRANS_FROM_UTF))
+ )
#if defined(USE_ITHREADS) \
&& (PERL_VERSION > 8 || (PERL_VERSION == 8 && PERL_SUBVERSION >= 9))
? OPc_PADOP : OPc_PVOP;
return OPc_PVOP;
}
warn("can't determine class of operator %s, assuming BASEOP\n",
- PL_op_name[o->op_type]);
+ OP_NAME(o));
return OPc_BASEOP;
}
-static char *
-cc_opclassname(pTHX_ const OP *o)
+static SV *
+make_op_object(pTHX_ const OP *o)
{
- return (char *)opclassnames[cc_opclass(aTHX_ o)];
+ SV *opsv = sv_newmortal();
+ sv_setiv(newSVrv(opsv, opclassnames[cc_opclass(aTHX_ o)]), PTR2IV(o));
+ return opsv;
}
-/* FIXME - figure out how to get the typemap to assign this to ST(0), rather
- than creating a new mortal for ST(0) then passing it in as the first
- argument. */
static SV *
-make_sv_object(pTHX_ SV *arg, SV *sv)
+make_sv_object(pTHX_ SV *sv)
{
+ SV *const arg = sv_newmortal();
const char *type = 0;
IV iv;
dMY_CXT;
- if (!arg)
- arg = sv_newmortal();
-
- for (iv = 0; iv < sizeof(specialsv_list)/sizeof(SV*); iv++) {
+ for (iv = 0; iv < (IV)(sizeof(specialsv_list)/sizeof(SV*)); iv++) {
if (sv == specialsv_list[iv]) {
type = "B::SPECIAL";
break;
Perl_emulate_cop_io(aTHX_ cop, value);
if(SvOK(value)) {
- return make_sv_object(aTHX_ NULL, value);
+ return make_sv_object(aTHX_ value);
} else {
SvREFCNT_dec(value);
- return make_sv_object(aTHX_ NULL, NULL);
+ return make_sv_object(aTHX_ NULL);
}
}
#endif
dSP;
OP *kid;
SV *object;
- const char *const classname = cc_opclassname(aTHX_ o);
+ const char *const classname = opclassnames[cc_opclass(aTHX_ o)];
dMY_CXT;
/* Check that no-one has changed our reference, or is holding a reference
oplist(pTHX_ OP *o, SV **SP)
{
for(; o; o = o->op_next) {
- SV *opsv;
#if PERL_VERSION >= 9
if (o->op_opt == 0)
break;
break;
o->op_seq = 0;
#endif
- opsv = sv_newmortal();
- sv_setiv(newSVrv(opsv, cc_opclassname(aTHX_ (OP*)o)), PTR2IV(o));
- XPUSHs(opsv);
+ XPUSHs(make_op_object(aTHX_ o));
switch (o->op_type) {
case OP_SUBST:
SP = oplist(aTHX_ PMOP_pmreplstart(cPMOPo), SP);
typedef struct refcounted_he *B__RHE;
#endif
-#ifdef USE_ITHREADS
+#ifdef MULTIPLICITY
# define ASSIGN_COMMON_ALIAS(var) \
STMT_START { XSANY.any_i32 = offsetof(struct interpreter, var); } STMT_END
#else
SV *ret;
if (items != 0)
croak_xs_usage(cv, "");
-#ifdef USE_ITHREADS
+#ifdef MULTIPLICITY
ret = *(SV **)(XSANY.any_i32 + (char *)my_perl);
#else
ret = *(SV **)(XSANY.any_ptr);
#endif
- ST(0) = make_sv_object(aTHX_ NULL, ret);
+ ST(0) = make_sv_object(aTHX_ ret);
XSRETURN(1);
}
OUTPUT:
RETVAL
-B::AV
+void
comppadlist()
- CODE:
- RETVAL = PL_main_cv ? CvPADLIST(PL_main_cv) : CvPADLIST(PL_compcv);
- OUTPUT:
- RETVAL
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ (SV *)(PL_main_cv ? CvPADLIST(PL_main_cv)
+ : CvPADLIST(PL_compcv))));
-B::SV
+void
sv_undef()
ALIAS:
sv_no = 1
sv_yes = 2
- CODE:
- RETVAL = ix > 1 ? &PL_sv_yes : ix < 1 ? &PL_sv_undef : &PL_sv_no;
- OUTPUT:
- RETVAL
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ ix > 1 ? &PL_sv_yes
+ : ix < 1 ? &PL_sv_undef
+ : &PL_sv_no));
-B::OP
+void
main_root()
ALIAS:
main_start = 1
- CODE:
- RETVAL = ix ? PL_main_start : PL_main_root;
- OUTPUT:
- RETVAL
+ PPCODE:
+ PUSHs(make_op_object(aTHX_ ix ? PL_main_start : PL_main_root));
UV
sub_generation()
address(sv)
SV * sv
-B::SV
+void
svref_2object(sv)
SV * sv
- CODE:
+ PPCODE:
if (!SvROK(sv))
croak("argument is not a reference");
- RETVAL = (SV*)SvRV(sv);
- OUTPUT:
- RETVAL
+ PUSHs(make_sv_object(aTHX_ SvRV(sv)));
void
opnumber(name)
else
PL_minus_c = TRUE;
-SV *
+void
cstring(sv)
SV * sv
ALIAS:
perlstring = 1
cchar = 2
PPCODE:
- PUSHs(ix == 2 ? cchar(aTHX_ sv) : cstring(aTHX_ sv, ix));
+ PUSHs(ix == 2 ? cchar(aTHX_ sv) : cstring(aTHX_ sv, (bool)ix));
void
threadsv_names()
ptr = (ix & 0xFFFF) + (char *)o;
switch ((U8)(ix >> 16)) {
case (U8)(OPp >> 16):
- {
- OP *const o2 = *((OP **)ptr);
- ret = sv_newmortal();
- sv_setiv(newSVrv(ret, cc_opclassname(aTHX_ o2)), PTR2IV(o2));
- break;
- }
+ ret = make_op_object(aTHX_ *((OP **)ptr));
+ break;
case (U8)(PADOFFSETp >> 16):
ret = sv_2mortal(newSVuv(*((PADOFFSET*)ptr)));
break;
ret = sv_2mortal(newSVuv(*((U32*)ptr)));
break;
case (U8)(SVp >> 16):
- ret = make_sv_object(aTHX_ NULL, *((SV **)ptr));
+ ret = make_sv_object(aTHX_ *((SV **)ptr));
break;
case (U8)(line_tp >> 16):
ret = sv_2mortal(newSVuv(*((line_t *)ptr)));
ret = sv_2mortal(newSVpv(*((char **)ptr), 0));
break;
#endif
+ default:
+ croak("Illegal alias 0x%08x for B::*next", (unsigned)ix);
+
}
ST(0) = ret;
XSRETURN(1);
ALIAS:
desc = 1
CODE:
- RETVAL = (char *)(ix ? PL_op_desc : PL_op_name)[o->op_type];
+ RETVAL = (char *)(ix ? OP_DESC(o) : OP_NAME(o));
OUTPUT:
RETVAL
B::PMOP o
OP * root = NO_INIT
CODE:
- ST(0) = sv_newmortal();
root = o->op_pmreplroot;
/* OP_PUSHRE stores an SV* instead of an OP* in op_pmreplroot */
if (o->op_type == OP_PUSHRE) {
+ ST(0) = sv_newmortal();
# ifdef USE_ITHREADS
sv_setiv(ST(0), INT2PTR(PADOFFSET,root) );
# else
# endif
}
else {
- sv_setiv(newSVrv(ST(0), cc_opclassname(aTHX_ root)), PTR2IV(root));
+ ST(0) = make_op_object(aTHX_ root);
}
#else
PMOP_pmreplroot(o)
B::PMOP o
CODE:
- ST(0) = sv_newmortal();
if (o->op_type == OP_PUSHRE) {
# ifdef USE_ITHREADS
+ ST(0) = sv_newmortal();
sv_setiv(ST(0), o->op_pmreplrootu.op_pmtargetoff);
# else
GV *const target = o->op_pmreplrootu.op_pmtargetgv;
+ ST(0) = sv_newmortal();
sv_setiv(newSVrv(ST(0), target ?
svclassnames[SvTYPE((SV*)target)] : "B::SV"),
PTR2IV(target));
}
else {
OP *const root = o->op_pmreplrootu.op_pmreplroot;
- sv_setiv(newSVrv(ST(0), cc_opclassname(aTHX_ root)),
- PTR2IV(root));
+ ST(0) = make_op_object(aTHX_ root);
}
#endif
B::PMOP o
#else
-#define PMOP_pmstash(o) PmopSTASH(o);
-B::HV
+void
PMOP_pmstash(o)
B::PMOP o
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ (SV *) PmopSTASH(o)));
#endif
#if PERL_VERSION < 9
-#define PMOP_pmnext(o) o->op_pmnext
-B::PMOP
+void
PMOP_pmnext(o)
B::PMOP o
+ PPCODE:
+ PUSHs(make_op_object(aTHX_ o->op_pmnext));
U32
PMOP_pmpermflags(o)
MODULE = B PACKAGE = B::PADOP
-B::SV
+void
sv(o)
B::PADOP o
+ PREINIT:
+ SV *ret;
ALIAS:
gv = 1
- CODE:
+ PPCODE:
/* It happens that the output typemaps for B::SV and B::GV are
identical. The "smarts" are in make_sv_object(), which determines
which class to use based on SvTYPE(), rather than anything baked in
at compile time. */
if (o->op_padix) {
- RETVAL = PAD_SVl(o->op_padix);
- if (ix && SvTYPE(RETVAL) != SVt_PVGV)
- RETVAL = NULL;
+ ret = PAD_SVl(o->op_padix);
+ if (ix && SvTYPE(ret) != SVt_PVGV)
+ ret = NULL;
} else {
- RETVAL = NULL;
+ ret = NULL;
}
- OUTPUT:
- RETVAL
+ PUSHs(make_sv_object(aTHX_ ret));
MODULE = B PACKAGE = B::PVOP
#ifdef USE_ITHREADS
-B::SV
+void
COP_stash(o)
B::COP o
ALIAS:
filegv = 1
- CODE:
- RETVAL = ix ? (SV *)CopFILEGV(o) : (SV *)CopSTASH(o);
- OUTPUT:
- RETVAL
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_
+ ix ? (SV *)CopFILEGV(o) : (SV *)CopSTASH(o)));
#else
void
COP_warnings(o)
B::COP o
- PPCODE:
-#if PERL_VERSION >= 9
- ST(0) = make_warnings_object(aTHX_ o);
-#else
- ST(0) = make_sv_object(aTHX_ NULL, o->cop_warnings);
-#endif
- XSRETURN(1);
-
-void
-COP_io(o)
- B::COP o
- PPCODE:
+ ALIAS:
+ io = 1
+ PPCODE:
#if PERL_VERSION >= 9
- ST(0) = make_cop_io_object(aTHX_ o);
+ ST(0) = ix ? make_cop_io_object(aTHX_ o) : make_warnings_object(aTHX_ o);
#else
- ST(0) = make_sv_object(aTHX_ NULL, o->cop_io);
+ ST(0) = make_sv_object(aTHX_ ix ? o->cop_io : o->cop_warnings);
#endif
XSRETURN(1);
#define PVMG_stash_ix sv_SVp | offsetof(struct xpvmg, xmg_stash)
#if PERL_VERSION >= 10
+# if PERL_VERSION > 14
+# define PVBM_useful_ix sv_I32p | offsetof(struct xpvgv, xnv_u.xbm_s.xbm_useful)
+# define PVBM_previous_ix sv_UVp | offsetof(struct xpvuv, xuv_uv)
+# else
#define PVBM_useful_ix sv_I32p | offsetof(struct xpvgv, xiv_u.xivu_i32)
#define PVBM_previous_ix sv_U32p | offsetof(struct xpvgv, xnv_u.xbm_s.xbm_previous)
+# endif
#define PVBM_rare_ix sv_U8p | offsetof(struct xpvgv, xnv_u.xbm_s.xbm_rare)
#else
#define PVBM_useful_ix sv_I32p | offsetof(struct xpvbm, xbm_useful)
ptr = (ix & 0xFFFF) + (char *)SvANY(sv);
switch ((U8)(ix >> 16)) {
case (U8)(sv_SVp >> 16):
- ret = make_sv_object(aTHX_ NULL, *((SV **)ptr));
+ ret = make_sv_object(aTHX_ *((SV **)ptr));
break;
case (U8)(sv_IVp >> 16):
ret = sv_2mortal(newSViv(*((IV *)ptr)));
case (U8)(sv_U16p >> 16):
ret = sv_2mortal(newSVuv(*((U16 *)ptr)));
break;
+ default:
+ croak("Illegal alias 0x%08x for B::*IVX", (unsigned)ix);
}
ST(0) = ret;
XSRETURN(1);
MODULE = B PACKAGE = B::RV PREFIX = Sv
-B::SV
+void
SvRV(sv)
B::RV sv
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ SvRV(sv)));
#else
MODULE = B PACKAGE = B::PV
-B::SV
+void
RV(sv)
B::PV sv
- CODE:
- if( SvROK(sv) ) {
- RETVAL = SvRV(sv);
- }
- else {
+ PPCODE:
+ if (!SvROK(sv))
croak( "argument is not SvROK" );
- }
- OUTPUT:
- RETVAL
+ PUSHs(make_sv_object(aTHX_ SvRV(sv)));
void
PV(sv)
len = 256;
} else if (ix == 2) {
/* This used to read 257. I think that that was buggy - should have
- been 258. (The "\0", the flags byte, and 256 for the table. Not
- that anything anywhere calls this method. NWC. */
- /* Also, the start pointer has always been SvPVX(sv). Surely it
- should be SvPVX(sv) + SvCUR(sv)? The code has faithfully been
- refactored with this behaviour, since PVBM was added in
- 651aa52ea1faa806. */
+ been 258. (The "\0", the flags byte, and 256 for the table.)
+ The only user of this method is B::Bytecode in B::PV::bsave.
+ I'm guessing that nothing tested the runtime correctness of
+ output of bytecompiled string constant arguments to index (etc).
+
+ Note the start pointer is and has always been SvPVX(sv), not
+ SvPVX(sv) + SvCUR(sv) PVBM was added in 651aa52ea1faa806, and
+ first used by the compiler in 651aa52ea1faa806. It's used to
+ get a "complete" dump of the buffer at SvPVX(), not just the
+ PVBM table. This permits the generated bytecode to "load"
+ SvPVX in "one" hit. */
p = SvPVX_const(sv);
len = SvCUR(sv) + (SvVALID(sv) ? 256 + PERL_FBM_TABLE_OFFSET : 0);
} else if (ix) {
to avoid tripping up over variable names in the pads. */
if((SvLEN(sv) && len >= SvLEN(sv))) {
/* It claims to be longer than the space allocated for it -
- presuambly it's a variable name in the pad */
+ presumably it's a variable name in the pad */
len = strlen(p);
}
#endif
PRIVATE = 1
TYPE = 2
FLAGS = 3
- LEN = 4
+ LENGTH = 4
OBJ = 5
PTR = 6
REGEX = 7
mPUSHi(mg->mg_len);
break;
case 5:
- PUSHs(make_sv_object(aTHX_ NULL, mg->mg_obj));
+ PUSHs(make_sv_object(aTHX_ mg->mg_obj));
break;
case 6:
if (mg->mg_ptr) {
if (mg->mg_len >= 0) {
PUSHs(newSVpvn_flags(mg->mg_ptr, mg->mg_len, SVs_TEMP));
} else if (mg->mg_len == HEf_SVKEY) {
- PUSHs(make_sv_object(aTHX_ NULL, (SV*)mg->mg_ptr));
+ PUSHs(make_sv_object(aTHX_ (SV*)mg->mg_ptr));
} else
PUSHs(sv_newmortal());
} else
ptr = (ix & 0xFFFF) + (char *)gp;
switch ((U8)(ix >> 16)) {
case (U8)(SVp >> 16):
- ret = make_sv_object(aTHX_ NULL, *((SV **)ptr));
+ ret = make_sv_object(aTHX_ *((SV **)ptr));
break;
case (U8)(U32p >> 16):
ret = sv_2mortal(newSVuv(*((U32*)ptr)));
case (U8)(line_tp >> 16):
ret = sv_2mortal(newSVuv(*((line_t *)ptr)));
break;
+ default:
+ croak("Illegal alias 0x%08x for B::*SV", (unsigned)ix);
}
ST(0) = ret;
XSRETURN(1);
-B::GV
-GvFILEGV(gv)
+void
+FILEGV(gv)
B::GV gv
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ (SV *)GvFILEGV(gv)));
MODULE = B PACKAGE = B::IO PREFIX = Io
SV **svp = AvARRAY(av);
I32 i;
for (i = 0; i <= AvFILL(av); i++)
- XPUSHs(make_sv_object(aTHX_ NULL, svp[i]));
+ XPUSHs(make_sv_object(aTHX_ svp[i]));
}
void
int idx
PPCODE:
if (idx >= 0 && AvFILL(av) >= 0 && idx <= AvFILL(av))
- XPUSHs(make_sv_object(aTHX_ NULL, (AvARRAY(av)[idx])));
+ XPUSHs(make_sv_object(aTHX_ (AvARRAY(av)[idx])));
else
- XPUSHs(make_sv_object(aTHX_ NULL, NULL));
+ XPUSHs(make_sv_object(aTHX_ NULL));
#if PERL_VERSION < 9
CvCONST(cv)
B::CV cv
-B::OP
+void
CvSTART(cv)
B::CV cv
ALIAS:
ROOT = 1
- CODE:
- RETVAL = CvISXSUB(cv) ? NULL : ix ? CvROOT(cv) : CvSTART(cv);
- OUTPUT:
- RETVAL
+ PPCODE:
+ PUSHs(make_op_object(aTHX_ CvISXSUB(cv) ? NULL
+ : ix ? CvROOT(cv) : CvSTART(cv)));
void
CvXSUB(cv)
XSUBANY = 1
CODE:
ST(0) = ix && CvCONST(cv)
- ? make_sv_object(aTHX_ NULL, (SV *)CvXSUBANY(cv).any_ptr)
+ ? make_sv_object(aTHX_ (SV *)CvXSUBANY(cv).any_ptr)
: sv_2mortal(newSViv(CvISXSUB(cv)
? (ix ? CvXSUBANY(cv).any_iv
: PTR2IV(CvXSUB(cv)))
: 0));
-MODULE = B PACKAGE = B::CV PREFIX = cv_
-
-B::SV
-cv_const_sv(cv)
+void
+const_sv(cv)
B::CV cv
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ (SV *)cv_const_sv(cv)));
MODULE = B PACKAGE = B::HV PREFIX = Hv
B::PMOP
HvPMROOT(hv)
B::HV hv
+ PPCODE:
+ PUSHs(make_op_object(aTHX_ HvPMROOT(hv)));
#endif
HvARRAY(hv)
B::HV hv
PPCODE:
- if (HvKEYS(hv) > 0) {
+ if (HvUSEDKEYS(hv) > 0) {
SV *sv;
char *key;
I32 len;
(void)hv_iterinit(hv);
- EXTEND(sp, HvKEYS(hv) * 2);
+ EXTEND(sp, HvUSEDKEYS(hv) * 2);
while ((sv = hv_iternextsv(hv, &key, &len))) {
mPUSHp(key, len);
- PUSHs(make_sv_object(aTHX_ NULL, sv));
+ PUSHs(make_sv_object(aTHX_ sv));
}
}
MODULE = B PACKAGE = B::HE PREFIX = He
-B::SV
+void
HeVAL(he)
B::HE he
ALIAS:
SVKEY_force = 1
- CODE:
- RETVAL = ix ? HeSVKEY_force(he) : HeVAL(he);
- OUTPUT:
- RETVAL
+ PPCODE:
+ PUSHs(make_sv_object(aTHX_ ix ? HeSVKEY_force(he) : HeVAL(he)));
U32
HeHASH(he)