#include "EXTERN.h"
#define PERL_IN_PP_HOT_C
#include "perl.h"
#include "regcomp.h"
PP(pp_const)
{
dSP;
XPUSHs(cSVOP_sv);
RETURN;
}
PP(pp_nextstate)
{
PL_curcop = (COP*)PL_op;
TAINT_NOT;
PL_stack_sp = PL_stack_base + CX_CUR()->blk_oldsp;
FREETMPS;
PERL_ASYNC_CHECK();
return
NORMAL;
}
PP(pp_gvsv)
{
dSP;
EXTEND(SP,1);
if
(UNLIKELY(PL_op->op_private & OPpLVAL_INTRO))
PUSHs(save_scalar(cGVOP_gv));
else
PUSHs(GvSVn(cGVOP_gv));
RETURN;
}
PP(pp_null)
{
return
NORMAL;
}
PP(pp_pushmark)
{
PUSHMARK(PL_stack_sp);
return
NORMAL;
}
PP(pp_stringify)
{
dSP; dTARGET;
SV *
const
sv = TOPs;
SETs(TARG);
sv_copypv(TARG, sv);
SvSETMAGIC(TARG);
return
NORMAL;
}
PP(pp_gv)
{
dSP;
XPUSHs(MUTABLE_SV(cGVOP_gv));
RETURN;
}
PP(pp_and)
{
PERL_ASYNC_CHECK();
{
SV *
const
sv = *PL_stack_sp;
if
(!SvTRUE_NN(sv))
return
NORMAL;
else
{
if
(PL_op->op_type == OP_AND)
--PL_stack_sp;
return
cLOGOP->op_other;
}
}
}
PP(pp_sassign)
{
dSP;
SV *left = POPs; SV *right = TOPs;
if
(PL_op->op_private & OPpASSIGN_BACKWARDS) {
SV *
const
temp = left;
left = right; right = temp;
}
assert
(TAINTING_get || !TAINT_get);
if
(UNLIKELY(TAINT_get) && !SvTAINTED(right))
TAINT_NOT;
if
(UNLIKELY(PL_op->op_private & OPpASSIGN_CV_TO_GV)) {
SV *
const
cv = SvRV(right);
const
U32 cv_type = SvTYPE(cv);
const
bool
is_gv = isGV_with_GP(left);
const
bool
got_coderef = cv_type == SVt_PVCV || cv_type == SVt_PVFM;
if
(!got_coderef) {
assert
(SvROK(cv));
}
if
(!got_coderef && !is_gv && GIMME_V == G_VOID) {
GV *
const
gv = gv_fetchsv_nomg(left, GV_NOINIT, SVt_PVGV);
if
(SvTYPE(gv) != SVt_PVGV && !SvOK(gv)) {
SV *
const
value = SvRV(cv);
SvUPGRADE(MUTABLE_SV(gv), SVt_IV);
SvPCS_IMPORTED_on(gv);
SvRV_set(gv, value);
SvREFCNT_inc_simple_void(value);
SETs(left);
RETURN;
}
}
if
(!is_gv) {
left = MUTABLE_SV(gv_fetchsv_nomg(left,GV_ADD, SVt_PVGV));
}
if
(!got_coderef) {
if
(SvROK(cv)) {
ENTER_with_name(
"sassign_coderef"
);
SvREFCNT_inc_void(SvRV(cv));
SvRV_set(right, MUTABLE_SV(newCONSTSUB(GvSTASH(left), NULL,
SvRV(cv))));
SvREFCNT_dec_NN(cv);
LEAVE_with_name(
"sassign_coderef"
);
}
else
{
GV *
const
upgraded = MUTABLE_GV(cv);
CV *
const
source = GvCV(upgraded);
assert
(source);
assert
(CvFLAGS(source) & CVf_CONST);
SvREFCNT_inc_simple_void_NN(source);
SvREFCNT_dec_NN(upgraded);
SvRV_set(right, MUTABLE_SV(source));
}
}
}
if
(
UNLIKELY(SvTEMP(left)) && !SvSMAGICAL(left) && SvREFCNT(left) == 1 &&
(!isGV_with_GP(left) || SvFAKE(left)) && ckWARN(WARN_MISC)
)
Perl_warner(aTHX_
packWARN(WARN_MISC),
"Useless assignment to a temporary"
);
SvSetMagicSV(left, right);
SETs(left);
RETURN;
}
PP(pp_cond_expr)
{
dSP;
SV *sv;
PERL_ASYNC_CHECK();
sv = POPs;
RETURNOP(SvTRUE_NN(sv) ? cLOGOP->op_other : cLOGOP->op_next);
}
PP(pp_unstack)
{
PERL_CONTEXT *cx;
PERL_ASYNC_CHECK();
TAINT_NOT;
cx = CX_CUR();
PL_stack_sp = PL_stack_base + cx->blk_oldsp;
FREETMPS;
if
(!(PL_op->op_flags & OPf_SPECIAL)) {
assert
(CxTYPE(cx) == CXt_BLOCK || CxTYPE_is_LOOP(cx));
CX_LEAVE_SCOPE(cx);
}
return
NORMAL;
}
PERL_STATIC_INLINE
void
S_do_concat(pTHX_ SV *left, SV *right, SV *targ, U8 targmy)
{
bool
lbyte;
STRLEN rlen;
const
char
*rpv = NULL;
bool
rbyte = FALSE;
bool
rcopied = FALSE;
if
(TARG == right && right != left) {
rpv = SvPV_nomg_const(right, rlen);
rbyte = !DO_UTF8(right);
right = newSVpvn_flags(rpv, rlen, SVs_TEMP);
rpv = SvPV_const(right, rlen);
rcopied = TRUE;
}
if
(TARG != left) {
STRLEN llen;
const
char
*
const
lpv = SvPV_nomg_const(left, llen);
lbyte = !DO_UTF8(left);
sv_setpvn(TARG, lpv, llen);
if
(!lbyte)
SvUTF8_on(TARG);
else
SvUTF8_off(TARG);
}
else
{
if
(!SvOK(left)) {
if
((left == right
|| targmy)
&& ckWARN(WARN_UNINITIALIZED)
)
report_uninit(left);
SvPVCLEAR(left);
}
else
{
SvPV_force_nomg_nolen(left);
}
lbyte = !DO_UTF8(left);
if
(IN_BYTES)
SvUTF8_off(left);
}
if
(!rcopied) {
rpv = SvPV_nomg_const(right, rlen);
rbyte = !DO_UTF8(right);
}
if
(lbyte != rbyte) {
if
(lbyte)
sv_utf8_upgrade_nomg(TARG);
else
{
if
(!rcopied)
right = newSVpvn_flags(rpv, rlen, SVs_TEMP);
sv_utf8_upgrade_nomg(right);
rpv = SvPV_nomg_const(right, rlen);
}
}
sv_catpvn_nomg(TARG, rpv, rlen);
SvSETMAGIC(TARG);
}
PP(pp_concat)
{
dSP; dATARGET; tryAMAGICbin_MG(concat_amg, AMGf_assign);
{
dPOPTOPssrl;
S_do_concat(aTHX_ left, right, targ, PL_op->op_private & OPpTARGET_MY);
SETs(TARG);
RETURN;
}
}
PP(pp_multiconcat)
{
dSP;
SV *targ;
char
*targ_pv;
STRLEN targ_len;
SV **toparg;
UNOP_AUX_item *aux;
UNOP_AUX_item *const_lens;
const
char
*const_pv;
SSize_t nargs;
SSize_t stack_adj;
STRLEN grow;
UV targ_count;
bool
is_append;
bool
slow_concat;
U32 dst_utf8;
struct
multiconcat_svpv {
const
char
*pv;
SSize_t len;
}
*targ_chain,
*svpv_p,
*svpv_base,
*svpv_end,
svpv_buf[PERL_MULTICONCAT_MAXARG];
aux = cUNOP_AUXx(PL_op)->op_aux;
stack_adj = nargs = aux[PERL_MULTICONCAT_IX_NARGS].ssize;
is_append = cBOOL(PL_op->op_private & OPpMULTICONCAT_APPEND);
if
(PL_op->op_flags & OPf_STACKED) {
if
(is_append) {
targ = SP[-nargs];
stack_adj++;
}
else
targ = POPs;
}
else
{
SV **svp = &(PAD_SVl(PL_op->op_targ));
targ = *svp;
if
(PL_op->op_private & OPpLVAL_INTRO) {
assert
(PL_op->op_private & OPpTARGET_MY);
save_clearsv(svp);
}
if
(!nargs)
EXTEND(SP,1);
}
toparg = SP;
SP -= (nargs - 1);
grow = 1;
targ_count = 0;
targ_chain = NULL;
targ_len = 0;
svpv_end = svpv_buf;
dst_utf8 = aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv ? 0 : SVf_UTF8;
for
(; SP <= toparg; SP++, svpv_end++) {
U32 utf8;
STRLEN len;
SV *sv;
assert
(svpv_end - svpv_buf < PERL_MULTICONCAT_MAXARG);
sv = *SP;
if
(LIKELY((SvFLAGS(sv) & (SVs_GMG|SVf_ROK|SVf_POK)) == SVf_POK)) {
if
(targ == sv) {
targ_on_rhs:
svpv_end->len = 0;
svpv_end->pv = (
char
*)targ_chain;
targ_chain = svpv_end;
targ_count++;
continue
;
}
len = SvCUR(sv);
svpv_end->pv = SvPVX(sv);
}
else
if
(UNLIKELY(SvFLAGS(sv) & (SVs_GMG|SVf_ROK)))
goto
do_magical;
else
if
(SvNIOK(sv)) {
if
(targ == sv)
goto
targ_on_rhs;
svpv_end->pv = sv_2pv_flags(sv, &len, 0);
}
else
if
(!SvOK(sv)) {
if
(ckWARN(WARN_UNINITIALIZED))
goto
do_magical;
svpv_end->pv =
""
;
len = 0;
}
else
goto
do_magical;
utf8 = (SvFLAGS(sv) & SVf_UTF8);
dst_utf8 |= utf8;
ASSUME(len < SSize_t_MAX);
svpv_end->len = utf8 ? -(SSize_t)len : (SSize_t)len;
grow += len;
}
if
(is_append) {
if
(UNLIKELY(SvFLAGS(targ) & (SVs_GMG|SVf_ROK)))
goto
do_magical;
if
(SvOK(targ)) {
U32 targ_utf8;
stringify_targ:
SvPV_force_nomg_nolen(targ);
targ_utf8 = SvFLAGS(targ) & SVf_UTF8;
if
(UNLIKELY(dst_utf8 & ~targ_utf8)) {
if
(LIKELY(!IN_BYTES))
sv_utf8_upgrade_nomg(targ);
}
else
dst_utf8 |= targ_utf8;
targ_len = SvCUR(targ);
grow += targ_len * (targ_count + is_append);
goto
phase3;
}
else
if
(ckWARN(WARN_UNINITIALIZED))
goto
do_magical;
}
else
if
(UNLIKELY(SvTYPE(targ) >= SVt_REGEXP)) {
goto
do_magical;
}
else
if
(targ_chain)
goto
stringify_targ;
SV_CHECK_THINKFIRST_COW_DROP(targ);
SvUPGRADE(targ, SVt_PV);
SvFLAGS(targ) &= ~(SVf_OK|SVf_IVisUV|SVf_UTF8);
SvFLAGS(targ) |= (SVf_POK|SVp_POK|dst_utf8);
phase3:
if
(UNLIKELY(dst_utf8 && IN_BYTES)) {
dst_utf8 = 0;
SvUTF8_off(targ);
for
(svpv_p = svpv_buf; svpv_p < svpv_end; svpv_p++) {
SSize_t len = svpv_p->len;
if
(len < 0)
svpv_p->len = -len;
}
}
{
SSize_t len;
len = aux[dst_utf8 ? PERL_MULTICONCAT_IX_UTF8_LEN
: PERL_MULTICONCAT_IX_PLAIN_LEN].ssize;
slow_concat = cBOOL(len);
grow += len;
}
const_lens = aux + PERL_MULTICONCAT_IX_LENGTHS;
if
(dst_utf8) {
const_pv = aux[PERL_MULTICONCAT_IX_UTF8_PV].pv;
if
( aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv
&& const_pv != aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv)
const_lens += nargs + 1;
for
(svpv_p = svpv_buf; svpv_p < svpv_end; svpv_p++) {
SSize_t len, extra;
len = svpv_p->len;
if
(len <= 0) {
svpv_p->len = -len;
continue
;
}
extra = variant_under_utf8_count((U8 *) svpv_p->pv,
(U8 *) svpv_p->pv + len);
if
(UNLIKELY(extra)) {
grow += extra;
svpv_p->len = -(len + extra);
slow_concat = TRUE;
}
}
}
else
const_pv = aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv;
assert
(!SvIsCOW(targ));
targ_pv = (SvLEN(targ) < (grow) ? sv_grow(targ,grow) : SvPVX(targ));
svpv_base = svpv_buf;
if
(targ_len) {
struct
multiconcat_svpv *tc_stop;
char
*targ_buf = targ_pv;
assert
(is_append || targ_count);
if
(is_append) {
targ_pv += targ_len;
tc_stop = NULL;
}
else
{
UNOP_AUX_item *lens = const_lens;
STRLEN offset = lens->ssize > 0 ? lens->ssize : 0;
assert
(targ_chain);
svpv_p = svpv_base;
for
(;;) {
SSize_t len;
if
(!svpv_p->pv)
break
;
len = svpv_p->len;
if
(len < 0)
len = -len;
offset += (STRLEN)len;
len = (++lens)->ssize;
offset += (len >= 0) ? (STRLEN)len : 0;
if
(!offset) {
svpv_base++;
const_lens++;
}
svpv_p++;
assert
(svpv_p < svpv_end);
}
if
(offset) {
targ_buf += offset;
Move(targ_pv, targ_buf, targ_len,
char
);
svpv_p->len = -((SSize_t)targ_len);
slow_concat = TRUE;
}
else
{
svpv_base++;
const_lens++;
targ_pv += targ_len;
}
tc_stop = svpv_p;
}
while
(targ_chain != tc_stop) {
struct
multiconcat_svpv *p = targ_chain;
targ_chain = (
struct
multiconcat_svpv *)(p->pv);
p->pv = targ_buf;
p->len = (SSize_t)targ_len;
}
}
if
(!slow_concat) {
for
(svpv_p = svpv_base; svpv_p < svpv_end; svpv_p++) {
SSize_t len = svpv_p->len;
if
(!len)
continue
;
Copy(svpv_p->pv, targ_pv, len,
char
);
targ_pv += len;
}
const_lens += (svpv_end - svpv_base + 1);
}
else
{
svpv_p = svpv_base - 1;
for
(;;) {
SSize_t len = (const_lens++)->ssize;
if
(len > 0) {
Copy(const_pv, targ_pv, len,
char
);
targ_pv += len;
const_pv += len;
}
if
(++svpv_p == svpv_end)
break
;
len = svpv_p->len;
if
(LIKELY(len > 0)) {
Copy(svpv_p->pv, targ_pv, len,
char
);
targ_pv += len;
}
else
if
(UNLIKELY(len < 0)) {
const
char
*p = svpv_p->pv;
len = -len;
if
(UNLIKELY(p)) {
char
* end_pv = targ_pv + len;
assert
(dst_utf8);
while
(targ_pv < end_pv) {
U8 c = (U8) *p++;
append_utf8_from_native_byte(c, (U8**)&targ_pv);
}
}
else
targ_pv += len;
}
}
}
*targ_pv =
'\0'
;
SvCUR_set(targ, targ_pv - SvPVX(targ));
assert
(grow >= SvCUR(targ) + 1);
assert
(SvLEN(targ) >= SvCUR(targ) + 1);
SP -= stack_adj;
SvTAINT(targ);
SETTARG;
RETURN;
do_magical:
{
SSize_t i, n;
SV *left = NULL;
SV *right;
SV* nexttarg;
bool
nextappend;
U32 utf8 = 0;
SV **svp;
const
char
*cpv = aux[PERL_MULTICONCAT_IX_PLAIN_PV].pv;
UNOP_AUX_item *lens = aux + PERL_MULTICONCAT_IX_LENGTHS;
Size_t arg_count = 0;
if
(!cpv) {
cpv = aux[PERL_MULTICONCAT_IX_UTF8_PV].pv;
utf8 = SVf_UTF8;
}
svp = toparg - nargs + 1;
n = nargs *2 + 1;
for
(i = 0; i <= n; i++) {
SSize_t len;
if
( i == n
&& (PL_op->op_private &OPpMULTICONCAT_STRINGIFY)
&& !(SvPOK(left))
&& ( arg_count == 1
|| ( arg_count >= 3
&& !is_append
&& (PL_op->op_private & OPpTARGET_MY)
&& !(PL_op->op_private & OPpLVAL_INTRO)
)
)
)
{
SV *tmp = newSV_type_mortal(SVt_PV);
sv_copypv(tmp, left);
SvSETMAGIC(tmp);
left = tmp;
}
if
(i == n && !is_append)
break
;
len = lens[i >> 1].ssize;
if
(i == n) {
right = left;
left = targ;
}
else
if
(i & 1)
right = svp[(i >> 1)];
else
if
(len < 0)
continue
;
else
{
right = newSVpvn_flags(cpv, len, (utf8 | SVs_TEMP));
cpv += len;
}
arg_count++;
if
(arg_count <= 1) {
left = right;
continue
;
}
if
(arg_count == 2 && i < n) {
nexttarg = sv_newmortal();
nextappend = FALSE;
}
else
{
nexttarg = left;
nextappend = TRUE;
}
if
((SvFLAGS(left)|SvFLAGS(right)) & (SVf_ROK|SVs_GMG)) {
SvGETMAGIC(left);
if
(left != right)
SvGETMAGIC(right);
if
((SvAMAGIC(left) || SvAMAGIC(right))
&& ( !(PL_op->op_private & OPpMULTICONCAT_FAKE)
|| i == n)
)
{
SV *
const
tmpsv = amagic_call(left, right, concat_amg,
(nextappend ? AMGf_assign: 0));
if
(tmpsv) {
if
(nextappend) {
sv_setsv(left, tmpsv);
SvSETMAGIC(left);
}
else
left = tmpsv;
continue
;
}
}
if
(left == right && SvGMAGICAL(left)) {
SV * targetsv = right;
if
(!SvOK(right)) {
if
(ckWARN(WARN_UNINITIALIZED))
report_uninit(right);
targetsv = &PL_sv_no;
}
left = sv_mortalcopy_flags(targetsv, 0);
SvGETMAGIC(right);
}
}
S_do_concat(aTHX_ left, right, nexttarg, 0);
left = nexttarg;
}
SP = toparg - stack_adj + 1;
if
( !is_append
&& ( (PL_op->op_flags & OPf_STACKED)
|| (PL_op->op_private & OPpTARGET_MY))
) {
sv_setsv(targ, left);
SvSETMAGIC(targ);
}
else
targ = left;
SETs(targ);
RETURN;
}
}
STATIC OP*
S_pushav(pTHX_ AV*
const
av)
{
dSP;
const
SSize_t maxarg = AvFILL(av) + 1;
EXTEND(SP, maxarg);
if
(UNLIKELY(SvRMAGICAL(av))) {
PADOFFSET i;
for
(i=0; i < (PADOFFSET)maxarg; i++) {
SV **
const
svp = av_fetch(av, i, FALSE);
SP[i+1] = LIKELY(svp)
? *svp
: UNLIKELY(PL_op->op_flags & OPf_MOD)
? av_nonelem(av,i)
: &PL_sv_undef;
}
}
else
{
PADOFFSET i;
for
(i=0; i < (PADOFFSET)maxarg; i++) {
SV *sv = AvARRAY(av)[i];
SP[i+1] = LIKELY(sv)
? sv
: UNLIKELY(PL_op->op_flags & OPf_MOD)
? av_nonelem(av,i)
: &PL_sv_undef;
}
}
SP += maxarg;
PUTBACK;
return
NORMAL;
}
PP(pp_padrange)
{
dSP;
PADOFFSET base = PL_op->op_targ;
int
count = (
int
)(PL_op->op_private) & OPpPADRANGE_COUNTMASK;
if
(PL_op->op_flags & OPf_SPECIAL) {
PUSHMARK(SP);
(
void
)S_pushav(aTHX_ GvAVn(PL_defgv));
SPAGAIN;
}
if
((PL_op->op_flags & OPf_WANT) != OPf_WANT_VOID) {
int
i;
EXTEND(SP, count);
PUSHMARK(SP);
for
(i = 0; i <count; i++)
*++SP = PAD_SV(base+i);
}
if
(PL_op->op_private & OPpLVAL_INTRO) {
SV **svp = &(PAD_SVl(base));
const
UV payload = (UV)(
(base << (OPpPADRANGE_COUNTSHIFT + SAVE_TIGHT_SHIFT))
| (count << SAVE_TIGHT_SHIFT)
| SAVEt_CLEARPADRANGE);
int
i;
STATIC_ASSERT_STMT(OPpPADRANGE_COUNTMASK + 1 == (1 << OPpPADRANGE_COUNTSHIFT));
assert
((payload >> (OPpPADRANGE_COUNTSHIFT+SAVE_TIGHT_SHIFT))
== (Size_t)base);
{
dSS_ADD;
SS_ADD_UV(payload);
SS_ADD_END(1);
}
for
(i = 0; i <count; i++)
SvPADSTALE_off(*svp++);
}
RETURN;
}
PP(pp_padsv)
{
dSP;
EXTEND(SP, 1);
{
OP *
const
op = PL_op;
SV **
const
padentry = &(PAD_SVl(op->op_targ));
{
dTARG;
TARG = *padentry;
PUSHs(TARG);
PUTBACK;
}
if
(op->op_flags & OPf_MOD) {
if
(op->op_private & OPpLVAL_INTRO)
if
(!(op->op_private & OPpPAD_STATE))
save_clearsv(padentry);
if
(op->op_private & OPpDEREF) {
TOPs = vivify_ref(TOPs, op->op_private & OPpDEREF);
}
}
return
op->op_next;
}
}
PP(pp_readline)
{
dSP;
if
(TOPs) {
SvGETMAGIC(TOPs);
tryAMAGICunTARGETlist(iter_amg, 0);
PL_last_in_gv = MUTABLE_GV(*PL_stack_sp--);
}
else
PL_last_in_gv = PL_argvgv, PL_stack_sp--;
if
(!isGV_with_GP(PL_last_in_gv)) {
if
(SvROK(PL_last_in_gv) && isGV_with_GP(SvRV(PL_last_in_gv)))
PL_last_in_gv = MUTABLE_GV(SvRV(PL_last_in_gv));
else
{
dSP;
XPUSHs(MUTABLE_SV(PL_last_in_gv));
PUTBACK;
Perl_pp_rv2gv(aTHX);
PL_last_in_gv = MUTABLE_GV(*PL_stack_sp--);
assert
((SV*)PL_last_in_gv == &PL_sv_undef || isGV_with_GP(PL_last_in_gv));
}
}
return
do_readline();
}
PP(pp_eq)
{
dSP;
SV *left, *right;
U32 flags_and, flags_or;
tryAMAGICbin_MG(eq_amg, AMGf_numeric);
right = POPs;
left = TOPs;
flags_and = SvFLAGS(left) & SvFLAGS(right);
flags_or = SvFLAGS(left) | SvFLAGS(right);
SETs(boolSV(
( (flags_and & SVf_IOK) && ((flags_or & SVf_IVisUV) ==0 ) )
? (SvIVX(left) == SvIVX(right))
: (flags_and & SVf_NOK)
? (SvNVX(left) == SvNVX(right))
: ( do_ncmp(left, right) == 0)
));
RETURN;
}
PP(pp_preinc)
{
SV *sv = *PL_stack_sp;
if
(LIKELY(((sv->sv_flags &
(SVf_THINKFIRST|SVs_GMG|SVf_IVisUV|
SVf_IOK|SVf_NOK|SVf_POK|SVp_NOK|SVp_POK|SVf_ROK))
== SVf_IOK))
&& SvIVX(sv) != IV_MAX)
{
SvIV_set(sv, SvIVX(sv) + 1);
}
else
sv_inc(sv);
SvSETMAGIC(sv);
return
NORMAL;
}
PP(pp_predec)
{
SV *sv = *PL_stack_sp;
if
(LIKELY(((sv->sv_flags &
(SVf_THINKFIRST|SVs_GMG|SVf_IVisUV|
SVf_IOK|SVf_NOK|SVf_POK|SVp_NOK|SVp_POK|SVf_ROK))
== SVf_IOK))
&& SvIVX(sv) != IV_MIN)
{
SvIV_set(sv, SvIVX(sv) - 1);
}
else
sv_dec(sv);
SvSETMAGIC(sv);
return
NORMAL;
}
PP(pp_or)
{
dSP;
SV *sv;
PERL_ASYNC_CHECK();
sv = TOPs;
if
(SvTRUE_NN(sv))
RETURN;
else
{
if
(PL_op->op_type == OP_OR)
--SP;
RETURNOP(cLOGOP->op_other);
}
}
PP(pp_defined)
{
dSP;
SV* sv = TOPs;
bool
defined = FALSE;
const
int
op_type = PL_op->op_type;
const
bool
is_dor = (op_type == OP_DOR || op_type == OP_DORASSIGN);
if
(is_dor) {
PERL_ASYNC_CHECK();
if
(UNLIKELY(!sv || !SvANY(sv))) {
if
(op_type == OP_DOR)
--SP;
RETURNOP(cLOGOP->op_other);
}
}
else
{
if
(UNLIKELY(!sv || !SvANY(sv)))
RETSETNO;
}
#ifdef DEBUGGING
assert
(SvTYPE(sv) != SVt_PVAV);
assert
(SvTYPE(sv) != SVt_PVHV);
#endif
if
(UNLIKELY(SvTYPE(sv) == SVt_PVCV)) {
if
(CvROOT(sv) || CvXSUB(sv))
defined = TRUE;
}
else
{
SvGETMAGIC(sv);
if
(SvOK(sv))
defined = TRUE;
}
if
(is_dor) {
if
(defined)
RETURN;
if
(op_type == OP_DOR)
--SP;
RETURNOP(cLOGOP->op_other);
}
if
(defined)
RETSETYES;
RETSETNO;
}
PP(pp_add)
{
dSP; dATARGET;
bool
useleft; SV *svl, *svr;
tryAMAGICbin_MG(add_amg, AMGf_assign|AMGf_numeric);
svr = TOPs;
svl = TOPm1s;
#ifdef PERL_PRESERVE_IVUV
if
(!((svl->sv_flags|svr->sv_flags) & (SVf_IVisUV|SVs_GMG))) {
IV il, ir;
U32 flags = (svl->sv_flags & svr->sv_flags);
if
(flags & SVf_IOK) {
UV topl, topr;
il = SvIVX(svl);
ir = SvIVX(svr);
do_iv:
topl = ((UV)il) >> (UVSIZE * 8 - 2);
topr = ((UV)ir) >> (UVSIZE * 8 - 2);
if
(!( ((topl+1) | (topr+1)) & 2)) {
SP--;
TARGi(il + ir, 0);
SETs(TARG);
RETURN;
}
goto
generic;
}
else
if
(flags & SVf_NOK) {
NV nl = SvNVX(svl);
NV nr = SvNVX(svr);
if
(lossless_NV_to_IV(nl, &il) && lossless_NV_to_IV(nr, &ir)) {
goto
do_iv;
}
SP--;
TARGn(nl + nr, 0);
SETs(TARG);
RETURN;
}
}
generic:
useleft = USE_LEFT(svl);
if
(SvIV_please_nomg(svr)) {
UV auv = 0;
bool
auvok = FALSE;
bool
a_valid = 0;
if
(!useleft) {
auv = 0;
a_valid = auvok = 1;
}
else
{
if
(SvIV_please_nomg(svl)) {
if
((auvok = SvUOK(svl)))
auv = SvUVX(svl);
else
{
const
IV aiv = SvIVX(svl);
if
(aiv >= 0) {
auv = aiv;
auvok = 1;
}
else
{
auv = (UV) (0 - (UV) aiv);
}
}
a_valid = 1;
}
}
if
(a_valid) {
bool
result_good = 0;
UV result;
UV buv;
bool
buvok = SvUOK(svr);
if
(buvok)
buv = SvUVX(svr);
else
{
const
IV biv = SvIVX(svr);
if
(biv >= 0) {
buv = biv;
buvok = 1;
}
else
buv = (UV) (0 - (UV) biv);
}
if
(auvok ^ buvok) {
if
(auv >= buv) {
result = auv - buv;
if
(result <= auv)
result_good = 1;
}
else
{
result = buv - auv;
if
(result <= buv) {
auvok = !auvok;
result_good = 1;
}
}
}
else
{
result = auv + buv;
if
(result >= auv)
result_good = 1;
}
if
(result_good) {
SP--;
if
(auvok)
SETu( result );
else
{
if
(result <= (UV)IV_MIN)
SETi(result == (UV)IV_MIN
? IV_MIN : -(IV)result);
else
{
SETn( -(NV)result );
}
}
RETURN;
}
}
}
#else
useleft = USE_LEFT(svl);
#endif
{
NV value = SvNV_nomg(svr);
(
void
)POPs;
if
(!useleft) {
SETn(value);
RETURN;
}
SETn( value + SvNV_nomg(svl) );
RETURN;
}
}
PP(pp_aelemfast)
{
dSP;
AV *
const
av = PL_op->op_type == OP_AELEMFAST_LEX
? MUTABLE_AV(PAD_SV(PL_op->op_targ)) : GvAVn(cGVOP_gv);
const
U32 lval = PL_op->op_flags & OPf_MOD;
const
I8 key = (I8)PL_op->op_private;
SV** svp;
SV *sv;
assert
(SvTYPE(av) == SVt_PVAV);
EXTEND(SP, 1);
if
(!SvRMAGICAL(av) && key >= 0 && key <= AvFILLp(av)) {
sv = AvARRAY(av)[key];
if
(sv) {
PUSHs(sv);
RETURN;
}
}
svp = av_fetch(av, key, lval);
sv = (svp ? *svp : &PL_sv_undef);
if
(UNLIKELY(!svp && lval))
DIE(aTHX_ PL_no_aelem, (
int
)key);
if
(!lval && SvRMAGICAL(av) && SvGMAGICAL(sv))
mg_get(sv);
PUSHs(sv);
RETURN;
}
PP(pp_join)
{
dSP; dMARK; dTARGET;
MARK++;
do_join(TARG, *MARK, MARK, SP);
SP = MARK;
SETs(TARG);
RETURN;
}
PP(pp_print)
{
dSP; dMARK; dORIGMARK;
PerlIO *fp;
MAGIC *mg;
GV *
const
gv
= (PL_op->op_flags & OPf_STACKED) ? MUTABLE_GV(*++MARK) : PL_defoutgv;
IO *io = GvIO(gv);
if
(io
&& (mg = SvTIED_mg((
const
SV *)io, PERL_MAGIC_tiedscalar)))
{
had_magic:
if
(MARK == ORIGMARK) {
MEXTEND(SP, 1);
++MARK;
Move(MARK, MARK + 1, (SP - MARK) + 1, SV*);
++SP;
}
return
Perl_tied_method(aTHX_ SV_CONST(PRINT), mark - 1, MUTABLE_SV(io),
mg,
(G_SCALAR | TIED_METHOD_ARGUMENTS_ON_STACK
| (PL_op->op_type == OP_SAY
? TIED_METHOD_SAY : 0)), sp - mark);
}
if
(!io) {
if
( gv && GvEGVx(gv) && (io = GvIO(GvEGV(gv)))
&& (mg = SvTIED_mg((
const
SV *)io, PERL_MAGIC_tiedscalar)))
goto
had_magic;
report_evil_fh(gv);
SETERRNO(EBADF,RMS_IFI);
goto
just_say_no;
}
else
if
(!(fp = IoOFP(io))) {
if
(IoIFP(io))
report_wrongway_fh(gv,
'<'
);
else
report_evil_fh(gv);
SETERRNO(EBADF,IoIFP(io)?RMS_FAC:RMS_IFI);
goto
just_say_no;
}
else
{
SV *
const
ofs = GvSV(PL_ofsgv);
MARK++;
if
(ofs && (SvGMAGICAL(ofs) || SvOK(ofs))) {
while
(MARK <= SP) {
if
(!do_print(*MARK, fp))
break
;
MARK++;
if
(MARK <= SP) {
if
(!do_print(GvSV(PL_ofsgv), fp)) {
MARK--;
break
;
}
}
}
}
else
{
while
(MARK <= SP) {
if
(!do_print(*MARK, fp))
break
;
MARK++;
}
}
if
(MARK <= SP)
goto
just_say_no;
else
{
if
(PL_op->op_type == OP_SAY) {
if
(PerlIO_write(fp,
"\n"
, 1) == 0 || PerlIO_error(fp))
goto
just_say_no;
}
else
if
(PL_ors_sv && SvOK(PL_ors_sv))
if
(!do_print(PL_ors_sv, fp))
goto
just_say_no;
if
(IoFLAGS(io) & IOf_FLUSH)
if
(PerlIO_flush(fp) == EOF)
goto
just_say_no;
}
}
SP = ORIGMARK;
XPUSHs(&PL_sv_yes);
RETURN;
just_say_no:
SP = ORIGMARK;
XPUSHs(&PL_sv_undef);
RETURN;
}
PERL_STATIC_INLINE OP*
S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme,
bool
is_keys,
bool
has_targ)
{
bool
is_tied;
bool
is_bool;
MAGIC *mg;
dSP;
IV i;
SV *sv;
assert
(PL_op->op_type == OP_PADHV || PL_op->op_type == OP_RV2HV);
if
(gimme == G_LIST) {
hv_pushkv(hv, 3);
return
NORMAL;
}
if
(is_keys)
(
void
)hv_iterinit(hv);
if
(gimme == G_VOID)
return
NORMAL;
is_bool = ( PL_op->op_private & OPpTRUEBOOL
|| ( PL_op->op_private & OPpMAYBE_TRUEBOOL
&& block_gimme() == G_VOID));
is_tied = SvRMAGICAL(hv) && (mg = mg_find(MUTABLE_SV(hv), PERL_MAGIC_tied));
if
(UNLIKELY(is_tied)) {
if
(is_keys && !is_bool) {
i = 0;
while
(hv_iternext(hv))
i++;
goto
push_i;
}
else
{
sv = magic_scalarpack(hv, mg);
goto
push_sv;
}
}
else
{
#if defined(DYNAMIC_ENV_FETCH) && defined(VMS)
if
(SvRMAGICAL((
const
SV *)hv)
&& mg_find((
const
SV *)hv, PERL_MAGIC_env)) {
prime_env_iter();
}
#endif
i = HvUSEDKEYS(hv);
if
(is_bool) {
sv = i ? &PL_sv_yes : &PL_sv_zero;
push_sv:
PUSHs(sv);
}
else
{
push_i:
if
(has_targ) {
dTARGET;
PUSHi(i);
}
else
if
(is_keys) {
dTARG;
OP *k;
assert
(!OpHAS_SIBLING(PL_op));
k = PL_op->op_sibparent;
assert
(k->op_type == OP_KEYS);
TARG = PAD_SV(k->op_targ);
PUSHi(i);
}
else
mPUSHi(i);
}
}
PUTBACK;
return
NORMAL;
}
PP(pp_padav)
{
dSP; dTARGET;
U8 gimme;
assert
(SvTYPE(TARG) == SVt_PVAV);
if
(UNLIKELY( PL_op->op_private & OPpLVAL_INTRO ))
if
(LIKELY( !(PL_op->op_private & OPpPAD_STATE) ))
SAVECLEARSV(PAD_SVl(PL_op->op_targ));
EXTEND(SP, 1);
if
(PL_op->op_flags & OPf_REF) {
PUSHs(TARG);
RETURN;
}
else
if
(PL_op->op_private & OPpMAYBE_LVSUB) {
const
I32 flags = is_lvalue_sub();
if
(flags && !(flags & OPpENTERSUB_INARGS)) {
if
(GIMME_V == G_SCALAR)
Perl_croak(aTHX_
"Can't return array to lvalue scalar context"
);
PUSHs(TARG);
RETURN;
}
}
gimme = GIMME_V;
if
(gimme == G_LIST)
return
S_pushav(aTHX_ (AV*)TARG);
if
(gimme == G_SCALAR) {
const
SSize_t maxarg = AvFILL(MUTABLE_AV(TARG)) + 1;
if
(!maxarg)
PUSHs(&PL_sv_zero);
else
if
(PL_op->op_private & OPpTRUEBOOL)
PUSHs(&PL_sv_yes);
else
mPUSHi(maxarg);
}
RETURN;
}
PP(pp_padhv)
{
dSP; dTARGET;
U8 gimme;
assert
(SvTYPE(TARG) == SVt_PVHV);
if
(UNLIKELY( PL_op->op_private & OPpLVAL_INTRO ))
if
(LIKELY( !(PL_op->op_private & OPpPAD_STATE) ))
SAVECLEARSV(PAD_SVl(PL_op->op_targ));
EXTEND(SP, 1);
if
(PL_op->op_flags & OPf_REF) {
PUSHs(TARG);
RETURN;
}
else
if
(PL_op->op_private & OPpMAYBE_LVSUB) {
const
I32 flags = is_lvalue_sub();
if
(flags && !(flags & OPpENTERSUB_INARGS)) {
if
(GIMME_V == G_SCALAR)
Perl_croak(aTHX_
"Can't return hash to lvalue scalar context"
);
PUSHs(TARG);
RETURN;
}
}
gimme = GIMME_V;
return
S_padhv_rv2hv_common(aTHX_ (HV*)TARG, gimme,
cBOOL(PL_op->op_private & OPpPADHV_ISKEYS),
0
);
}
PP(pp_rv2av)
{
dSP; dTOPss;
const
U8 gimme = GIMME_V;
static
const
char
an_array[] =
"an ARRAY"
;
static
const
char
a_hash[] =
"a HASH"
;
const
bool
is_pp_rv2av = PL_op->op_type == OP_RV2AV
|| PL_op->op_type == OP_LVAVREF;
const
svtype type = is_pp_rv2av ? SVt_PVAV : SVt_PVHV;
SvGETMAGIC(sv);
if
(SvROK(sv)) {
if
(UNLIKELY(SvAMAGIC(sv))) {
sv = amagic_deref_call(sv, is_pp_rv2av ? to_av_amg : to_hv_amg);
}
sv = SvRV(sv);
if
(UNLIKELY(SvTYPE(sv) != type))
DIE(aTHX_
"Not %s reference"
, is_pp_rv2av ? an_array : a_hash);
else
if
(UNLIKELY(PL_op->op_flags & OPf_MOD
&& PL_op->op_private & OPpLVAL_INTRO))
Perl_croak(aTHX_
"%s"
, PL_no_localize_ref);
}
else
if
(UNLIKELY(SvTYPE(sv) != type)) {
GV *gv;
if
(!isGV_with_GP(sv)) {
gv = Perl_softref2xv(aTHX_ sv, is_pp_rv2av ? an_array : a_hash,
type, &sp);
if
(!gv)
RETURN;
}
else
{
gv = MUTABLE_GV(sv);
}
sv = is_pp_rv2av ? MUTABLE_SV(GvAVn(gv)) : MUTABLE_SV(GvHVn(gv));
if
(PL_op->op_private & OPpLVAL_INTRO)
sv = is_pp_rv2av ? MUTABLE_SV(save_ary(gv)) : MUTABLE_SV(save_hash(gv));
}
if
(PL_op->op_flags & OPf_REF) {
SETs(sv);
RETURN;
}
else
if
(UNLIKELY(PL_op->op_private & OPpMAYBE_LVSUB)) {
const
I32 flags = is_lvalue_sub();
if
(flags && !(flags & OPpENTERSUB_INARGS)) {
if
(gimme != G_LIST)
goto
croak_cant_return;
SETs(sv);
RETURN;
}
}
if
(is_pp_rv2av) {
AV *
const
av = MUTABLE_AV(sv);
if
(gimme == G_LIST) {
SP--;
PUTBACK;
return
S_pushav(aTHX_ av);
}
if
(gimme == G_SCALAR) {
const
SSize_t maxarg = AvFILL(av) + 1;
if
(PL_op->op_private & OPpTRUEBOOL)
SETs(maxarg ? &PL_sv_yes : &PL_sv_zero);
else
{
dTARGET;
SETi(maxarg);
}
}
}
else
{
SP--; PUTBACK;
return
S_padhv_rv2hv_common(aTHX_ (HV*)sv, gimme,
cBOOL(PL_op->op_private & OPpRV2HV_ISKEYS),
1
);
}
RETURN;
croak_cant_return:
Perl_croak(aTHX_
"Can't return %s to lvalue scalar context"
,
is_pp_rv2av ?
"array"
:
"hash"
);
RETURN;
}
STATIC
void
S_do_oddball(pTHX_ SV **oddkey, SV **firstkey)
{
PERL_ARGS_ASSERT_DO_ODDBALL;
if
(*oddkey) {
if
(ckWARN(WARN_MISC)) {
const
char
*err;
if
(oddkey == firstkey &&
SvROK(*oddkey) &&
(SvTYPE(SvRV(*oddkey)) == SVt_PVAV ||
SvTYPE(SvRV(*oddkey)) == SVt_PVHV))
{
err =
"Reference found where even-sized list expected"
;
}
else
err =
"Odd number of elements in hash assignment"
;
Perl_warner(aTHX_ packWARN(WARN_MISC),
"%s"
, err);
}
}
}
PERL_STATIC_INLINE
void
S_aassign_copy_common(pTHX_ SV **firstlelem, SV **lastlelem,
SV **firstrelem, SV **lastrelem
#ifdef DEBUGGING
,
bool
fake
#endif
)
{
SV **relem;
SV **lelem;
SSize_t lcount = lastlelem - firstlelem + 1;
bool
marked = FALSE;
bool
const
do_rc1 = cBOOL(PL_op->op_private & OPpASSIGN_COMMON_RC1);
bool
copy_all = FALSE;
assert
(!PL_in_clean_all);
assert
(firstlelem < lastlelem);
assert
(firstrelem < lastrelem);
lelem = firstlelem;
relem = firstrelem + 1;
for
(; relem <= lastrelem; relem++) {
SV *svr;
if
(--lcount >= 0) {
SV *svl = *lelem++;
if
(UNLIKELY(!svl)) {
assert
(lelem <= lastlelem);
svl = *lelem++;
lcount--;
}
assert
(svl);
if
(SvSMAGICAL(svl)) {
copy_all = TRUE;
}
if
(SvTYPE(svl) == SVt_PVAV || SvTYPE(svl) == SVt_PVHV) {
if
(!marked)
return
;
lcount = -1;
lelem--;
}
else
if
(!(do_rc1 && SvREFCNT(svl) == 1) && !SvIMMORTAL(svl)) {
SvFLAGS(svl) |= SVf_BREAK;
marked = TRUE;
}
else
if
(!marked) {
if
(!lcount)
break
;
continue
;
}
}
assert
(marked);
svr = *relem;
assert
(svr);
if
(UNLIKELY(SvFLAGS(svr) & (SVf_BREAK|SVs_GMG) || copy_all)) {
U32 brk = (SvFLAGS(svr) & SVf_BREAK);
#ifdef DEBUGGING
if
(fake) {
Perl_croak(aTHX_
"panic: aassign skipped needed copy of common RH elem %"
UVuf, (UV)(relem - firstrelem));
}
#endif
TAINT_NOT;
if
(UNLIKELY(SvIS_FREED(svr))) {
Perl_croak(aTHX_
"panic: attempt to copy freed scalar %p"
,
(
void
*)svr);
}
SvFLAGS(svr) &= ~SVf_BREAK;
*relem = sv_mortalcopy_flags(svr,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL);
SvFLAGS(svr) |= brk;
}
if
(!lcount)
break
;
}
if
(!marked)
return
;
while
(lelem > firstlelem) {
SV *
const
svl = *(--lelem);
if
(svl)
SvFLAGS(svl) &= ~SVf_BREAK;
}
}
PP(pp_aassign)
{
dSP;
SV **lastlelem = PL_stack_sp;
SV **lastrelem = PL_stack_base + POPMARK;
SV **firstrelem = PL_stack_base + POPMARK + 1;
SV **firstlelem = lastrelem + 1;
SV **relem;
SV **lelem;
U8 gimme;
U16 old_delaymagic = PL_delaymagic;
#ifdef DEBUGGING
bool
fake = 0;
#endif
PL_delaymagic = DM_DELAY;
if
(firstlelem < lastlelem && firstrelem < lastrelem) {
for
(relem = firstrelem+1; relem <= lastrelem; relem++) {
if
(SvGMAGICAL(*relem))
goto
do_scan;
}
for
(lelem = firstlelem; lelem <= lastlelem; lelem++) {
if
(*lelem && SvSMAGICAL(*lelem))
goto
do_scan;
}
if
( PL_op->op_private & (OPpASSIGN_COMMON_SCALAR|OPpASSIGN_COMMON_RC1) ) {
if
(PL_op->op_private & OPpASSIGN_COMMON_RC1) {
for
(lelem = firstlelem; lelem <= lastlelem; lelem++) {
SV *sv = *lelem;
if
(!sv || SvREFCNT(sv) == 1)
continue
;
if
(SvTYPE(sv) != SVt_PVAV && SvTYPE(sv) != SVt_PVAV)
goto
do_scan;
break
;
}
}
else
{
do_scan:
S_aassign_copy_common(aTHX_
firstlelem, lastlelem, firstrelem, lastrelem
#ifdef DEBUGGING
, fake
#endif
);
}
}
}
#ifdef DEBUGGING
else
{
if
(firstlelem < lastlelem && firstrelem < lastrelem) {
fake = 1;
goto
do_scan;
}
}
#endif
gimme = GIMME_V;
relem = firstrelem;
lelem = firstlelem;
if
(relem > lastrelem)
goto
no_relems;
while
(LIKELY(lelem <= lastlelem)) {
bool
alias = FALSE;
SV *lsv = *lelem++;
TAINT_NOT;
assert
(relem <= lastrelem);
if
(UNLIKELY(!lsv)) {
alias = TRUE;
lsv = *lelem++;
ASSUME(SvTYPE(lsv) == SVt_PVAV);
}
switch
(SvTYPE(lsv)) {
case
SVt_PVAV: {
SV **svp;
SSize_t i;
SSize_t tmps_base;
SSize_t nelems = lastrelem - relem + 1;
AV *ary = MUTABLE_AV(lsv);
EXTEND_MORTAL(nelems + 1);
PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(ary);
tmps_base = PL_tmps_ix + 1;
for
(i = 0; i < nelems; i++)
PL_tmps_stack[tmps_base + i] = &PL_sv_undef;
PL_tmps_ix += nelems;
if
(UNLIKELY(alias)) {
U32 lval = (gimme == G_LIST)
? (PL_op->op_flags & OPf_MOD || LVRET) : 0;
for
(svp = relem; svp <= lastrelem; svp++) {
SV *rsv = *svp;
SvGETMAGIC(rsv);
if
(!SvROK(rsv))
DIE(aTHX_
"Assigned value is not a reference"
);
if
(SvTYPE(SvRV(rsv)) > SVt_PVLV)
DIE(aTHX_
"Assigned value is not a SCALAR reference"
);
if
(lval)
*svp = rsv = sv_mortalcopy(rsv);
rsv = SvREFCNT_inc_NN(SvRV(rsv));
assert
(tmps_base <= PL_tmps_max);
PL_tmps_stack[tmps_base++] = rsv;
}
}
else
{
for
(svp = relem; svp <= lastrelem; svp++) {
SV *rsv = *svp;
if
(SvTEMP(rsv) && !SvGMAGICAL(rsv) && SvREFCNT(rsv) == 1) {
SvREFCNT_inc_simple_void_NN(rsv);
SvTEMP_off(rsv);
}
else
{
SV *nsv;
nsv = newSVsv_flags(rsv,
(SV_DO_COW_SVSETSV|SV_NOSTEAL|SV_GMAGIC));
rsv = *svp = nsv;
}
assert
(tmps_base <= PL_tmps_max);
PL_tmps_stack[tmps_base++] = rsv;
}
}
if
(SvRMAGICAL(ary) || AvFILLp(ary) >= 0)
av_clear(ary);
tmps_base -= nelems;
if
(SvMAGICAL(ary) || SvREADONLY(ary) || !AvREAL(ary)) {
av_extend(ary, nelems - 1);
for
(i = 0; i < nelems; i++) {
SV **svp = &(PL_tmps_stack[tmps_base + i]);
SV *rsv = *svp;
if
(av_store(ary, i, rsv))
*svp = &PL_sv_undef;
;
SvSETMAGIC(rsv);
}
PL_tmps_stack[tmps_base - 1] = &PL_sv_undef;
}
else
{
SSize_t fill = nelems - 1;
if
(fill > AvMAX(ary))
av_extend_guts(ary, fill, &AvMAX(ary), &AvALLOC(ary),
&AvARRAY(ary));
AvFILLp(ary) = fill;
Copy(&(PL_tmps_stack[tmps_base]), AvARRAY(ary), nelems, SV*);
if
(UNLIKELY(PL_tmps_ix >= tmps_base + nelems))
Move(&PL_tmps_stack[tmps_base + nelems],
&PL_tmps_stack[tmps_base - 1],
PL_tmps_ix - (tmps_base + nelems) + 1,
SV*);
PL_tmps_ix -= (nelems + 1);
}
if
(UNLIKELY(PL_delaymagic & DM_ARRAY_ISA))
SvSETMAGIC(MUTABLE_SV(ary));
SvREFCNT_dec_NN(ary);
relem = lastrelem + 1;
goto
no_relems;
}
case
SVt_PVHV: {
SV **svp;
bool
dirty_tmps;
SSize_t i;
SSize_t tmps_base;
SSize_t nelems = lastrelem - relem + 1;
HV *hash = MUTABLE_HV(lsv);
if
(UNLIKELY(nelems & 1)) {
do_oddball(lastrelem, relem);
*++lastrelem = &PL_sv_undef;
nelems++;
}
EXTEND_MORTAL(nelems + 1);
nelems >>= 1;
PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(hash);
tmps_base = PL_tmps_ix + 1;
for
(i = 0; i < nelems; i++)
PL_tmps_stack[tmps_base + i] = &PL_sv_undef;
PL_tmps_ix += nelems;
for
(svp = relem + 1; svp <= lastrelem; svp += 2) {
SV *rsv = *svp;
if
(SvTEMP(rsv) && !SvGMAGICAL(rsv) && SvREFCNT(rsv) == 1) {
SvREFCNT_inc_simple_void_NN(rsv);
SvTEMP_off(rsv);
}
else
{
SV *nsv;
nsv = newSVsv_flags(rsv,
(SV_DO_COW_SVSETSV|SV_NOSTEAL|SV_GMAGIC));
rsv = *svp = nsv;
}
assert
(tmps_base <= PL_tmps_max);
PL_tmps_stack[tmps_base++] = rsv;
}
tmps_base -= nelems;
if
(UNLIKELY(gimme == G_LIST)) {
EXTEND_MORTAL(nelems);
for
(svp = relem; svp <= lastrelem; svp += 2)
*svp = sv_mortalcopy_flags(*svp,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL);
}
else
if
(PL_op->op_private & OPpASSIGN_COMMON_AGG) {
EXTEND_MORTAL(nelems);
for
(svp = relem; svp <= lastrelem; svp += 2) {
SV *rsv = *svp;
if
(UNLIKELY(SvGMAGICAL(rsv))) {
SSize_t n;
*svp = sv_mortalcopy_flags(*svp,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL);
n = (lastrelem - relem) >> 1;
EXTEND_MORTAL(n);
}
else
PL_tmps_stack[++PL_tmps_ix] =
SvREFCNT_inc_simple_NN(rsv);
}
}
if
(SvRMAGICAL(hash) || HvUSEDKEYS(hash))
hv_clear(hash);
if
(nelems > PERL_HASH_DEFAULT_HvMAX) {
hv_ksplit(hash, nelems);
}
dirty_tmps = FALSE;
if
(UNLIKELY(gimme == G_LIST)) {
SV **svp;
SV **topelem = relem;
for
(i = 0, svp = relem; svp <= lastrelem; i++, svp++) {
SV *key = *svp++;
SV *val = *svp;
if
(!hv_exists_ent(hash, key, 0)) {
*topelem = key;
topelem += 2;
}
if
(hv_store_ent(hash, key, val, 0))
PL_tmps_stack[tmps_base + i] = &PL_sv_undef;
else
dirty_tmps = TRUE;
;
SvSETMAGIC(val);
}
if
(topelem < svp) {
lastrelem = topelem - 1;
while
(relem < lastrelem) {
HE *he;
he = hv_fetch_ent(hash, *relem++, 0, 0);
*relem++ = (he ? HeVAL(he) : &PL_sv_undef);
}
}
}
else
{
SV **svp;
for
(i = 0, svp = relem; svp <= lastrelem; i++, svp++) {
SV *key = *svp++;
SV *val = *svp;
if
(hv_store_ent(hash, key, val, 0))
PL_tmps_stack[tmps_base + i] = &PL_sv_undef;
else
dirty_tmps = TRUE;
;
SvSETMAGIC(val);
}
}
if
(dirty_tmps) {
PL_tmps_stack[tmps_base - 1] = &PL_sv_undef;
}
else
{
if
(UNLIKELY(PL_tmps_ix >= tmps_base + nelems))
Move(&PL_tmps_stack[tmps_base + nelems],
&PL_tmps_stack[tmps_base - 1],
PL_tmps_ix - (tmps_base + nelems) + 1,
SV*);
PL_tmps_ix -= (nelems + 1);
}
SvREFCNT_dec_NN(hash);
relem = lastrelem + 1;
goto
no_relems;
}
default
:
if
(!SvIMMORTAL(lsv)) {
SV *ref;
if
(UNLIKELY(
SvTEMP(lsv) && !SvSMAGICAL(lsv) && SvREFCNT(lsv) == 1 &&
(!isGV_with_GP(lsv) || SvFAKE(lsv)) && ckWARN(WARN_MISC)
))
Perl_warner(aTHX_
packWARN(WARN_MISC),
"Useless assignment to a temporary"
);
if
( SvROK(lsv)
&& ( ((ref = SvRV(lsv)), SvREFCNT(ref)) == 1)
&& lelem <= lastlelem
) {
SSize_t ix;
SvREFCNT_inc_simple_void_NN(ref);
ix = ++PL_tmps_ix;
if
(UNLIKELY(ix >= PL_tmps_max))
(
void
)tmps_grow_p(ix + (lastlelem - lelem));
PL_tmps_stack[ix] = ref;
}
sv_setsv(lsv, *relem);
*relem = lsv;
SvSETMAGIC(lsv);
}
if
(++relem > lastrelem)
goto
no_relems;
break
;
}
}
no_relems:
while
(LIKELY(lelem <= lastlelem)) {
SV *lsv = *lelem++;
TAINT_NOT;
if
(UNLIKELY(!lsv)) {
lsv = *lelem++;
ASSUME(SvTYPE(lsv) == SVt_PVAV);
}
switch
(SvTYPE(lsv)) {
case
SVt_PVAV:
if
(SvRMAGICAL(lsv) || AvFILLp((SV*)lsv) >= 0) {
av_clear((AV*)lsv);
if
(UNLIKELY(PL_delaymagic & DM_ARRAY_ISA))
SvSETMAGIC(lsv);
}
break
;
case
SVt_PVHV:
if
(SvRMAGICAL(lsv) || HvUSEDKEYS((HV*)lsv))
hv_clear((HV*)lsv);
break
;
default
:
if
(!SvIMMORTAL(lsv)) {
sv_set_undef(lsv);
SvSETMAGIC(lsv);
}
*relem++ = lsv;
break
;
}
}
TAINT_NOT;
if
(UNLIKELY(PL_delaymagic & ~DM_DELAY)) {
Uid_t tmp_uid = PerlProc_getuid();
Uid_t tmp_euid = PerlProc_geteuid();
Gid_t tmp_gid = PerlProc_getgid();
Gid_t tmp_egid = PerlProc_getegid();
if
(PL_delaymagic & DM_UID) {
#ifdef HAS_SETRESUID
PERL_UNUSED_RESULT(
setresuid((PL_delaymagic & DM_RUID) ? PL_delaymagic_uid : (Uid_t)-1,
(PL_delaymagic & DM_EUID) ? PL_delaymagic_euid : (Uid_t)-1,
(Uid_t)-1));
#elif defined(HAS_SETREUID)
PERL_UNUSED_RESULT(
setreuid((PL_delaymagic & DM_RUID) ? PL_delaymagic_uid : (Uid_t)-1,
(PL_delaymagic & DM_EUID) ? PL_delaymagic_euid : (Uid_t)-1));
#else
# ifdef HAS_SETRUID
if
((PL_delaymagic & DM_UID) == DM_RUID) {
PERL_UNUSED_RESULT(setruid(PL_delaymagic_uid));
PL_delaymagic &= ~DM_RUID;
}
# endif /* HAS_SETRUID */
# ifdef HAS_SETEUID
if
((PL_delaymagic & DM_UID) == DM_EUID) {
PERL_UNUSED_RESULT(seteuid(PL_delaymagic_euid));
PL_delaymagic &= ~DM_EUID;
}
# endif /* HAS_SETEUID */
if
(PL_delaymagic & DM_UID) {
if
(PL_delaymagic_uid != PL_delaymagic_euid)
DIE(aTHX_
"No setreuid available"
);
PERL_UNUSED_RESULT(PerlProc_setuid(PL_delaymagic_uid));
}
#endif /* HAS_SETRESUID */
tmp_uid = PerlProc_getuid();
tmp_euid = PerlProc_geteuid();
}
if
(PL_delaymagic & DM_GID) {
#ifdef HAS_SETRESGID
PERL_UNUSED_RESULT(
setresgid((PL_delaymagic & DM_RGID) ? PL_delaymagic_gid : (Gid_t)-1,
(PL_delaymagic & DM_EGID) ? PL_delaymagic_egid : (Gid_t)-1,
(Gid_t)-1));
#elif defined(HAS_SETREGID)
PERL_UNUSED_RESULT(
setregid((PL_delaymagic & DM_RGID) ? PL_delaymagic_gid : (Gid_t)-1,
(PL_delaymagic & DM_EGID) ? PL_delaymagic_egid : (Gid_t)-1));
#else
# ifdef HAS_SETRGID
if
((PL_delaymagic & DM_GID) == DM_RGID) {
PERL_UNUSED_RESULT(setrgid(PL_delaymagic_gid));
PL_delaymagic &= ~DM_RGID;
}
# endif /* HAS_SETRGID */
# ifdef HAS_SETEGID
if
((PL_delaymagic & DM_GID) == DM_EGID) {
PERL_UNUSED_RESULT(setegid(PL_delaymagic_egid));
PL_delaymagic &= ~DM_EGID;
}
# endif /* HAS_SETEGID */
if
(PL_delaymagic & DM_GID) {
if
(PL_delaymagic_gid != PL_delaymagic_egid)
DIE(aTHX_
"No setregid available"
);
PERL_UNUSED_RESULT(PerlProc_setgid(PL_delaymagic_gid));
}
#endif /* HAS_SETRESGID */
tmp_gid = PerlProc_getgid();
tmp_egid = PerlProc_getegid();
}
TAINTING_set( TAINTING_get | (tmp_uid && (tmp_euid != tmp_uid || tmp_egid != tmp_gid)) );
#ifdef NO_TAINT_SUPPORT
PERL_UNUSED_VAR(tmp_uid);
PERL_UNUSED_VAR(tmp_euid);
PERL_UNUSED_VAR(tmp_gid);
PERL_UNUSED_VAR(tmp_egid);
#endif
}
PL_delaymagic = old_delaymagic;
if
(gimme == G_VOID)
SP = firstrelem - 1;
else
if
(gimme == G_SCALAR) {
SP = firstrelem;
EXTEND(SP,1);
if
(PL_op->op_private & OPpASSIGN_TRUEBOOL)
SETs((firstlelem - firstrelem) ? &PL_sv_yes : &PL_sv_zero);
else
{
dTARGET;
SETi(firstlelem - firstrelem);
}
}
else
SP = relem - 1;
RETURN;
}
PP(pp_qr)
{
dSP;
PMOP *
const
pm = cPMOP;
REGEXP * rx = PM_GETRE(pm);
regexp *prog = ReANY(rx);
SV *
const
pkg = RXp_ENGINE(prog)->qr_package(aTHX_ (rx));
SV *
const
rv = newSV_type_mortal(SVt_IV);
CV **cvp;
CV *cv;
SvUPGRADE(rv, SVt_IV);
SvRV_set(rv, MUTABLE_SV(reg_temp_copy(NULL, rx)));
SvROK_on(rv);
cvp = &( ReANY((REGEXP *)SvRV(rv))->qr_anoncv);
if
(UNLIKELY((cv = *cvp) && CvCLONE(*cvp))) {
*cvp = cv_clone(cv);
SvREFCNT_dec_NN(cv);
}
if
(pkg) {
HV *
const
stash = gv_stashsv(pkg, GV_ADD);
SvREFCNT_dec_NN(pkg);
(
void
)sv_bless(rv, stash);
}
if
(UNLIKELY(RXp_ISTAINTED(prog))) {
SvTAINTED_on(rv);
SvTAINTED_on(SvRV(rv));
}
XPUSHs(rv);
RETURN;
}
STATIC
bool
S_are_we_in_Debug_EXECUTE_r(pTHX)
{
DECLARE_AND_GET_RE_DEBUG_FLAGS_NON_REGEX;
return
cBOOL(RE_DEBUG_FLAG(RE_DEBUG_EXECUTE_MASK));
}
PERL_STATIC_INLINE
bool
S_should_we_output_Debug_r(pTHX_ regexp *prog)
{
PERL_ARGS_ASSERT_SHOULD_WE_OUTPUT_DEBUG_R;
if
(UNLIKELY(DEBUG_r_TEST)) {
return
TRUE;
}
if
( LIKELY(prog->engine->exec == &Perl_regexec_flags)
|| UNLIKELY(prog->engine->op_comp == NULL))
{
return
FALSE;
}
return
S_are_we_in_Debug_EXECUTE_r(aTHX);
}
PP(pp_match)
{
dSP; dTARG;
PMOP *pm = cPMOP;
PMOP *dynpm = pm;
const
char
*s;
const
char
*strend;
SSize_t curpos = 0;
I32 global;
U8 r_flags = 0;
const
char
*truebase;
REGEXP *rx = PM_GETRE(pm);
regexp *prog = ReANY(rx);
bool
rxtainted;
const
U8 gimme = GIMME_V;
STRLEN len;
const
I32 oldsave = PL_savestack_ix;
I32 had_zerolen = 0;
MAGIC *mg = NULL;
if
(PL_op->op_flags & OPf_STACKED)
TARG = POPs;
else
{
if
(ARGTARG)
GETTARGET;
else
{
TARG = DEFSV;
}
EXTEND(SP,1);
}
PUTBACK;
truebase = prog->mother_re
? SvPV_nomg_const(TARG, len)
: SvPV_const(TARG, len);
if
(!truebase)
DIE(aTHX_
"panic: pp_match"
);
strend = truebase + len;
rxtainted = (RXp_ISTAINTED(prog) ||
(TAINT_get && (pm->op_pmflags & PMf_RETAINT)));
TAINT_NOT;
global = dynpm->op_pmflags & PMf_GLOBAL;
if
(
#ifdef USE_ITHREADS
SvREADONLY(PL_regex_pad[pm->op_pmoffset])
#else
pm->op_pmflags & PMf_USED
#endif
) {
if
(UNLIKELY(should_we_output_Debug_r(prog))) {
PerlIO_printf(Perl_debug_log,
"?? already matched once"
);
}
goto
nope;
}
if
(!RX_PRELEN(rx) && PL_curpm && !prog->mother_re) {
if
(PL_curpm == PL_reg_curpm) {
if
(PL_curpm_under) {
if
(PL_curpm_under == PL_reg_curpm) {
Perl_croak(aTHX_
"Infinite recursion via empty pattern"
);
}
else
{
pm = PL_curpm_under;
}
}
}
else
{
pm = PL_curpm;
}
rx = PM_GETRE(pm);
prog = ReANY(rx);
}
if
(RXp_MINLEN(prog) >= 0 && (STRLEN)RXp_MINLEN(prog) > len) {
if
(UNLIKELY(should_we_output_Debug_r(prog))) {
PerlIO_printf(Perl_debug_log,
"String shorter than min possible regex match (%zd < %zd)\n"
,
len, RXp_MINLEN(prog));
}
goto
nope;
}
if
(global) {
mg = mg_find_mglob(TARG);
if
(mg && mg->mg_len >= 0) {
curpos = MgBYTEPOS(mg, TARG, truebase, len);
if
(mg->mg_flags & MGf_MINMATCH)
had_zerolen = 1;
}
}
#ifdef PERL_SAWAMPERSAND
if
( RXp_NPARENS(prog)
|| PL_sawampersand
|| (RXp_EXTFLAGS(prog) & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY))
|| (dynpm->op_pmflags & PMf_KEEPCOPY)
)
#endif
{
r_flags |= (REXEC_COPY_STR|REXEC_COPY_SKIP_PRE);
if
(! (global && gimme == G_LIST))
r_flags |= REXEC_COPY_SKIP_POST;
};
#ifdef PERL_SAWAMPERSAND
if
(dynpm->op_pmflags & PMf_KEEPCOPY)
r_flags &= ~(REXEC_COPY_SKIP_PRE|REXEC_COPY_SKIP_POST);
#endif
s = truebase;
play_it_again:
if
(global)
s = truebase + curpos;
if
(!CALLREGEXEC(rx, (
char
*)s, (
char
*)strend, (
char
*)truebase,
had_zerolen, TARG, NULL, r_flags))
goto
nope;
PL_curpm = pm;
if
(dynpm->op_pmflags & PMf_ONCE)
#ifdef USE_ITHREADS
SvREADONLY_on(PL_regex_pad[dynpm->op_pmoffset]);
#else
dynpm->op_pmflags |= PMf_USED;
#endif
if
(rxtainted)
RXp_MATCH_TAINTED_on(prog);
TAINT_IF(RXp_MATCH_TAINTED(prog));
if
(global && (gimme != G_LIST || (dynpm->op_pmflags & PMf_CONTINUE))) {
if
(!mg)
mg = sv_magicext_mglob(TARG);
MgBYTEPOS_set(mg, TARG, truebase, RXp_OFFS(prog)[0].end);
if
(RXp_ZERO_LEN(prog))
mg->mg_flags |= MGf_MINMATCH;
else
mg->mg_flags &= ~MGf_MINMATCH;
}
if
((!RXp_NPARENS(prog) && !global) || gimme != G_LIST) {
LEAVE_SCOPE(oldsave);
RETPUSHYES;
}
{
const
I32 nparens = RXp_NPARENS(prog);
I32 i = (global && !nparens) ? 1 : 0;
SPAGAIN;
EXTEND(SP, nparens + i);
EXTEND_MORTAL(nparens + i);
for
(i = !i; i <= nparens; i++) {
if
(LIKELY((RXp_OFFS(prog)[i].start != -1)
&& RXp_OFFS(prog)[i].end != -1 ))
{
const
I32 len = RXp_OFFS(prog)[i].end - RXp_OFFS(prog)[i].start;
const
char
*
const
s = RXp_OFFS(prog)[i].start + truebase;
if
(UNLIKELY( RXp_OFFS(prog)[i].end < 0
|| RXp_OFFS(prog)[i].start < 0
|| len < 0
|| len > strend - s)
)
DIE(aTHX_
"panic: pp_match start/end pointers, i=%ld, "
"start=%ld, end=%ld, s=%p, strend=%p, len=%"
UVuf,
(
long
) i, (
long
) RXp_OFFS(prog)[i].start,
(
long
)RXp_OFFS(prog)[i].end, s, strend, (UV) len);
PUSHs(newSVpvn_flags(s, len,
(DO_UTF8(TARG))
? SVf_UTF8|SVs_TEMP
: SVs_TEMP)
);
}
else
{
PUSHs(sv_newmortal());
}
}
if
(global) {
curpos = (UV)RXp_OFFS(prog)[0].end;
had_zerolen = RXp_ZERO_LEN(prog);
PUTBACK;
r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
goto
play_it_again;
}
LEAVE_SCOPE(oldsave);
RETURN;
}
NOT_REACHED;
nope:
if
(global && !(dynpm->op_pmflags & PMf_CONTINUE)) {
if
(!mg)
mg = mg_find_mglob(TARG);
if
(mg)
mg->mg_len = -1;
}
LEAVE_SCOPE(oldsave);
if
(gimme == G_LIST)
RETURN;
RETPUSHNO;
}
OP *
Perl_do_readline(pTHX)
{
dSP; dTARGETSTACKED;
SV *sv;
STRLEN tmplen = 0;
STRLEN offset;
PerlIO *fp;
IO *
const
io = GvIO(PL_last_in_gv);
const
I32 type = PL_op->op_type;
const
U8 gimme = GIMME_V;
if
(io) {
const
MAGIC *
const
mg = SvTIED_mg((
const
SV *)io, PERL_MAGIC_tiedscalar);
if
(mg) {
Perl_tied_method(aTHX_ SV_CONST(READLINE), SP, MUTABLE_SV(io), mg, gimme, 0);
if
(gimme == G_SCALAR) {
SPAGAIN;
SvSetSV_nosteal(TARG, TOPs);
SETTARG;
}
return
NORMAL;
}
}
fp = NULL;
if
(io) {
fp = IoIFP(io);
if
(!fp) {
if
(IoFLAGS(io) & IOf_ARGV) {
if
(IoFLAGS(io) & IOf_START) {
IoLINES(io) = 0;
if
(av_count(GvAVn(PL_last_in_gv)) == 0) {
IoFLAGS(io) &= ~IOf_START;
do_open6(PL_last_in_gv,
"-"
, 1, NULL, NULL, 0);
SvTAINTED_off(GvSVn(PL_last_in_gv));
sv_setpvs(GvSVn(PL_last_in_gv),
"-"
);
SvSETMAGIC(GvSV(PL_last_in_gv));
fp = IoIFP(io);
goto
have_fp;
}
}
fp = nextargv(PL_last_in_gv, PL_op->op_flags & OPf_SPECIAL);
if
(!fp) {
(
void
)do_close(PL_last_in_gv, FALSE);
}
}
else
if
(type == OP_GLOB)
fp = Perl_start_glob(aTHX_ POPs, io);
}
else
if
(type == OP_GLOB)
SP--;
else
if
(IoTYPE(io) == IoTYPE_WRONLY) {
report_wrongway_fh(PL_last_in_gv,
'>'
);
}
}
if
(!fp) {
if
((!io || !(IoFLAGS(io) & IOf_START))
&& ckWARN(WARN_CLOSED)
&& type != OP_GLOB)
{
report_evil_fh(PL_last_in_gv);
}
if
(gimme == G_SCALAR) {
if
(type != OP_RCATLINE) {
sv_set_undef(TARG);
}
PUSHTARG;
}
RETURN;
}
have_fp:
if
(gimme == G_SCALAR) {
sv = TARG;
if
(type == OP_RCATLINE && SvGMAGICAL(sv))
mg_get(sv);
if
(SvROK(sv)) {
if
(type == OP_RCATLINE)
SvPV_force_nomg_nolen(sv);
else
sv_unref(sv);
}
else
if
(isGV_with_GP(sv)) {
SvPV_force_nomg_nolen(sv);
}
SvUPGRADE(sv, SVt_PV);
tmplen = SvLEN(sv);
if
(!tmplen && !SvREADONLY(sv) && !SvIsCOW(sv)) {
Sv_Grow(sv, 80);
}
offset = 0;
if
(type == OP_RCATLINE && SvOK(sv)) {
if
(!SvPOK(sv)) {
SvPV_force_nomg_nolen(sv);
}
offset = SvCUR(sv);
}
}
else
{
sv = sv_2mortal(newSV(80));
offset = 0;
}
#define MAYBE_TAINT_LINE(io, sv) \
if
(!(IoFLAGS(io) & IOf_UNTAINT)) { \
TAINT; \
SvTAINTED_on(sv); \
}
#define SNARF_EOF(gimme,rs,io,sv) \
(gimme != G_SCALAR || SvCUR(sv) \
|| (IoFLAGS(io) & IOf_NOLINE) || !RsSNARF(rs))
for
(;;) {
PUTBACK;
if
(!sv_gets(sv, fp, offset)
&& (type == OP_GLOB
|| SNARF_EOF(gimme, PL_rs, io, sv)
|| PerlIO_error(fp)))
{
PerlIO_clearerr(fp);
if
(IoFLAGS(io) & IOf_ARGV) {
fp = nextargv(PL_last_in_gv, PL_op->op_flags & OPf_SPECIAL);
if
(fp)
continue
;
(
void
)do_close(PL_last_in_gv, FALSE);
}
else
if
(type == OP_GLOB) {
if
(!do_close(PL_last_in_gv, FALSE)) {
Perl_ck_warner(aTHX_ packWARN(WARN_GLOB),
"glob failed (child exited with status %d%s)"
,
(
int
)(STATUS_CURRENT >> 8),
(STATUS_CURRENT & 0x80) ?
", core dumped"
:
""
);
}
}
if
(gimme == G_SCALAR) {
if
(type != OP_RCATLINE) {
SV_CHECK_THINKFIRST_COW_DROP(TARG);
SvOK_off(TARG);
}
SPAGAIN;
PUSHTARG;
}
MAYBE_TAINT_LINE(io, sv);
RETURN;
}
MAYBE_TAINT_LINE(io, sv);
IoLINES(io)++;
IoFLAGS(io) |= IOf_NOLINE;
SvSETMAGIC(sv);
SPAGAIN;
XPUSHs(sv);
if
(type == OP_GLOB) {
const
char
*t1;
Stat_t statbuf;
if
(SvCUR(sv) > 0 && SvCUR(PL_rs) > 0) {
char
*
const
tmps = SvEND(sv) - 1;
if
(*tmps == *SvPVX_const(PL_rs)) {
*tmps =
'\0'
;
SvCUR_set(sv, SvCUR(sv) - 1);
}
}
for
(t1 = SvPVX_const(sv); *t1; t1++)
#ifdef __VMS
if
(memCHRs(
"*%?"
, *t1))
#else
if
(memCHRs(
"$&*(){}[]'\";\\|?<>~`"
, *t1))
#endif
break
;
if
(*t1 && PerlLIO_lstat(SvPVX_const(sv), &statbuf) < 0) {
(
void
)POPs;
continue
;
}
}
else
if
(SvUTF8(sv)) {
if
(ckWARN(WARN_UTF8)) {
const
U8 *
const
s = (
const
U8*)SvPVX_const(sv) + offset;
const
STRLEN len = SvCUR(sv) - offset;
const
U8 *f;
if
(!is_utf8_string_loc(s, len, &f))
Perl_warner(aTHX_ packWARN(WARN_UTF8),
"utf8 \"\\x%02X\" does not map to Unicode"
,
f < (U8*)SvEND(sv) ? *f : 0);
}
}
if
(gimme == G_LIST) {
if
(SvLEN(sv) - SvCUR(sv) > 20) {
SvPV_shrink_to_cur(sv);
}
sv = sv_2mortal(newSV(80));
continue
;
}
else
if
(gimme == G_SCALAR && !tmplen && SvLEN(sv) - SvCUR(sv) > 80) {
const
STRLEN new_len
= SvCUR(sv) < 60 ? 80 : SvCUR(sv)+40;
SvPV_renew(sv, new_len);
}
RETURN;
}
}
PP(pp_helem)
{
dSP;
HE* he;
SV **svp;
SV *
const
keysv = POPs;
HV *
const
hv = MUTABLE_HV(POPs);
const
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
const
U32 defer = PL_op->op_private & OPpLVAL_DEFER;
SV *sv;
const
bool
localizing = PL_op->op_private & OPpLVAL_INTRO;
bool
preeminent = TRUE;
if
(SvTYPE(hv) != SVt_PVHV)
RETPUSHUNDEF;
if
(localizing) {
MAGIC *mg;
HV *stash;
if
(SvCANEXISTDELETE(hv))
preeminent = hv_exists_ent(hv, keysv, 0);
}
he = hv_fetch_ent(hv, keysv, lval && !defer, 0);
svp = he ? &HeVAL(he) : NULL;
if
(lval) {
if
(!svp || !*svp || *svp == &PL_sv_undef) {
SV* lv;
SV* key2;
if
(!defer) {
DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
}
lv = newSV_type_mortal(SVt_PVLV);
LvTYPE(lv) =
'y'
;
sv_magic(lv, key2 = newSVsv(keysv), PERL_MAGIC_defelem, NULL, 0);
SvREFCNT_dec_NN(key2);
LvTARG(lv) = SvREFCNT_inc_simple_NN(hv);
LvTARGLEN(lv) = 1;
PUSHs(lv);
RETURN;
}
if
(localizing) {
if
(HvNAME_get(hv) && isGV_or_RVCV(*svp))
save_gp(MUTABLE_GV(*svp), !(PL_op->op_flags & OPf_SPECIAL));
else
if
(preeminent)
save_helem_flags(hv, keysv, svp,
(PL_op->op_flags & OPf_SPECIAL) ? 0 : SAVEf_SETMAGIC);
else
SAVEHDELETE(hv, keysv);
}
else
if
(PL_op->op_private & OPpDEREF) {
PUSHs(vivify_ref(*svp, PL_op->op_private & OPpDEREF));
RETURN;
}
}
sv = (svp && *svp ? *svp : &PL_sv_undef);
if
(!lval && SvRMAGICAL(hv) && SvGMAGICAL(sv))
mg_get(sv);
PUSHs(sv);
RETURN;
}
STATIC GV *
S_softref2xv_lite(pTHX_ SV *
const
sv,
const
char
*
const
what,
const
svtype type)
{
if
(PL_op->op_private & HINT_STRICT_REFS) {
if
(SvOK(sv))
Perl_die(aTHX_ PL_no_symref_sv, sv,
(SvPOKp(sv) && SvCUR(sv)>32 ?
"..."
:
""
), what);
else
Perl_die(aTHX_ PL_no_usym, what);
}
if
(!SvOK(sv))
Perl_die(aTHX_ PL_no_usym, what);
return
gv_fetchsv_nomg(sv, GV_ADD, type);
}
PP(pp_multideref)
{
SV *sv = NULL;
UNOP_AUX_item *items = cUNOP_AUXx(PL_op)->op_aux;
UV actions = items->uv;
assert
(actions);
PL_multideref_pc = items;
while
(1) {
switch
(actions & MDEREF_ACTION_MASK) {
case
MDEREF_reload:
actions = (++items)->uv;
continue
;
case
MDEREF_AV_padav_aelem:
sv = PAD_SVl((++items)->pad_offset);
goto
do_AV_aelem;
case
MDEREF_AV_gvav_aelem:
sv = UNOP_AUX_item_sv(++items);
assert
(isGV_with_GP(sv));
sv = (SV*)GvAVn((GV*)sv);
goto
do_AV_aelem;
case
MDEREF_AV_pop_rv2av_aelem:
{
dSP;
sv = POPs;
PUTBACK;
goto
do_AV_rv2av_aelem;
}
case
MDEREF_AV_gvsv_vivify_rv2av_aelem:
sv = UNOP_AUX_item_sv(++items);
assert
(isGV_with_GP(sv));
sv = GvSVn((GV*)sv);
goto
do_AV_vivify_rv2av_aelem;
case
MDEREF_AV_padsv_vivify_rv2av_aelem:
sv = PAD_SVl((++items)->pad_offset);
do_AV_vivify_rv2av_aelem:
case
MDEREF_AV_vivify_rv2av_aelem:
sv = vivify_ref(sv, OPpDEREF_AV);
do_AV_rv2av_aelem:
SvGETMAGIC(sv);
if
(LIKELY(SvROK(sv))) {
if
(UNLIKELY(SvAMAGIC(sv))) {
sv = amagic_deref_call(sv, to_av_amg);
}
sv = SvRV(sv);
if
(UNLIKELY(SvTYPE(sv) != SVt_PVAV))
DIE(aTHX_
"Not an ARRAY reference"
);
}
else
if
(SvTYPE(sv) != SVt_PVAV) {
if
(!isGV_with_GP(sv))
sv = (SV*)S_softref2xv_lite(aTHX_ sv,
"an ARRAY"
, SVt_PVAV);
sv = MUTABLE_SV(GvAVn((GV*)sv));
}
do_AV_aelem:
{
SV *elemsv;
IV elem = 0;
assert
(SvTYPE(sv) == SVt_PVAV);
switch
(actions & MDEREF_INDEX_MASK) {
case
MDEREF_INDEX_none:
goto
finish;
case
MDEREF_INDEX_const:
elem = (++items)->iv;
break
;
case
MDEREF_INDEX_padsv:
elemsv = PAD_SVl((++items)->pad_offset);
goto
check_elem;
case
MDEREF_INDEX_gvsv:
elemsv = UNOP_AUX_item_sv(++items);
assert
(isGV_with_GP(elemsv));
elemsv = GvSVn((GV*)elemsv);
check_elem:
if
(UNLIKELY(SvROK(elemsv) && !SvGAMAGIC(elemsv)
&& ckWARN(WARN_MISC)))
Perl_warner(aTHX_ packWARN(WARN_MISC),
"Use of reference \"%"
SVf
"\" as array index"
,
SVfARG(elemsv));
PL_multideref_pc = items;
elem = SvIV(elemsv);
break
;
}
if
(!(actions & MDEREF_FLAG_last)) {
SV** svp = av_fetch((AV*)sv, elem, 1);
if
(!svp || ! (sv=*svp))
DIE(aTHX_ PL_no_aelem, elem);
break
;
}
if
(PL_op->op_private &
(OPpMULTIDEREF_EXISTS|OPpMULTIDEREF_DELETE))
{
if
(PL_op->op_private & OPpMULTIDEREF_EXISTS) {
sv = av_exists((AV*)sv, elem) ? &PL_sv_yes : &PL_sv_no;
}
else
{
I32 discard = (GIMME_V == G_VOID) ? G_DISCARD : 0;
sv = av_delete((AV*)sv, elem, discard);
if
(discard)
return
NORMAL;
if
(!sv)
sv = &PL_sv_undef;
}
}
else
{
const
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
const
U32 defer = PL_op->op_private & OPpLVAL_DEFER;
const
bool
localizing = PL_op->op_private & OPpLVAL_INTRO;
bool
preeminent = TRUE;
AV *
const
av = (AV*)sv;
SV** svp;
if
(UNLIKELY(localizing)) {
MAGIC *mg;
HV *stash;
if
(SvCANEXISTDELETE(av))
preeminent = av_exists(av, elem);
}
svp = av_fetch(av, elem, lval && !defer);
if
(lval) {
if
(!svp || !(sv = *svp)) {
IV len;
if
(!defer)
DIE(aTHX_ PL_no_aelem, elem);
len = av_top_index(av);
if
(elem < 0 && len + elem >= 0)
elem = len + elem;
if
(elem >= 0 && elem <= len)
sv = av_nonelem(av,elem);
else
sv = sv_2mortal(newSVavdefelem(av,elem,1));
}
else
{
if
(UNLIKELY(localizing)) {
if
(preeminent) {
save_aelem(av, elem, svp);
sv = *svp;
}
else
SAVEADELETE(av, elem);
}
}
}
else
{
sv = (svp ? *svp : &PL_sv_undef);
if
(SvRMAGICAL(av) && SvGMAGICAL(sv))
mg_get(sv);
}
}
}
finish:
{
dSP;
XPUSHs(sv);
RETURN;
}
case
MDEREF_HV_padhv_helem:
sv = PAD_SVl((++items)->pad_offset);
goto
do_HV_helem;
case
MDEREF_HV_gvhv_helem:
sv = UNOP_AUX_item_sv(++items);
assert
(isGV_with_GP(sv));
sv = (SV*)GvHVn((GV*)sv);
goto
do_HV_helem;
case
MDEREF_HV_pop_rv2hv_helem:
{
dSP;
sv = POPs;
PUTBACK;
goto
do_HV_rv2hv_helem;
}
case
MDEREF_HV_gvsv_vivify_rv2hv_helem:
sv = UNOP_AUX_item_sv(++items);
assert
(isGV_with_GP(sv));
sv = GvSVn((GV*)sv);
goto
do_HV_vivify_rv2hv_helem;
case
MDEREF_HV_padsv_vivify_rv2hv_helem:
sv = PAD_SVl((++items)->pad_offset);
do_HV_vivify_rv2hv_helem:
case
MDEREF_HV_vivify_rv2hv_helem:
sv = vivify_ref(sv, OPpDEREF_HV);
do_HV_rv2hv_helem:
SvGETMAGIC(sv);
if
(LIKELY(SvROK(sv))) {
if
(UNLIKELY(SvAMAGIC(sv))) {
sv = amagic_deref_call(sv, to_hv_amg);
}
sv = SvRV(sv);
if
(UNLIKELY(SvTYPE(sv) != SVt_PVHV))
DIE(aTHX_
"Not a HASH reference"
);
}
else
if
(SvTYPE(sv) != SVt_PVHV) {
if
(!isGV_with_GP(sv))
sv = (SV*)S_softref2xv_lite(aTHX_ sv,
"a HASH"
, SVt_PVHV);
sv = MUTABLE_SV(GvHVn((GV*)sv));
}
do_HV_helem:
{
SV *keysv = NULL;
assert
(SvTYPE(sv) == SVt_PVHV);
switch
(actions & MDEREF_INDEX_MASK) {
case
MDEREF_INDEX_none:
goto
finish;
case
MDEREF_INDEX_const:
keysv = UNOP_AUX_item_sv(++items);
break
;
case
MDEREF_INDEX_padsv:
keysv = PAD_SVl((++items)->pad_offset);
break
;
case
MDEREF_INDEX_gvsv:
keysv = UNOP_AUX_item_sv(++items);
keysv = GvSVn((GV*)keysv);
break
;
}
PL_multideref_pc = items;
assert
( ((actions & MDEREF_INDEX_MASK) != MDEREF_INDEX_const)
|| SvTYPE(keysv) >= SVt_PVMG
|| !SvOK(keysv)
|| SvROK(keysv)
|| SvIsCOW_shared_hash(keysv));
if
(!(actions & MDEREF_FLAG_last)) {
HE *he = hv_fetch_ent((HV*)sv, keysv, 1, 0);
if
(!he || !(sv=HeVAL(he)) || sv == &PL_sv_undef)
DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
break
;
}
if
(PL_op->op_private &
(OPpMULTIDEREF_EXISTS|OPpMULTIDEREF_DELETE))
{
if
(PL_op->op_private & OPpMULTIDEREF_EXISTS) {
sv = hv_exists_ent((HV*)sv, keysv, 0)
? &PL_sv_yes : &PL_sv_no;
}
else
{
I32 discard = (GIMME_V == G_VOID) ? G_DISCARD : 0;
sv = hv_delete_ent((HV*)sv, keysv, discard, 0);
if
(discard)
return
NORMAL;
if
(!sv)
sv = &PL_sv_undef;
}
}
else
{
const
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
const
U32 defer = PL_op->op_private & OPpLVAL_DEFER;
const
bool
localizing = PL_op->op_private & OPpLVAL_INTRO;
bool
preeminent = TRUE;
SV **svp;
HV *
const
hv = (HV*)sv;
HE* he;
if
(UNLIKELY(localizing)) {
MAGIC *mg;
HV *stash;
if
(SvCANEXISTDELETE(hv))
preeminent = hv_exists_ent(hv, keysv, 0);
}
he = hv_fetch_ent(hv, keysv, lval && !defer, 0);
svp = he ? &HeVAL(he) : NULL;
if
(lval) {
if
(!svp || !(sv = *svp) || sv == &PL_sv_undef) {
SV* lv;
SV* key2;
if
(!defer)
DIE(aTHX_ PL_no_helem_sv, SVfARG(keysv));
lv = newSV_type_mortal(SVt_PVLV);
LvTYPE(lv) =
'y'
;
sv_magic(lv, key2 = newSVsv(keysv),
PERL_MAGIC_defelem, NULL, 0);
SvREFCNT_dec_NN(key2);
LvTARG(lv) = SvREFCNT_inc_simple_NN(hv);
LvTARGLEN(lv) = 1;
sv = lv;
}
else
{
if
(localizing) {
if
(HvNAME_get(hv) && isGV_or_RVCV(sv))
save_gp(MUTABLE_GV(sv),
!(PL_op->op_flags & OPf_SPECIAL));
else
if
(preeminent) {
save_helem_flags(hv, keysv, svp,
(PL_op->op_flags & OPf_SPECIAL)
? 0 : SAVEf_SETMAGIC);
sv = *svp;
}
else
SAVEHDELETE(hv, keysv);
}
}
}
else
{
sv = (svp && *svp ? *svp : &PL_sv_undef);
if
(SvRMAGICAL(hv) && SvGMAGICAL(sv))
mg_get(sv);
}
}
goto
finish;
}
}
actions >>= MDEREF_SHIFT;
}
}
PP(pp_iter)
{
PERL_CONTEXT *cx = CX_CUR();
SV **itersvp = CxITERVAR(cx);
const
U8 type = CxTYPE(cx);
PADOFFSET how_many = PL_op->op_targ;
PADOFFSET i = 0;
assert
(itersvp);
for
(; i <= how_many; ++i ) {
SV *oldsv;
SV *sv;
AV *av;
IV ix;
IV inc;
switch
(type) {
case
CXt_LOOP_LAZYSV:
{
SV* cur = cx->blk_loop.state_u.lazysv.cur;
SV *end = cx->blk_loop.state_u.lazysv.end;
STRLEN maxlen = 0;
const
char
*max = SvPV_const(end, maxlen);
bool
pad_it = FALSE;
if
(DO_UTF8(end) && IN_UNI_8_BIT)
maxlen = sv_len_utf8_nomg(end);
if
(UNLIKELY(SvNIOK(cur) || SvCUR(cur) > maxlen)) {
if
(LIKELY(!i)) {
goto
retno;
}
pad_it = TRUE;
}
oldsv = *itersvp;
if
(UNLIKELY(pad_it)) {
*itersvp = &PL_sv_undef;
SvREFCNT_dec(oldsv);
}
else
if
(oldsv && LIKELY(SvREFCNT(oldsv) == 1 && !SvMAGICAL(oldsv))) {
sv_setsv(oldsv, cur);
}
else
{
*itersvp = newSVsv(cur);
SvREFCNT_dec(oldsv);
}
if
(UNLIKELY(pad_it)) {
}
else
if
(strEQ(SvPVX_const(cur), max))
sv_setiv(cur, 0);
else
sv_inc(cur);
break
;
}
case
CXt_LOOP_LAZYIV:
{
IV cur = cx->blk_loop.state_u.lazyiv.cur;
bool
pad_it = FALSE;
if
(UNLIKELY(cur > cx->blk_loop.state_u.lazyiv.end)) {
if
(LIKELY(!i)) {
goto
retno;
}
pad_it = TRUE;
}
oldsv = *itersvp;
if
(UNLIKELY(pad_it)) {
*itersvp = &PL_sv_undef;
SvREFCNT_dec(oldsv);
}
else
if
(oldsv && LIKELY(SvREFCNT(oldsv) == 1 && !SvMAGICAL(oldsv))) {
if
( (SvFLAGS(oldsv) & (SVTYPEMASK|SVf_THINKFIRST|SVf_IVisUV))
== SVt_IV) {
assert
(!(SvFLAGS(oldsv) &
(SVf_OOK|SVf_UTF8|(SVf_OK & ~(SVf_IOK|SVp_IOK)))));
SvFLAGS(oldsv) |= (SVf_IOK|SVp_IOK);
oldsv->sv_u.svu_iv = cur;
}
else
sv_setiv(oldsv, cur);
}
else
{
*itersvp = newSViv(cur);
SvREFCNT_dec(oldsv);
}
if
(UNLIKELY(pad_it)) {
}
else
if
(UNLIKELY(cur == IV_MAX)) {
cx->blk_loop.state_u.lazyiv.end = IV_MIN;
}
else
++cx->blk_loop.state_u.lazyiv.cur;
break
;
}
case
CXt_LOOP_LIST:
assert
(OPpITER_REVERSED == 2);
inc = (IV)1 - (IV)(PL_op->op_private & OPpITER_REVERSED);
ix = (cx->blk_loop.state_u.stack.ix += inc);
if
(UNLIKELY(inc > 0
? ix > cx->blk_oldsp
: ix <= cx->blk_loop.state_u.stack.basesp)
) {
if
(LIKELY(!i)) {
goto
retno;
}
sv = &PL_sv_undef;
}
else
{
sv = PL_stack_base[ix];
}
av = NULL;
goto
loop_ary_common;
case
CXt_LOOP_ARY:
av = cx->blk_loop.state_u.ary.ary;
inc = (IV)1 - (IV)(PL_op->op_private & OPpITER_REVERSED);
ix = (cx->blk_loop.state_u.ary.ix += inc);
if
(UNLIKELY(inc > 0
? ix > AvFILL(av)
: ix < 0)
) {
if
(LIKELY(!i)) {
goto
retno;
}
sv = &PL_sv_undef;
}
else
if
(UNLIKELY(SvRMAGICAL(av))) {
SV *
const
*
const
svp = av_fetch(av, ix, FALSE);
sv = svp ? *svp : NULL;
}
else
{
sv = AvARRAY(av)[ix];
}
loop_ary_common:
if
(UNLIKELY(cx->cx_type & CXp_FOR_LVREF)) {
SvSetMagicSV(*itersvp, sv);
break
;
}
if
(LIKELY(sv)) {
if
(UNLIKELY(SvIS_FREED(sv))) {
*itersvp = NULL;
Perl_croak(aTHX_
"Use of freed value in iteration"
);
}
if
(SvPADTMP(sv)) {
sv = newSVsv(sv);
}
else
{
SvTEMP_off(sv);
SvREFCNT_inc_simple_void_NN(sv);
}
}
else
if
(av) {
sv = newSVavdefelem(av, ix, 0);
}
else
sv = &PL_sv_undef;
oldsv = *itersvp;
*itersvp = sv;
SvREFCNT_dec(oldsv);
break
;
default
:
DIE(aTHX_
"panic: pp_iter, type=%u"
, CxTYPE(cx));
}
++itersvp;
}
assert
(PL_op->op_next->op_type == OP_AND);
if
(PL_op->op_next->op_ppaddr == Perl_pp_and) {
return
cLOGOPx(PL_op->op_next)->op_other;
}
else
{
EXTEND_SKIP(PL_stack_sp, 1);
*++PL_stack_sp = &PL_sv_yes;
return
PL_op->op_next;
}
retno:
assert
(PL_op->op_next->op_type == OP_AND);
EXTEND_SKIP(PL_stack_sp, 1);
*++PL_stack_sp = &PL_sv_no;
if
(PL_op->op_next->op_ppaddr == Perl_pp_and) {
return
PL_op->op_next->op_next;
}
else
{
return
PL_op->op_next;
}
}
PP(pp_subst)
{
dSP; dTARG;
PMOP *pm = cPMOP;
PMOP *rpm = pm;
char
*s;
char
*strend;
const
char
*c;
STRLEN clen;
SSize_t iters = 0;
SSize_t maxiters;
bool
once;
U8 rxtainted = 0;
char
*orig;
U8 r_flags;
REGEXP *rx = PM_GETRE(pm);
regexp *prog = ReANY(rx);
STRLEN len;
int
force_on_match = 0;
const
I32 oldsave = PL_savestack_ix;
STRLEN slen;
bool
doutf8 = FALSE;
#ifdef PERL_ANY_COW
bool
was_cow;
#endif
SV *nsv = NULL;
SV *dstr = (pm->op_pmflags & PMf_CONST) ? POPs : NULL;
PERL_ASYNC_CHECK();
if
(PL_op->op_flags & OPf_STACKED)
TARG = POPs;
else
{
if
(ARGTARG)
GETTARGET;
else
{
TARG = DEFSV;
}
EXTEND(SP,1);
}
SvGETMAGIC(TARG);
#ifdef PERL_ANY_COW
was_cow = cBOOL(SvIsCOW(TARG));
#endif
if
(!(rpm->op_pmflags & PMf_NONDESTRUCT)) {
#ifndef PERL_ANY_COW
if
(SvIsCOW(TARG))
sv_force_normal_flags(TARG,0);
#endif
if
((SvREADONLY(TARG)
|| ( ((SvTYPE(TARG) == SVt_PVGV && isGV_with_GP(TARG))
|| SvTYPE(TARG) > SVt_PVLV)
&& !(SvTYPE(TARG) == SVt_PVGV && SvFAKE(TARG)))))
Perl_croak_no_modify();
}
PUTBACK;
orig = SvPV_nomg(TARG, len);
if
(!SvPOKp(TARG) || SvTYPE(TARG) == SVt_PVGV || SvVOK(TARG))
force_on_match = 1;
once = !(rpm->op_pmflags & PMf_GLOBAL);
if
(TAINTING_get) {
rxtainted = (
(SvTAINTED(TARG) ? SUBST_TAINT_STR : 0)
| (RXp_ISTAINTED(prog) ? SUBST_TAINT_PAT : 0)
| ((pm->op_pmflags & PMf_RETAINT) ? SUBST_TAINT_RETAINT : 0)
| (( (once && !(rpm->op_pmflags & PMf_NONDESTRUCT))
|| (PL_op->op_private & OPpTRUEBOOL)) ? SUBST_TAINT_BOOLRET : 0));
TAINT_NOT;
}
force_it:
if
(!pm || !orig)
DIE(aTHX_
"panic: pp_subst, pm=%p, orig=%p"
, pm, orig);
strend = orig + len;
slen = DO_UTF8(TARG) ? utf8_length((U8*)orig, (U8*)strend) : len;
maxiters = 2 * slen + 10;
if
(!RX_PRELEN(rx) && PL_curpm && !prog->mother_re) {
if
(PL_curpm == PL_reg_curpm) {
if
(PL_curpm_under) {
if
(PL_curpm_under == PL_reg_curpm) {
Perl_croak(aTHX_
"Infinite recursion via empty pattern"
);
}
else
{
pm = PL_curpm_under;
}
}
}
else
{
pm = PL_curpm;
}
rx = PM_GETRE(pm);
prog = ReANY(rx);
}
#ifdef PERL_SAWAMPERSAND
r_flags = ( RXp_NPARENS(prog)
|| PL_sawampersand
|| (RXp_EXTFLAGS(prog) & (RXf_EVAL_SEEN|RXf_PMf_KEEPCOPY))
|| (rpm->op_pmflags & PMf_KEEPCOPY)
)
? REXEC_COPY_STR
: 0;
#else
r_flags = REXEC_COPY_STR;
#endif
if
(!CALLREGEXEC(rx, orig, strend, orig, 0, TARG, NULL, r_flags))
{
SPAGAIN;
PUSHs(rpm->op_pmflags & PMf_NONDESTRUCT ? TARG : &PL_sv_no);
LEAVE_SCOPE(oldsave);
RETURN;
}
PL_curpm = pm;
if
(dstr) {
if
(DO_UTF8(TARG) && !doutf8) {
nsv = sv_newmortal();
SvSetSV(nsv, dstr);
sv_utf8_upgrade(nsv);
c = SvPV_const(nsv, clen);
doutf8 = TRUE;
}
else
{
c = SvPV_const(dstr, clen);
doutf8 = DO_UTF8(dstr);
}
if
(UNLIKELY(TAINT_get))
rxtainted |= SUBST_TAINT_REPL;
}
else
{
c = NULL;
doutf8 = FALSE;
}
if
(c
#ifdef PERL_ANY_COW
&& !was_cow
#endif
&& (I32)clen <= RXp_MINLENRET(prog)
&& ( once
|| !(r_flags & REXEC_COPY_STR)
|| (!SvGMAGICAL(dstr) && !(RXp_EXTFLAGS(prog) & RXf_EVAL_SEEN))
)
&& !(RXp_EXTFLAGS(prog) & RXf_NO_INPLACE_SUBST)
&& (!doutf8 || SvUTF8(TARG))
&& !(rpm->op_pmflags & PMf_NONDESTRUCT))
{
#ifdef PERL_ANY_COW
if
(SvIsCOW(TARG)) {
if
(!force_on_match)
goto
have_a_cow;
assert
(SvVOK(TARG));
}
#endif
if
(force_on_match) {
force_on_match = 0;
orig = SvPV_force_nomg(TARG, len);
goto
force_it;
}
if
(once) {
char
*d, *m;
if
(RXp_MATCH_TAINTED(prog))
rxtainted |= SUBST_TAINT_PAT;
m = orig + RXp_OFFS(prog)[0].start;
d = orig + RXp_OFFS(prog)[0].end;
s = orig;
if
(m - s > strend - d) {
I32 i;
if
(clen) {
Copy(c, m, clen,
char
);
m += clen;
}
i = strend - d;
if
(i > 0) {
Move(d, m, i,
char
);
m += i;
}
*m =
'\0'
;
SvCUR_set(TARG, m - s);
}
else
{
I32 i = m - s;
d -= clen;
if
(i > 0)
Move(s, d - i, i,
char
);
sv_chop(TARG, d-i);
if
(clen)
Copy(c, d, clen,
char
);
}
SPAGAIN;
PUSHs(&PL_sv_yes);
}
else
{
char
*d, *m;
d = s = RXp_OFFS(prog)[0].start + orig;
do
{
I32 i;
if
(UNLIKELY(iters++ > maxiters))
DIE(aTHX_
"Substitution loop"
);
if
(UNLIKELY(RXp_MATCH_TAINTED(prog)))
rxtainted |= SUBST_TAINT_PAT;
m = RXp_OFFS(prog)[0].start + orig;
if
((i = m - s)) {
if
(s != d)
Move(s, d, i,
char
);
d += i;
}
if
(clen) {
Copy(c, d, clen,
char
);
d += clen;
}
s = RXp_OFFS(prog)[0].end + orig;
}
while
(CALLREGEXEC(rx, s, strend, orig,
s == m,
TARG, NULL,
REXEC_NOT_FIRST|REXEC_IGNOREPOS|REXEC_FAIL_ON_UNDERFLOW));
if
(s != d) {
I32 i = strend - s;
SvCUR_set(TARG, d - SvPVX_const(TARG) + i);
Move(s, d, i+1,
char
);
}
SPAGAIN;
assert
(iters);
if
(PL_op->op_private & OPpTRUEBOOL)
PUSHs(&PL_sv_yes);
else
mPUSHi(iters);
}
}
else
{
bool
first;
char
*m;
SV *repl;
if
(force_on_match) {
force_on_match = 0;
if
(rpm->op_pmflags & PMf_NONDESTRUCT) {
TARG = sv_2mortal(newSVsv(TARG));
}
orig = SvPV_force_nomg(TARG, len);
goto
force_it;
}
#ifdef PERL_ANY_COW
have_a_cow:
#endif
if
(RXp_MATCH_TAINTED(prog))
rxtainted |= SUBST_TAINT_PAT;
repl = dstr;
s = RXp_OFFS(prog)[0].start + orig;
dstr = newSVpvn_flags(orig, s-orig,
SVs_TEMP | (DO_UTF8(TARG) ? SVf_UTF8 : 0));
if
(!c) {
PERL_CONTEXT *cx;
SPAGAIN;
m = orig;
CX_PUSHSUBST(cx);
RETURNOP(cPMOP->op_pmreplrootu.op_pmreplroot);
}
first = TRUE;
do
{
if
(UNLIKELY(iters++ > maxiters))
DIE(aTHX_
"Substitution loop"
);
if
(UNLIKELY(RXp_MATCH_TAINTED(prog)))
rxtainted |= SUBST_TAINT_PAT;
if
(RXp_MATCH_COPIED(prog) && RXp_SUBBEG(prog) != orig) {
char
*old_s = s;
char
*old_orig = orig;
assert
(RXp_SUBOFFSET(prog) == 0);
orig = RXp_SUBBEG(prog);
s = orig + (old_s - old_orig);
strend = s + (strend - old_s);
}
m = RXp_OFFS(prog)[0].start + orig;
sv_catpvn_nomg_maybeutf8(dstr, s, m - s, DO_UTF8(TARG));
s = RXp_OFFS(prog)[0].end + orig;
if
(first) {
if
(clen)
sv_catpvn_nomg_maybeutf8(dstr, c, clen, doutf8);
first = FALSE;
}
else
{
sv_catsv(dstr, repl);
}
if
(once)
break
;
}
while
(CALLREGEXEC(rx, s, strend, orig,
s == m,
TARG, NULL,
REXEC_NOT_FIRST|REXEC_IGNOREPOS|REXEC_FAIL_ON_UNDERFLOW));
assert
(strend >= s);
sv_catpvn_nomg_maybeutf8(dstr, s, strend - s, DO_UTF8(TARG));
if
(rpm->op_pmflags & PMf_NONDESTRUCT) {
TARG = dstr;
SPAGAIN;
PUSHs(dstr);
}
else
{
#ifdef PERL_ANY_COW
if
(SvIsCOW(TARG)) {
sv_force_normal_flags(TARG, SV_COW_DROP_PV);
}
else
#endif
{
SvPV_free(TARG);
}
SvPV_set(TARG, SvPVX(dstr));
SvCUR_set(TARG, SvCUR(dstr));
SvLEN_set(TARG, SvLEN(dstr));
SvFLAGS(TARG) |= SvUTF8(dstr);
SvPV_set(dstr, NULL);
SPAGAIN;
if
(PL_op->op_private & OPpTRUEBOOL)
PUSHs(&PL_sv_yes);
else
mPUSHi(iters);
}
}
if
(!(rpm->op_pmflags & PMf_NONDESTRUCT)) {
(
void
)SvPOK_only_UTF8(TARG);
}
if
(TAINTING_get) {
if
((rxtainted & SUBST_TAINT_PAT) ||
((rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_RETAINT)) ==
(SUBST_TAINT_STR|SUBST_TAINT_RETAINT))
)
(RXp_MATCH_TAINTED_on(prog));
if
(!(rxtainted & SUBST_TAINT_BOOLRET)
&& (rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_PAT))
)
SvTAINTED_on(TOPs);
else
SvTAINTED_off(TOPs);
TAINT_set(
cBOOL(rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_PAT|SUBST_TAINT_REPL))
);
SvTAINT(TARG);
}
SvSETMAGIC(TARG);
TAINT_NOT;
LEAVE_SCOPE(oldsave);
RETURN;
}
PP(pp_grepwhile)
{
dSP;
dPOPss;
if
(SvTRUE_NN(sv))
PL_stack_base[PL_markstack_ptr[-1]++] = PL_stack_base[*PL_markstack_ptr];
++*PL_markstack_ptr;
FREETMPS;
LEAVE_with_name(
"grep_item"
);
if
(UNLIKELY(PL_stack_base + *PL_markstack_ptr > SP)) {
I32 items;
const
U8 gimme = GIMME_V;
LEAVE_with_name(
"grep"
);
(
void
)POPMARK;
items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
(
void
)POPMARK;
SP = PL_stack_base + POPMARK;
if
(gimme == G_SCALAR) {
if
(PL_op->op_private & OPpTRUEBOOL)
PUSHs(items ? &PL_sv_yes : &PL_sv_zero);
else
{
dTARGET;
PUSHi(items);
}
}
else
if
(gimme == G_LIST)
SP += items;
RETURN;
}
else
{
SV *src;
ENTER_with_name(
"grep_item"
);
SAVEVPTR(PL_curpm);
src = PL_stack_base[TOPMARK];
if
(SvPADTMP(src)) {
src = PL_stack_base[TOPMARK] = sv_mortalcopy(src);
PL_tmps_floor++;
}
SvTEMP_off(src);
DEFSV_set(src);
RETURNOP(cLOGOP->op_other);
}
}
void
Perl_leave_adjust_stacks(pTHX_ SV **from_sp, SV **to_sp, U8 gimme,
int
pass)
{
dSP;
SSize_t tmps_base;
SSize_t nargs;
PERL_ARGS_ASSERT_LEAVE_ADJUST_STACKS;
TAINT_NOT;
if
(gimme == G_LIST) {
nargs = SP - from_sp;
from_sp++;
}
else
{
assert
(gimme == G_SCALAR);
if
(UNLIKELY(from_sp >= SP)) {
assert
(from_sp == SP);
EXTEND(SP, 1);
*++SP = &PL_sv_undef;
to_sp = SP;
nargs = 0;
}
else
{
from_sp = SP;
nargs = 1;
}
}
tmps_base = PL_tmps_floor + 1;
assert
(nargs >= 0);
if
(nargs) {
SV **tmps_basep;
EXTEND_MORTAL(nargs);
tmps_basep = PL_tmps_stack + tmps_base;
do
{
SV *sv = *from_sp++;
assert
(PL_tmps_ix + nargs < PL_tmps_max);
#ifdef DEBUGGING
if
(SvPADTMP(sv) && SvSMAGICAL(sv)) {
MAGIC *mg;
for
(mg = SvMAGIC(sv); mg; mg = mg->mg_moremagic) {
assert
(PERL_MAGIC_TYPE_IS_VALUE_MAGIC(mg->mg_type));
}
}
#endif
if
(
pass == 0 ? (SvTEMP(sv) && !SvMAGICAL(sv) && SvREFCNT(sv) == 1)
: pass == 1 ? ((SvTEMP(sv) || SvPADTMP(sv)) && !SvMAGICAL(sv) && SvREFCNT(sv) == 1)
: pass == 2 ? (!SvPADTMP(sv))
: 1)
{
*++to_sp = sv;
if
(SvTEMP(sv)) {
if
(tmps_basep <= &PL_tmps_stack[PL_tmps_ix]) {
if
(sv == *tmps_basep)
tmps_basep++;
else
SvTEMP_off(sv);
}
}
else
if
(!SvPADTMP(sv)) {
if
(!SvIMMORTAL(sv)) {
SvREFCNT_inc_simple_void_NN(sv);
SvTEMP_on(sv);
PL_tmps_stack[++PL_tmps_ix] = *tmps_basep;
*tmps_basep++ = sv;
}
}
}
else
{
SV *newsv = newSV_type(SVt_NULL);
PL_tmps_stack[++PL_tmps_ix] = *tmps_basep;
*tmps_basep++ = newsv;
*++to_sp = newsv;
if
(SvTYPE(sv) <= SVt_IV) {
U32 dstflags;
U32 srcflags = SvFLAGS(sv);
assert
(!SvGMAGICAL(sv));
if
(srcflags & (SVf_IOK|SVf_ROK)) {
SET_SVANY_FOR_BODYLESS_IV(newsv);
if
(srcflags & SVf_ROK) {
newsv->sv_u.svu_rv = SvREFCNT_inc(SvRV(sv));
dstflags = (SVt_IV|SVf_ROK|SVs_TEMP);
}
else
{
assert
( &(sv->sv_u.svu_iv)
== &(((XPVIV*) SvANY(sv))->xiv_iv));
assert
( &(newsv->sv_u.svu_iv)
== &(((XPVIV*) SvANY(newsv))->xiv_iv));
newsv->sv_u.svu_iv = sv->sv_u.svu_iv;
dstflags = (SVt_IV|SVf_IOK|SVp_IOK|SVs_TEMP
|(srcflags & SVf_IVisUV));
}
}
else
{
assert
(!(srcflags & SVf_OK));
dstflags = (SVt_NULL|SVs_TEMP);
}
SvFLAGS(newsv) = dstflags;
}
else
{
SSize_t old_base;
SvTEMP_on(newsv);
old_base = tmps_basep - PL_tmps_stack;
SvGETMAGIC(sv);
sv_setsv_flags(newsv, sv, SV_DO_COW_SVSETSV);
EXTEND_MORTAL(nargs);
tmps_basep = PL_tmps_stack + old_base;
TAINT_NOT;
}
}
}
while
(--nargs);
{
SV **top = PL_tmps_stack + PL_tmps_ix;
while
(tmps_basep <= top) {
SV *sv = *top;
if
(SvTEMP(sv))
top--;
else
{
SvTEMP_on(sv);
*top = *tmps_basep;
*tmps_basep = sv;
tmps_basep++;
}
}
}
tmps_base = tmps_basep - PL_tmps_stack;
}
PL_stack_sp = to_sp;
while
(PL_tmps_ix >= tmps_base) {
SV*
const
sv = PL_tmps_stack[PL_tmps_ix--];
#ifdef PERL_POISON
PoisonWith(PL_tmps_stack + PL_tmps_ix + 1, 1, SV *, 0xAB);
#endif
if
(LIKELY(sv)) {
SvTEMP_off(sv);
SvREFCNT_dec_NN(sv);
}
}
}
PP(pp_leavesub)
{
U8 gimme;
PERL_CONTEXT *cx;
SV **oldsp;
OP *retop;
cx = CX_CUR();
assert
(CxTYPE(cx) == CXt_SUB);
if
(CxMULTICALL(cx)) {
assert
(PL_stack_sp > PL_stack_base || *PL_stack_base == &PL_sv_undef);
return
0;
}
gimme = cx->blk_gimme;
oldsp = PL_stack_base + cx->blk_oldsp;
if
(gimme == G_VOID)
PL_stack_sp = oldsp;
else
leave_adjust_stacks(oldsp, oldsp, gimme, 0);
CX_LEAVE_SCOPE(cx);
cx_popsub(cx);
cx_popblock(cx);
retop = cx->blk_sub.retop;
CX_POP(cx);
return
retop;
}
void
Perl_clear_defarray(pTHX_ AV* av,
bool
abandon)
{
PERL_ARGS_ASSERT_CLEAR_DEFARRAY;
if
(LIKELY(!abandon && SvREFCNT(av) == 1 && !SvMAGICAL(av))) {
av_clear(av);
AvREIFY_only(av);
}
else
{
const
SSize_t size = AvFILLp(av) + 1;
AV *newav = newAV_alloc_x(size < 4 ? 4 : size);
AvREIFY_only(newav);
PAD_SVl(0) = MUTABLE_SV(newav);
SvREFCNT_dec_NN(av);
}
}
PP(pp_entersub)
{
dSP; dPOPss;
GV *gv;
CV *cv;
PERL_CONTEXT *cx;
I32 old_savestack_ix;
if
(UNLIKELY(!sv))
goto
do_die;
if
(LIKELY( (SvFLAGS(sv) & (SVf_ROK|SVs_GMG)) == SVf_ROK)) {
cv = MUTABLE_CV(SvRV(sv));
if
(UNLIKELY(SvOBJECT(cv)))
goto
do_ref;
}
else
cv = MUTABLE_CV(sv);
if
(UNLIKELY(SvTYPE(cv) != SVt_PVCV)) {
switch
(SvTYPE(sv)) {
case
SVt_PVLV:
if
(!isGV_with_GP(sv))
goto
do_default;
case
SVt_PVGV:
cv = GvCVu((
const
GV *)sv);
if
(UNLIKELY(!cv)) {
HV *stash;
cv = sv_2cv(sv, &stash, &gv, 0);
if
(!cv) {
old_savestack_ix = PL_savestack_ix;
goto
try_autoload;
}
}
break
;
default
:
do_default:
SvGETMAGIC(sv);
if
(SvROK(sv)) {
do_ref:
if
(UNLIKELY(SvAMAGIC(sv))) {
sv = amagic_deref_call(sv, to_cv_amg);
}
}
else
{
const
char
*sym;
STRLEN len;
if
(UNLIKELY(!SvOK(sv)))
DIE(aTHX_ PL_no_usym,
"a subroutine"
);
sym = SvPV_nomg_const(sv, len);
if
(PL_op->op_private & HINT_STRICT_REFS)
DIE(aTHX_
"Can't use string (\"%"
SVf32
"\"%s) as a subroutine ref while \"strict refs\" in use"
, sv, len>32 ?
"..."
:
""
);
cv = get_cvn_flags(sym, len, GV_ADD|SvUTF8(sv));
break
;
}
cv = MUTABLE_CV(SvRV(sv));
if
(LIKELY(SvTYPE(cv) == SVt_PVCV))
break
;
case
SVt_PVHV:
case
SVt_PVAV:
do_die:
DIE(aTHX_
"Not a CODE reference"
);
}
}
old_savestack_ix = PL_savestack_ix;
assert
(cv);
assert
((
void
*)&CvROOT(cv) == (
void
*)&CvXSUB(cv));
while
(UNLIKELY(!CvROOT(cv))) {
GV* autogv;
SV* sub_name;
if
(CvLEXICAL(cv) && CvHASGV(cv))
DIE(aTHX_
"Undefined subroutine &%"
SVf
" called"
,
SVfARG(cv_name(cv, NULL, 0)));
if
(CvANON(cv) || !CvHASGV(cv)) {
DIE(aTHX_
"Undefined subroutine called"
);
}
if
(cv != GvCV(gv = CvGV(cv))) {
cv = GvCV(gv);
}
else
{
try_autoload:
autogv = gv_autoload_pvn(GvSTASH(gv), GvNAME(gv), GvNAMELEN(gv),
(GvNAMEUTF8(gv) ? SVf_UTF8 : 0)
|(PL_op->op_flags & OPf_REF
? GV_AUTOLOAD_ISMETHOD
: 0));
cv = autogv ? GvCV(autogv) : NULL;
}
if
(!cv) {
sub_name = sv_newmortal();
gv_efullname3(sub_name, gv, NULL);
DIE(aTHX_
"Undefined subroutine &%"
SVf
" called"
, SVfARG(sub_name));
}
}
if
(UNLIKELY((CvFLAGS(cv) & (CVf_CLONE|CVf_CLONED)) == CVf_CLONE))
DIE(aTHX_
"Closure prototype called"
);
if
(UNLIKELY((PL_op->op_private & OPpENTERSUB_DB) && GvCV(PL_DBsub)
&& !CvNODEBUG(cv)))
{
Perl_get_db_sub(aTHX_ &sv, cv);
if
(CvISXSUB(cv))
PL_curcopdb = PL_curcop;
if
(CvLVALUE(cv)) {
cv = GvCV(gv_fetchpvs(
"DB::lsub"
, GV_ADDMULTI, SVt_PVCV));
if
(!cv) cv = GvCV(PL_DBsub);
}
else
{
cv = GvCV(PL_DBsub);
}
if
(!cv || (!CvXSUB(cv) && !CvSTART(cv)))
DIE(aTHX_
"No DB::sub routine defined"
);
}
if
(!(CvISXSUB(cv))) {
dMARK;
PADLIST *padlist;
I32 depth;
bool
hasargs;
U8 gimme;
{
SV **svp = MARK;
while
(svp < SP) {
SV *sv = *++svp;
if
(!sv)
continue
;
if
(SvPADTMP(sv))
*svp = sv = sv_mortalcopy(sv);
SvTEMP_off(sv);
}
}
gimme = GIMME_V;
cx = cx_pushblock(CXt_SUB, gimme, MARK, old_savestack_ix);
hasargs = cBOOL(PL_op->op_flags & OPf_STACKED);
cx_pushsub(cx, cv, PL_op->op_next, hasargs);
padlist = CvPADLIST(cv);
if
(UNLIKELY((depth = ++CvDEPTH(cv)) >= 2))
pad_push(padlist, depth);
PAD_SET_CUR_NOSAVE(padlist, depth);
if
(LIKELY(hasargs)) {
AV *
const
av = MUTABLE_AV(PAD_SVl(0));
SSize_t items;
AV **defavp;
defavp = &GvAV(PL_defgv);
cx->blk_sub.savearray = *defavp;
*defavp = MUTABLE_AV(SvREFCNT_inc_simple_NN(av));
assert
(!AvREAL(av) && AvFILLp(av) == -1);
items = SP - MARK;
if
(UNLIKELY(items - 1 > AvMAX(av))) {
SV **ary = AvALLOC(av);
Renew(ary, items, SV*);
AvMAX(av) = items - 1;
AvALLOC(av) = ary;
AvARRAY(av) = ary;
}
if
(items)
Copy(MARK+1,AvARRAY(av),items,SV*);
AvFILLp(av) = items - 1;
}
if
(UNLIKELY((cx->blk_u16 & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
!CvLVALUE(cv)))
DIE(aTHX_
"Can't modify non-lvalue subroutine call of &%"
SVf,
SVfARG(cv_name(cv, NULL, 0)));
if
(UNLIKELY(depth == PERL_SUB_DEPTH_WARN
&& ckWARN(WARN_RECURSION)
&& !(PERLDB_SUB && cv == GvCV(PL_DBsub))))
sub_crush_depth(cv);
RETURNOP(CvSTART(cv));
}
else
{
SSize_t markix = TOPMARK;
bool
is_scalar;
ENTER;
PL_scopestack[PL_scopestack_ix - 1] = old_savestack_ix;
SAVETMPS;
PUTBACK;
if
(UNLIKELY(((PL_op->op_private
& CX_PUSHSUB_GET_LVALUE_MASK(Perl_is_lvalue_sub)
) & OPpENTERSUB_LVAL_MASK) == OPpLVAL_INTRO &&
!CvLVALUE(cv)))
DIE(aTHX_
"Can't modify non-lvalue subroutine call of &%"
SVf,
SVfARG(cv_name(cv, NULL, 0)));
if
(UNLIKELY(!(PL_op->op_flags & OPf_STACKED) && GvAV(PL_defgv))) {
AV *
const
av = GvAV(PL_defgv);
const
SSize_t items = AvFILL(av) + 1;
if
(items) {
SSize_t i = 0;
const
bool
m = cBOOL(SvRMAGICAL(av));
EXTEND(SP, items);
for
(; i < items; ++i)
{
SV *sv;
if
(m) {
SV **
const
svp = av_fetch(av, i, 0);
sv = svp ? *svp : NULL;
}
else
sv = AvARRAY(av)[i];
if
(sv) SP[i+1] = sv;
else
{
SP[i+1] = av_nonelem(av, i);
}
}
SP += items;
PUTBACK ;
}
}
else
{
SV **mark = PL_stack_base + markix;
SSize_t items = SP - mark;
while
(items--) {
mark++;
if
(*mark && SvPADTMP(*mark)) {
*mark = sv_mortalcopy(*mark);
}
}
}
if
(UNLIKELY(PL_curcopdb)) {
SAVEVPTR(PL_curcop);
PL_curcop = PL_curcopdb;
PL_curcopdb = NULL;
}
is_scalar = (GIMME_V == G_SCALAR);
assert
(CvXSUB(cv));
CvXSUB(cv)(aTHX_ cv);
#if defined DEBUGGING && !defined DEBUGGING_RE_ONLY
if
(PL_curstackinfo->si_stack_hwm < PL_stack_sp - PL_stack_base)
Perl_croak_nocontext(
"panic: XSUB %s::%s (%s) failed to extend arg stack: "
"base=%p, sp=%p, hwm=%p\n"
,
HvNAME(GvSTASH(CvGV(cv))), GvNAME(CvGV(cv)), CvFILE(cv),
PL_stack_base, PL_stack_sp,
PL_stack_base + PL_curstackinfo->si_stack_hwm);
#endif
if
(is_scalar) {
SV **svp = PL_stack_base + markix + 1;
if
(svp != PL_stack_sp) {
*svp = svp > PL_stack_sp ? &PL_sv_undef : *PL_stack_sp;
PL_stack_sp = svp;
}
}
LEAVE;
return
NORMAL;
}
}
void
Perl_sub_crush_depth(pTHX_ CV *cv)
{
PERL_ARGS_ASSERT_SUB_CRUSH_DEPTH;
if
(CvANON(cv))
Perl_warner(aTHX_ packWARN(WARN_RECURSION),
"Deep recursion on anonymous subroutine"
);
else
{
Perl_warner(aTHX_ packWARN(WARN_RECURSION),
"Deep recursion on subroutine \"%"
SVf
"\""
,
SVfARG(cv_name(cv,NULL,0)));
}
}
void
Perl_croak_caller(
const
char
*pat, ...)
{
dTHX;
va_list
args;
const
PERL_CONTEXT *cx = caller_cx(0, NULL);
assert
(cx);
PL_curcop = cx->blk_oldcop;
va_start
(args, pat);
vcroak(pat, &args);
NOT_REACHED;
va_end
(args);
}
PP(pp_aelem)
{
dSP;
SV** svp;
SV*
const
elemsv = POPs;
IV elem = SvIV(elemsv);
AV *
const
av = MUTABLE_AV(POPs);
const
U32 lval = PL_op->op_flags & OPf_MOD || LVRET;
const
U32 defer = PL_op->op_private & OPpLVAL_DEFER;
const
bool
localizing = PL_op->op_private & OPpLVAL_INTRO;
bool
preeminent = TRUE;
SV *sv;
if
(UNLIKELY(SvROK(elemsv) && !SvGAMAGIC(elemsv) && ckWARN(WARN_MISC)))
Perl_warner(aTHX_ packWARN(WARN_MISC),
"Use of reference \"%"
SVf
"\" as array index"
,
SVfARG(elemsv));
if
(UNLIKELY(SvTYPE(av) != SVt_PVAV))
RETPUSHUNDEF;
if
(UNLIKELY(localizing)) {
MAGIC *mg;
HV *stash;
if
(SvCANEXISTDELETE(av))
preeminent = av_exists(av, elem);
}
svp = av_fetch(av, elem, lval && !defer);
if
(lval) {
#ifdef PERL_MALLOC_WRAP
if
(SvUOK(elemsv)) {
const
UV uv = SvUV(elemsv);
elem = uv > IV_MAX ? IV_MAX : uv;
}
else
if
(SvNOK(elemsv))
elem = (IV)SvNV(elemsv);
if
(elem > 0) {
MEM_WRAP_CHECK_s(elem,SV*,
"Out of memory during array extend"
);
}
#endif
if
(!svp || !*svp) {
IV len;
if
(!defer)
DIE(aTHX_ PL_no_aelem, elem);
len = av_top_index(av);
if
(elem < 0 && len + elem >= 0)
elem = len + elem;
if
(elem >= 0 && elem <= len)
PUSHs(av_nonelem(av,elem));
else
mPUSHs(newSVavdefelem(av, elem, 1));
RETURN;
}
if
(UNLIKELY(localizing)) {
if
(preeminent)
save_aelem(av, elem, svp);
else
SAVEADELETE(av, elem);
}
else
if
(PL_op->op_private & OPpDEREF) {
PUSHs(vivify_ref(*svp, PL_op->op_private & OPpDEREF));
RETURN;
}
}
sv = (svp ? *svp : &PL_sv_undef);
if
(!lval && SvRMAGICAL(av) && SvGMAGICAL(sv))
mg_get(sv);
PUSHs(sv);
RETURN;
}
SV*
Perl_vivify_ref(pTHX_ SV *sv, U32 to_what)
{
PERL_ARGS_ASSERT_VIVIFY_REF;
SvGETMAGIC(sv);
if
(!SvOK(sv)) {
if
(SvREADONLY(sv))
Perl_croak_no_modify();
prepare_SV_for_RV(sv);
switch
(to_what) {
case
OPpDEREF_SV:
SvRV_set(sv, newSV_type(SVt_NULL));
break
;
case
OPpDEREF_AV:
SvRV_set(sv, MUTABLE_SV(newAV()));
break
;
case
OPpDEREF_HV:
SvRV_set(sv, MUTABLE_SV(newHV()));
break
;
}
SvROK_on(sv);
SvSETMAGIC(sv);
SvGETMAGIC(sv);
}
if
(SvGMAGICAL(sv)) {
SV* msv = sv_newmortal();
sv_setsv_nomg(msv, sv);
return
msv;
}
return
sv;
}
PERL_STATIC_INLINE HV *
S_opmethod_stash(pTHX_ SV* meth)
{
SV* ob;
HV* stash;
SV*
const
sv = PL_stack_base + TOPMARK == PL_stack_sp
? (Perl_croak(aTHX_
"Can't call method \"%"
SVf
"\" without a "
"package or object reference"
, SVfARG(meth)),
(SV *)NULL)
: *(PL_stack_base + TOPMARK + 1);
PERL_ARGS_ASSERT_OPMETHOD_STASH;
if
(UNLIKELY(!sv))
undefined:
Perl_croak(aTHX_
"Can't call method \"%"
SVf
"\" on an undefined value"
,
SVfARG(meth));
if
(UNLIKELY(SvGMAGICAL(sv))) mg_get(sv);
else
if
(SvIsCOW_shared_hash(sv)) {
stash = gv_stashsv(sv, GV_CACHE_ONLY);
if
(stash)
return
stash;
}
if
(SvROK(sv))
ob = MUTABLE_SV(SvRV(sv));
else
if
(!SvOK(sv))
goto
undefined;
else
if
(isGV_with_GP(sv)) {
if
(!GvIO(sv))
Perl_croak(aTHX_
"Can't call method \"%"
SVf
"\" "
"without a package or object reference"
,
SVfARG(meth));
ob = sv;
if
(SvTYPE(ob) == SVt_PVLV && LvTYPE(ob) ==
'y'
) {
assert
(!LvTARGLEN(ob));
ob = LvTARG(ob);
assert
(ob);
}
*(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV(ob));
}
else
{
GV* iogv;
STRLEN packlen;
const
char
*
const
packname = SvPV_nomg_const(sv, packlen);
const
U32 packname_utf8 = SvUTF8(sv);
stash = gv_stashpvn(packname, packlen, packname_utf8 | GV_CACHE_ONLY);
if
(stash)
return
stash;
if
(!(iogv = gv_fetchpvn_flags(
packname, packlen, packname_utf8, SVt_PVIO
)) ||
!(ob=MUTABLE_SV(GvIO(iogv))))
{
if
(!packlen)
{
Perl_croak(aTHX_
"Can't call method \"%"
SVf
"\" "
"without a package or object reference"
,
SVfARG(meth));
}
stash = gv_stashpvn(packname, packlen, packname_utf8);
if
(stash)
return
stash;
else
return
MUTABLE_HV(sv);
}
*(PL_stack_base + TOPMARK + 1) = sv_2mortal(newRV(MUTABLE_SV(iogv)));
}
if
(!ob || !(SvOBJECT(ob)
|| (isGV_with_GP(ob)
&& (ob = MUTABLE_SV(GvIO((
const
GV *)ob)))
&& SvOBJECT(ob))))
{
Perl_croak(aTHX_
"Can't call method \"%"
SVf
"\" on unblessed reference"
,
SVfARG((SvPOK(meth) && SvPVX(meth) == PL_isa_DOES)
? newSVpvs_flags(
"DOES"
, SVs_TEMP)
: meth));
}
return
SvSTASH(ob);
}
PP(pp_method)
{
dSP;
GV* gv;
HV* stash;
SV*
const
meth = TOPs;
if
(SvROK(meth)) {
SV*
const
rmeth = SvRV(meth);
if
(SvTYPE(rmeth) == SVt_PVCV) {
SETs(rmeth);
RETURN;
}
}
stash = opmethod_stash(meth);
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK);
assert
(gv);
SETs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
RETURN;
}
#define METHOD_CHECK_CACHE(stash,cache,meth) \
const
HE*
const
he = hv_fetch_ent(cache, meth, 0, 0); \
if
(he) { \
gv = MUTABLE_GV(HeVAL(he)); \
if
(isGV(gv) && GvCV(gv) && (!GvCVGEN(gv) || GvCVGEN(gv) \
== (PL_sub_generation + HvMROMETA(stash)->cache_gen))) \
{ \
XPUSHs(MUTABLE_SV(GvCV(gv))); \
RETURN; \
} \
} \
PP(pp_method_named)
{
dSP;
GV* gv;
SV*
const
meth = cMETHOPx_meth(PL_op);
HV*
const
stash = opmethod_stash(meth);
if
(LIKELY(SvTYPE(stash) == SVt_PVHV)) {
METHOD_CHECK_CACHE(stash, stash, meth);
}
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK);
assert
(gv);
XPUSHs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
RETURN;
}
PP(pp_method_super)
{
dSP;
GV* gv;
HV* cache;
SV*
const
meth = cMETHOPx_meth(PL_op);
HV*
const
stash = CopSTASH(PL_curcop);
opmethod_stash(meth);
if
((cache = HvMROMETA(stash)->super)) {
METHOD_CHECK_CACHE(stash, cache, meth);
}
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK|GV_SUPER);
assert
(gv);
XPUSHs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
RETURN;
}
PP(pp_method_redir)
{
dSP;
GV* gv;
SV*
const
meth = cMETHOPx_meth(PL_op);
HV* stash = gv_stashsv(cMETHOPx_rclass(PL_op), 0);
opmethod_stash(meth);
if
(stash) { METHOD_CHECK_CACHE(stash, stash, meth); }
else
stash = MUTABLE_HV(cMETHOPx_rclass(PL_op));
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK);
assert
(gv);
XPUSHs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
RETURN;
}
PP(pp_method_redir_super)
{
dSP;
GV* gv;
HV* cache;
SV*
const
meth = cMETHOPx_meth(PL_op);
HV* stash = gv_stashsv(cMETHOPx_rclass(PL_op), 0);
opmethod_stash(meth);
if
(UNLIKELY(!stash)) stash = MUTABLE_HV(cMETHOPx_rclass(PL_op));
else
if
((cache = HvMROMETA(stash)->super)) {
METHOD_CHECK_CACHE(stash, cache, meth);
}
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK|GV_SUPER);
assert
(gv);
XPUSHs(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
RETURN;
}