#include "EXTERN.h"
#define PERL_IN_PP_HOT_C
#include "perl.h"
#include "regcomp.h"
#include "feature.h"
#ifdef PERL_RC_STACK
STATIC
void
S_pp_xs_wrap_return(pTHX_ I32 nargs, I32 old_sp)
{
I32 nret = (I32)(PL_stack_sp - PL_stack_base) - old_sp;
assert
(nret >= 0);
if
(nret) {
SV **svp = PL_stack_sp - nret + 1;
while
(svp <= PL_stack_sp) {
SvREFCNT_inc(*svp);
svp++;
}
}
PL_curstackinfo->si_stack_nonrc_base = 0;
if
(nargs) {
SV **svp = PL_stack_sp - nret;
I32 i = nargs;
while
(i--) {
SvREFCNT_dec(*svp);
*svp = NULL;
svp--;
}
if
(nret) {
Move(PL_stack_sp - nret + 1,
PL_stack_sp - nret - nargs + 1,
nret, SV*);
}
PL_stack_sp -= nargs;
}
}
OP*
Perl_pp_wrap(pTHX_ Perl_ppaddr_t real_pp_fn, I32 nargs,
int
nlists)
{
PERL_ARGS_ASSERT_PP_WRAP;
if
(!rpp_stack_is_rc())
return
real_pp_fn(aTHX);
OP *next_op;
I32 old_sp = (I32)(PL_stack_sp - PL_stack_base);
assert
(nargs >= 0);
assert
(nlists >= 0);
assert
(AvREAL(PL_curstack));
PL_curstackinfo->si_stack_nonrc_base = PL_stack_sp - PL_stack_base + 1;
if
(nlists) {
assert
(nargs == 0);
I32 mark = PL_markstack_ptr[-nlists+1];
nargs = (PL_stack_sp - PL_stack_base) - mark;
assert
(nlists <= 2);
PL_markstack_ptr[0] += nargs;
if
(nlists == 2)
PL_markstack_ptr[-1] += nargs;
}
if
(nargs) {
rpp_extend(nargs);
Copy(PL_stack_sp - nargs + 1, PL_stack_sp + 1, nargs, SV*);
PL_stack_sp += nargs;
}
next_op = real_pp_fn(aTHX);
assert
(AvREAL(PL_curstack));
assert
(PL_curstackinfo->si_stack_nonrc_base);
S_pp_xs_wrap_return(aTHX_ nargs, old_sp);
return
next_op;
}
void
Perl_xs_wrap(pTHX_ XSUBADDR_t xsub, CV *cv)
{
PERL_ARGS_ASSERT_XS_WRAP;
I32 old_sp = (I32)(PL_stack_sp - PL_stack_base);
I32 mark = PL_markstack_ptr[0];
I32 nargs = (PL_stack_sp - PL_stack_base) - mark;
assert
(AvREAL(PL_curstack));
assert
(!PL_curstackinfo->si_stack_nonrc_base);
PL_curstackinfo->si_stack_nonrc_base = PL_stack_sp - PL_stack_base + 1;
if
(nargs) {
rpp_extend(nargs);
Copy(PL_stack_sp - nargs + 1, PL_stack_sp + 1, nargs, SV*);
PL_stack_sp += nargs;
PL_markstack_ptr[0] += nargs;
}
xsub(aTHX_ cv);
S_pp_xs_wrap_return(aTHX_ nargs, old_sp);
}
#endif
void
Perl_rpp_free_2_(pTHX_ SV *
const
sv1, SV *
const
sv2,
const
U32 rc1,
const
U32 rc2)
{
PERL_ARGS_ASSERT_RPP_FREE_2_;
#ifdef PERL_RC_STACK
if
(rc1 > 1)
SvREFCNT(sv1) = rc1 - 1;
else
{
assert
(PL_stack_sp[1] == sv2);
PL_stack_sp++;
Perl_sv_free2(aTHX_ sv1, rc1);
PL_stack_sp--;
}
if
(rc2 > 1)
SvREFCNT(sv2) = rc2 - 1;
else
Perl_sv_free2(aTHX_ sv2, rc2);
#else
PERL_UNUSED_VAR(sv1);
PERL_UNUSED_VAR(sv2);
PERL_UNUSED_VAR(rc1);
PERL_UNUSED_VAR(rc2);
#endif
}
PP(pp_const)
{
rpp_xpush_1(cSVOP_sv);
return
NORMAL;
}
PP(pp_nextstate)
{
PL_curcop = (COP*)PL_op;
TAINT_NOT;
rpp_popfree_to_NN(PL_stack_base + CX_CUR()->blk_oldsp);
FREETMPS;
PERL_ASYNC_CHECK();
return
NORMAL;
}
PP(pp_gvsv)
{
assert
(SvTYPE(cGVOP_gv) == SVt_PVGV);
rpp_xpush_1(
UNLIKELY(PL_op->op_private & OPpLVAL_INTRO)
? save_scalar(cGVOP_gv)
: GvSVn(cGVOP_gv));
return
NORMAL;
}
PP(pp_null)
{
return
NORMAL;
}
PP(pp_pushmark)
{
PUSHMARK(PL_stack_sp);
return
NORMAL;
}
PP(pp_stringify)
{
dTARGET;
sv_copypv(TARG, *PL_stack_sp);
SvSETMAGIC(TARG);
rpp_replace_1_1_NN(TARG);
return
NORMAL;
}
PP(pp_gv)
{
assert
(SvTYPE(cGVOP_gv) == SVt_PVGV ||
(SvTYPE(cGVOP_gv) <= SVt_PVMG && SvROK(cGVOP_gv) && SvTYPE(SvRV(cGVOP_gv)) == SVt_PVCV));
rpp_xpush_1(MUTABLE_SV(cGVOP_gv));
return
NORMAL;
}
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)
rpp_popfree_1_NN();
return
cLOGOP->op_other;
}
}
}
PP(pp_padsv_store)
{
OP *
const
op = PL_op;
SV**
const
padentry = &PAD_SVl(op->op_targ);
SV* targ = *padentry;
SV*
const
val = *PL_stack_sp;
assert
(op->op_flags & OPf_STACKED);
if
((op->op_private & (OPpLVAL_INTRO|OPpPAD_STATE)) == OPpLVAL_INTRO) {
save_clearsv(padentry);
}
assert
(TAINTING_get || !TAINT_get);
if
(UNLIKELY(TAINT_get) && !SvTAINTED(val))
TAINT_NOT;
if
(
UNLIKELY(SvTEMP(targ)) && !SvSMAGICAL(targ) && SvREFCNT(targ) == 1 &&
(!isGV_with_GP(targ) || SvFAKE(targ)) && ckWARN(WARN_MISC)
)
Perl_warner(aTHX_
packWARN(WARN_MISC),
"Useless assignment to a temporary"
);
SvSetMagicSV(targ, val);
rpp_replace_1_1_NN(targ);
return
NORMAL;
}
PP(pp_aelemfastlex_store)
{
OP *
const
op = PL_op;
SV*
const
val = *PL_stack_sp;
AV *
const
av = MUTABLE_AV(PAD_SV(op->op_targ));
const
I8 key = (I8)PL_op->op_private;
SV * targ = NULL;
assert
(op->op_flags & OPf_STACKED);
assert
(SvTYPE(av) == SVt_PVAV);
if
(!SvRMAGICAL(av) && key >=0 && key <= AvFILLp(av)) {
targ = AvARRAY(av)[key];
}
if
(!targ) {
SV **svp = av_fetch(av, key, 1);
if
(svp)
targ = *svp;
else
DIE(aTHX_ PL_no_aelem, (
int
)key);
}
assert
(TAINTING_get || !TAINT_get);
if
(UNLIKELY(TAINT_get) && !SvTAINTED(val))
TAINT_NOT;
assert
(!(SvTEMP(targ) && SvREFCNT(targ) == 1 && !SvSMAGICAL(targ)));
SvSetMagicSV(targ, val);
assert
(GIMME_V == G_VOID);
rpp_popfree_1_NN();
return
NORMAL;
}
PP(pp_sassign)
{
SV *left = PL_stack_sp[0];
SV *right = PL_stack_sp[-1];
if
(PL_op->op_private & OPpASSIGN_BACKWARDS) {
SV *
const
temp = left;
left = right; right = temp;
PL_stack_sp[0] = left;
PL_stack_sp[-1] = right;
}
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);
rpp_replace_2_1_NN(left);
return
NORMAL;
}
}
if
(!is_gv) {
SV *sv = MUTABLE_SV(gv_fetchsv_nomg(left,GV_ADD, SVt_PVGV));
rpp_replace_1_1_NN(sv);
left = sv;
}
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
(
rpp_is_lone(left) && !SvSMAGICAL(left) &&
(!isGV_with_GP(left) || SvFAKE(left)) && ckWARN(WARN_MISC)
)
Perl_warner(aTHX_
packWARN(WARN_MISC),
"Useless assignment to a temporary"
);
SvSetMagicSV(left, right);
if
(LIKELY(GIMME_V == G_VOID))
rpp_popfree_2_NN();
else
{
assert
(PL_stack_sp[-1] == right);
assert
(PL_stack_sp[0] == left);
*--PL_stack_sp = left;
#ifdef PERL_RC_STACK
SvREFCNT_dec_NN(right);
#endif
}
return
NORMAL;
}
PP(pp_cond_expr)
{
PERL_ASYNC_CHECK();
bool
ok = SvTRUE_NN(*PL_stack_sp);
rpp_popfree_1_NN();
return
(ok ? cLOGOP->op_other : cLOGOP->op_next);
}
PP(pp_unstack)
{
PERL_CONTEXT *cx;
PERL_ASYNC_CHECK();
TAINT_NOT;
cx = CX_CUR();
rpp_popfree_to_NN(PL_stack_base + CX_CUR()->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)
{
SV *targ = (PL_op->op_flags & OPf_STACKED)
? PL_stack_sp[-1]
: PAD_SV(PL_op->op_targ);
if
(rpp_try_AMAGIC_2(concat_amg, AMGf_assign))
return
NORMAL;
SV *right = PL_stack_sp[0];
SV *left = PL_stack_sp[-1];
S_do_concat(aTHX_ left, right, targ, PL_op->op_private & OPpTARGET_MY);
rpp_replace_2_1_NN(targ);
return
NORMAL;
}
PP(pp_multiconcat)
{
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);
toparg = PL_stack_sp;
if
(PL_op->op_flags & OPf_STACKED) {
stack_adj++;
if
(is_append) {
targ = PL_stack_sp[-nargs];
}
else
{
targ = *PL_stack_sp;
toparg--;
}
}
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)
rpp_extend(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
(SV **svp = toparg - (nargs - 1); svp <= toparg; svp++, svpv_end++) {
U32 utf8;
STRLEN len;
SV *sv;
assert
(svpv_end - svpv_buf < PERL_MULTICONCAT_MAXARG);
sv = *svp;
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;
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;
}
++svpv_p;
}
}
*targ_pv =
'\0'
;
SvCUR_set(targ, targ_pv - SvPVX(targ));
assert
(grow >= SvCUR(targ) + 1);
assert
(SvLEN(targ) >= SvCUR(targ) + 1);
rpp_popfree_to_NN(PL_stack_sp - stack_adj);
SvTAINT(targ);
SvSETMAGIC(targ);
rpp_push_1(targ);
return
NORMAL;
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;
SV *csv = NULL;
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)
)
)
)
{
assert
(aux[PERL_MULTICONCAT_IX_PADTMP2].pad_offset);
SV *tmp = PAD_SV(aux[PERL_MULTICONCAT_IX_PADTMP2].pad_offset);
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
{
if
(!csv || SvREFCNT(csv) > 1 || SvLEN(csv) != 0) {
if
(csv)
csv = newSV_type_mortal(SVt_PV);
else
{
assert
(aux[PERL_MULTICONCAT_IX_PADTMP1].pad_offset);
csv = PAD_SV(
aux[PERL_MULTICONCAT_IX_PADTMP1].pad_offset);
SvUPGRADE(csv, SVt_PV);
}
if
(utf8)
SvUTF8_on(csv);
SvREADONLY_on(csv);
SvPOK_on(csv);
}
SvPV_set(csv, (
char
*)cpv);
SvLEN_set(csv, 0);
SvCUR_set(csv, len);
right = csv;
cpv += len;
}
arg_count++;
if
(arg_count <= 1) {
left = right;
continue
;
}
if
(arg_count == 2 && i < n) {
nexttarg = PAD_SV(aux[PERL_MULTICONCAT_IX_PADTMP0].pad_offset);
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;
}
if
( !is_append
&& ( (PL_op->op_flags & OPf_STACKED)
|| (PL_op->op_private & OPpTARGET_MY))
) {
sv_setsv(targ, left);
SvSETMAGIC(targ);
}
else
targ = left;
rpp_popfree_to_NN(PL_stack_sp - stack_adj);
rpp_push_1(targ);
return
NORMAL;
}
}
STATIC OP*
S_pushav(pTHX_ AV*
const
av)
{
const
SSize_t maxarg = AvFILL(av) + 1;
rpp_extend(maxarg);
if
(UNLIKELY(SvRMAGICAL(av))) {
PADOFFSET i;
for
(i=0; i < (PADOFFSET)maxarg; i++) {
SV **
const
svp = av_fetch(av, i, FALSE);
rpp_push_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];
rpp_push_1(LIKELY(sv)
? sv
: UNLIKELY(PL_op->op_flags & OPf_MOD)
? av_nonelem(av,i)
: &PL_sv_undef
);
}
}
return
NORMAL;
}
PP(pp_padrange)
{
PADOFFSET base = PL_op->op_targ;
int
count = (
int
)(PL_op->op_private) & OPpPADRANGE_COUNTMASK;
if
(PL_op->op_flags & OPf_SPECIAL) {
PUSHMARK(PL_stack_sp);
(
void
)S_pushav(aTHX_ GvAVn(PL_defgv));
}
if
((PL_op->op_flags & OPf_WANT) != OPf_WANT_VOID) {
int
i;
rpp_extend(count);
PUSHMARK(PL_stack_sp);
for
(i = 0; i <count; i++)
rpp_push_1(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
NORMAL;
}
PP(pp_padsv)
{
{
OP *
const
op = PL_op;
SV **
const
padentry = &(PAD_SVl(op->op_targ));
{
dTARG;
TARG = *padentry;
rpp_xpush_1(TARG);
}
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) {
rpp_replace_1_1_NN(
vivify_ref(*PL_stack_sp, op->op_private & OPpDEREF));
}
}
return
op->op_next;
}
}
PP(pp_readline)
{
SV *arg = *PL_stack_sp;
if
(arg) {
SvGETMAGIC(arg);
SV *tmpsv;
U8 gimme = GIMME_V;
if
(UNLIKELY(SvAMAGIC(arg) &&
(tmpsv = amagic_call(arg, &PL_sv_undef, iter_amg,
AMGf_want_list | AMGf_noright
|AMGf_unary))))
{
if
(gimme == G_VOID) {
NOOP;
}
else
if
(gimme == G_LIST) {
SSize_t i;
SSize_t len;
assert
(SvTYPE(tmpsv) == SVt_PVAV);
len = av_count((AV *)tmpsv);
assert
(*PL_stack_sp == arg);
rpp_popfree_1_NN();
assert
(!(PL_op->op_flags & OPf_STACKED));
rpp_extend(len);
for
(i = 0; i < len; ++i)
rpp_push_1(av_shift((AV *)tmpsv));
}
else
{
SV *targ = (PL_op->op_flags & OPf_STACKED)
? PL_stack_sp[-1]
: PAD_SV(PL_op->op_targ);
sv_setsv(targ, tmpsv);
SvSETMAGIC(targ);
if
(PL_op->op_flags & OPf_STACKED) {
rpp_popfree_1_NN();
assert
(*PL_stack_sp == targ);
}
else
rpp_replace_1_1_NN(targ);
}
return
NORMAL;
}
PL_last_in_gv = MUTABLE_GV(*PL_stack_sp);
#ifdef PERL_RC_STACK
if
(SvREFCNT(PL_last_in_gv) < 2)
sv_2mortal((SV*)PL_last_in_gv);
#endif
rpp_popfree_1_NN();
}
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
{
rpp_xpush_1(MUTABLE_SV(PL_last_in_gv));
Perl_pp_rv2gv(aTHX);
PL_last_in_gv = MUTABLE_GV(*PL_stack_sp);
rpp_popfree_1_NN();
assert
( (SV*)PL_last_in_gv == &PL_sv_undef
|| isGV_with_GP(PL_last_in_gv));
}
}
return
do_readline();
}
PP(pp_eq)
{
if
(rpp_try_AMAGIC_2(eq_amg, AMGf_numeric))
return
NORMAL;
SV *right = PL_stack_sp[0];
SV *left = PL_stack_sp[-1];
U32 flags_and = SvFLAGS(left) & SvFLAGS(right);
U32 flags_or = SvFLAGS(left) | SvFLAGS(right);
rpp_replace_2_IMM_NN(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
NORMAL;
}
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)
{
SV *sv;
PERL_ASYNC_CHECK();
sv = *PL_stack_sp;
if
(SvTRUE_NN(sv))
return
NORMAL;
else
{
if
(PL_op->op_type == OP_OR)
rpp_popfree_1_NN();
return
cLOGOP->op_other;
}
}
PP(pp_defined)
{
SV* sv = *PL_stack_sp;
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)
rpp_popfree_1();
return
cLOGOP->op_other;
}
}
else
{
if
(UNLIKELY(!sv || !SvANY(sv))) {
rpp_replace_1_1(&PL_sv_no);
return
NORMAL;
}
}
#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
NORMAL;
if
(op_type == OP_DOR)
rpp_popfree_1_NN();
return
cLOGOP->op_other;
}
rpp_replace_1_IMM_NN(defined ? &PL_sv_yes : &PL_sv_no);
return
NORMAL;
}
PP(pp_add)
{
bool
useleft; SV *svl, *svr;
SV *targ = (PL_op->op_flags & OPf_STACKED)
? PL_stack_sp[-1]
: PAD_SV(PL_op->op_targ);
if
(rpp_try_AMAGIC_2(add_amg, AMGf_assign|AMGf_numeric))
return
NORMAL;
svr = PL_stack_sp[0];
svl = PL_stack_sp[-1];
#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)) {
TARGi(il + ir, 0);
goto
ret;
}
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;
}
TARGn(nl + nr, 0);
goto
ret;
}
}
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) {
if
(auvok)
TARGu(result,1);
else
{
if
(result <= (UV)IV_MIN)
TARGi(result == (UV)IV_MIN
? IV_MIN : -(IV)result, 1);
else
{
TARGn(-(NV)result, 1);
}
}
goto
ret;
}
}
}
#else
useleft = USE_LEFT(svl);
#endif
{
NV value = SvNV_nomg(svr);
if
(!useleft) {
TARGn(value, 1);
}
else
{
TARGn(value + SvNV_nomg(svl), 1);
}
}
ret:
rpp_replace_2_1_NN(targ);
return
NORMAL;
}
PP(pp_aelemfast)
{
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);
if
(!SvRMAGICAL(av) && key >= 0 && key <= AvFILLp(av)) {
sv = AvARRAY(av)[key];
if
(sv)
goto
ret;
if
(!lval) {
sv = &PL_sv_undef;
goto
ret;
}
}
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);
ret:
rpp_xpush_1(sv);
return
NORMAL;
}
PP(pp_join)
{
dMARK; dTARGET;
MARK++;
do_join(TARG, *MARK, MARK, PL_stack_sp);
rpp_popfree_to_NN(MARK - 1);
rpp_push_1(TARG);
return
NORMAL;
}
PP(pp_print)
{
dMARK; dORIGMARK;
PerlIO *fp;
MAGIC *mg;
GV *
const
gv
= (PL_op->op_flags & OPf_STACKED) ? MUTABLE_GV(*++MARK) : PL_defoutgv;
IO *io = GvIO(gv);
SV *retval = &PL_sv_undef;
if
(io
&& (mg = SvTIED_mg((
const
SV *)io, PERL_MAGIC_tiedscalar)))
{
had_magic:
if
(MARK == ORIGMARK) {
rpp_extend(1);
MARK = ORIGMARK;
++MARK;
Move(MARK, MARK + 1, (PL_stack_sp - MARK) + 1, SV*);
*MARK = NULL;
++PL_stack_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)),
PL_stack_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 <= PL_stack_sp) {
if
(!do_print(*MARK, fp))
break
;
MARK++;
if
(MARK <= PL_stack_sp) {
if
(!do_print(GvSV(PL_ofsgv), fp)) {
MARK--;
break
;
}
}
}
}
else
{
while
(MARK <= PL_stack_sp) {
if
(!do_print(*MARK, fp))
break
;
MARK++;
}
}
if
(MARK <= PL_stack_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;
}
}
retval = &PL_sv_yes;
just_say_no:
rpp_popfree_to_NN(ORIGMARK);
if
((PL_op->op_flags & OPf_WANT) != OPf_WANT_VOID)
rpp_xpush_IMM(retval);
return
NORMAL;
}
PERL_STATIC_INLINE OP*
S_padhv_rv2hv_common(pTHX_ HV *hv, U8 gimme,
bool
is_keys,
bool
has_targ)
{
assert
(PL_op->op_type == OP_PADHV || PL_op->op_type == OP_RV2HV);
if
(gimme == G_LIST) {
if
(has_targ) {
#ifdef PERL_RC_STACK
SSize_t sp_base = PL_stack_sp - PL_stack_base;
hv_pushkv(hv, 3);
SSize_t nitems = PL_stack_sp - (PL_stack_base + sp_base);
SV *old_sv = PL_stack_sp[-nitems];
if
(nitems)
Move(PL_stack_sp - nitems + 1,
PL_stack_sp - nitems, nitems, SV*);
PL_stack_sp--;
SvREFCNT_dec_NN(old_sv);
#else
rpp_popfree_1_NN();
hv_pushkv(hv, 3);
#endif
}
else
hv_pushkv(hv, 3);
return
NORMAL;
}
if
(is_keys)
(
void
)hv_iterinit(hv);
if
(gimme == G_VOID) {
if
(has_targ)
rpp_popfree_1_NN();
return
NORMAL;
}
bool
is_bool = ( PL_op->op_private & OPpTRUEBOOL
|| ( PL_op->op_private & OPpMAYBE_TRUEBOOL
&& block_gimme() == G_VOID));
MAGIC *is_tied_mg = SvRMAGICAL(hv)
? mg_find(MUTABLE_SV(hv), PERL_MAGIC_tied)
: NULL;
IV i = 0;
SV *sv = NULL;
if
(UNLIKELY(is_tied_mg)) {
if
(is_keys && !is_bool) {
i = 0;
while
(hv_iternext(hv))
i++;
if
(has_targ)
rpp_popfree_1_NN();
goto
push_i;
}
else
{
sv = magic_scalarpack(hv, is_tied_mg);
if
(has_targ)
rpp_popfree_1_NN();
rpp_push_1(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
(has_targ)
rpp_popfree_1_NN();
if
(is_bool) {
rpp_push_IMM(i ? &PL_sv_yes : &PL_sv_zero);
}
else
{
push_i:
if
(has_targ) {
dTARGET;
TARGi(i,1);
rpp_push_1(targ);
}
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);
TARGi(i,1);
rpp_push_1(targ);
}
else
rpp_push_1_norc(newSViv(i));
}
}
return
NORMAL;
}
PP(pp_padav)
{
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));
if
(PL_op->op_flags & OPf_REF)
goto
ret;
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"
);
goto
ret;
}
}
gimme = GIMME_V;
if
(gimme == G_LIST)
return
S_pushav(aTHX_ (AV*)TARG);
if
(gimme == G_VOID)
return
NORMAL;
{
const
SSize_t maxarg = AvFILL(MUTABLE_AV(TARG)) + 1;
rpp_extend(1);
if
(!maxarg)
targ = &PL_sv_zero;
else
if
(PL_op->op_private & OPpTRUEBOOL)
targ = &PL_sv_yes;
else
{
rpp_push_1_norc(newSViv(maxarg));
return
NORMAL;
}
rpp_push_IMM(targ);
return
NORMAL;
}
ret:
rpp_xpush_1(targ);
return
NORMAL;
}
PP(pp_padhv)
{
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));
rpp_extend(1);
if
(PL_op->op_flags & OPf_REF) {
rpp_push_1(TARG);
return
NORMAL;
}
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"
);
rpp_push_1(TARG);
return
NORMAL;
}
}
gimme = GIMME_V;
return
S_padhv_rv2hv_common(aTHX_ (HV*)TARG, gimme,
cBOOL(PL_op->op_private & OPpPADHV_ISKEYS),
0
);
}
PP(pp_rv2av)
{
SV *sv = *PL_stack_sp;
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);
if
(!gv)
return
NORMAL;
}
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) {
rpp_replace_1_1_NN(sv);
return
NORMAL;
}
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;
rpp_replace_1_1_NN(sv);
return
NORMAL;
}
}
if
(is_pp_rv2av) {
AV *
const
av = MUTABLE_AV(sv);
if
(gimme == G_LIST) {
#ifdef PERL_RC_STACK
SSize_t sp_base = PL_stack_sp - PL_stack_base;
(
void
)S_pushav(aTHX_ av);
SSize_t nitems = PL_stack_sp - (PL_stack_base + sp_base);
SV *old_sv = PL_stack_sp[-nitems];
if
(nitems)
Move(PL_stack_sp - nitems + 1,
PL_stack_sp - nitems, nitems, SV*);
PL_stack_sp--;
SvREFCNT_dec_NN(old_sv);
return
NORMAL;
#else
rpp_popfree_1_NN();
return
S_pushav(aTHX_ av);
#endif
}
if
(gimme == G_SCALAR) {
const
SSize_t maxarg = AvFILL(av) + 1;
if
(PL_op->op_private & OPpTRUEBOOL)
rpp_replace_1_IMM_NN(maxarg ? &PL_sv_yes : &PL_sv_zero);
else
{
dTARGET;
TARGi(maxarg, 1);
rpp_replace_1_1_NN(targ);
}
}
}
else
{
return
S_padhv_rv2hv_common(aTHX_ (HV*)sv, gimme,
cBOOL(PL_op->op_private & OPpRV2HV_ISKEYS),
1
);
}
return
NORMAL;
croak_cant_return:
Perl_croak(aTHX_
"Can't return %s to lvalue scalar context"
,
is_pp_rv2av ?
"array"
:
"hash"
);
}
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 &&
#ifdef PERL_RC_STACK
SvREFCNT(svl) <= 2
#else
SvREFCNT(svl) == 1
#endif
) && !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;
#ifndef PERL_RC_STACK
if
(UNLIKELY(SvIS_FREED(svr))) {
Perl_croak(aTHX_
"panic: attempt to copy freed scalar %p"
,
(
void
*)svr);
}
#endif
SvFLAGS(svr) &= ~SVf_BREAK;
#ifdef PERL_RC_STACK
*relem = newSVsv_flags(svr,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL);
SvREFCNT_dec_NN(svr);
#else
*relem = sv_mortalcopy_flags(svr,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL);
#endif
SvFLAGS(svr) |= brk;
}
if
(!lcount)
break
;
}
if
(!marked)
return
;
while
(lelem > firstlelem) {
SV *
const
svl = *(--lelem);
if
(svl)
SvFLAGS(svl) &= ~SVf_BREAK;
}
}
STATIC
void
S_aassign_uid(pTHX)
{
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)
Perl_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)
Perl_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
}
PP(pp_aassign)
{
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 ||
#ifdef PERL_RC_STACK
SvREFCNT(sv) <= 2
#else
SvREFCNT(sv) == 1
#endif
)
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;
bool
is_list = (gimme == G_LIST);
relem = firstrelem;
lelem = firstlelem;
#ifdef PERL_RC_STACK
SV ** first_discard = firstlelem;
#endif
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 nelems = lastrelem - relem + 1;
AV *ary = MUTABLE_AV(lsv);
#ifndef PERL_RC_STACK
EXTEND_MORTAL(nelems + 1);
PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(ary);
SSize_t 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;
#endif
if
(UNLIKELY(alias)) {
U32 lval = (is_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) {
rsv = sv_mortalcopy(rsv);
rpp_replace_at_NN(svp, rsv);
}
#ifndef PERL_RC_STACK
rsv = SvREFCNT_inc_NN(SvRV(rsv));
assert
(tmps_base <= PL_tmps_max);
PL_tmps_stack[tmps_base++] = rsv;
#endif
}
}
else
{
for
(svp = relem; svp <= lastrelem; svp++) {
SV *rsv = *svp;
if
(rpp_is_lone(rsv) && !SvGMAGICAL(rsv)) {
#ifndef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(rsv);
#endif
SvTEMP_off(rsv);
}
else
{
SV *nsv;
nsv = newSVsv_flags(rsv,
(SV_DO_COW_SVSETSV|SV_NOSTEAL|SV_GMAGIC));
#ifdef PERL_RC_STACK
rpp_replace_at_norc_NN(svp, nsv);
#else
rpp_replace_at_NN(svp, nsv);
#endif
rsv = nsv;
}
#ifndef PERL_RC_STACK
assert
(tmps_base <= PL_tmps_max);
PL_tmps_stack[tmps_base++] = rsv;
#endif
}
}
if
(SvRMAGICAL(ary) || AvFILLp(ary) >= 0)
av_clear(ary);
#ifndef PERL_RC_STACK
tmps_base -= nelems;
#endif
if
(alias || SvMAGICAL(ary) || SvREADONLY(ary) || !AvREAL(ary)) {
av_extend(ary, nelems - 1);
for
(i = 0; i < nelems; i++) {
SV **svp =
#ifdef PERL_RC_STACK
&relem[i];
#else
&(PL_tmps_stack[tmps_base + i]);
#endif
SV *rsv = *svp;
#ifdef PERL_RC_STACK
if
(alias) {
assert
(SvROK(rsv));
rsv = SvRV(rsv);
}
#endif
if
(av_store(ary, i, rsv))
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_NN(rsv);
#else
*svp = &PL_sv_undef;
#endif
;
SvSETMAGIC(rsv);
}
#ifndef PERL_RC_STACK
PL_tmps_stack[tmps_base - 1] = &PL_sv_undef;
#endif
}
else
{
SSize_t fill = nelems - 1;
if
(fill > AvMAX(ary))
av_extend_guts(ary, fill, &AvMAX(ary), &AvALLOC(ary),
&AvARRAY(ary));
AvFILLp(ary) = fill;
#ifdef PERL_RC_STACK
Copy(relem, AvARRAY(ary), nelems, SV*);
if
(UNLIKELY(is_list))
for
(i = 0; i < nelems; i++)
SvREFCNT_inc_void_NN(relem[i]);
else
{
assert
(first_discard == relem + nelems);
Zero(relem, nelems, SV*);
first_discard = relem;
}
#else
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);
#endif
}
if
(UNLIKELY(PL_delaymagic & DM_ARRAY_ISA))
SvSETMAGIC(MUTABLE_SV(ary));
#ifdef PERL_RC_STACK
assert
(*lelem == (SV*)ary);
*lelem = NULL;
#endif
lelem++;
SvREFCNT_dec_NN(ary);
relem = lastrelem + 1;
goto
no_relems;
}
case
SVt_PVHV: {
SV **svp;
SSize_t i;
SSize_t nelems = lastrelem - relem + 1;
HV *hash = MUTABLE_HV(lsv);
if
(UNLIKELY(nelems & 1)) {
do_oddball(lastrelem, relem);
#ifdef PERL_RC_STACK
if
(lelem == lastrelem + 1) {
assert
(lastrelem[1] == (SV*)hash);
sv_2mortal((SV*)hash);
}
else
{
assert
(!lastrelem[1] || SvIMMORTAL(lastrelem[1]));
}
first_discard++;
assert
(first_discard = lastrelem + 2);
#endif
*++lastrelem = &PL_sv_undef;
nelems++;
}
#ifndef PERL_RC_STACK
EXTEND_MORTAL(nelems + 1);
#endif
nelems >>= 1;
#ifndef PERL_RC_STACK
PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple_NN(hash);
SSize_t 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;
#endif
for
(svp = relem + 1; svp <= lastrelem; svp += 2) {
SV *rsv = *svp;
if
(rpp_is_lone(rsv) && !SvGMAGICAL(rsv)) {
#ifndef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(rsv);
#endif
SvTEMP_off(rsv);
}
else
{
SV *nsv;
nsv = newSVsv_flags(rsv,
(SV_DO_COW_SVSETSV|SV_NOSTEAL|SV_GMAGIC));
#ifdef PERL_RC_STACK
rpp_replace_at_norc_NN(svp, nsv);
#else
rpp_replace_at_NN(svp, nsv);
#endif
rsv = nsv;
}
#ifndef PERL_RC_STACK
assert
(tmps_base <= PL_tmps_max);
PL_tmps_stack[tmps_base++] = rsv;
#endif
}
#ifndef PERL_RC_STACK
tmps_base -= nelems;
#endif
if
(UNLIKELY(is_list)) {
#ifndef PERL_RC_STACK
EXTEND_MORTAL(nelems);
#endif
for
(svp = relem; svp <= lastrelem; svp += 2) {
rpp_replace_at_norc_NN(svp,
newSVsv_flags(*svp,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL));
}
}
else
if
(PL_op->op_private & OPpASSIGN_COMMON_AGG) {
#ifdef PERL_RC_STACK
for
(svp = relem; svp <= lastrelem; svp += 2) {
SV *rsv = *svp;
if
(UNLIKELY(SvGMAGICAL(rsv)))
rpp_replace_at_norc_NN(svp,
newSVsv_flags(rsv,
SV_GMAGIC|SV_DO_COW_SVSETSV|SV_NOSTEAL));
}
#else
EXTEND_MORTAL(nelems);
for
(svp = relem; svp <= lastrelem; svp += 2) {
SV *rsv = *svp;
if
(UNLIKELY(SvGMAGICAL(rsv))) {
SSize_t n;
rpp_replace_at_norc_NN(svp,
newSVsv_flags(rsv,
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);
}
#endif
}
if
(SvRMAGICAL(hash) || HvUSEDKEYS(hash))
hv_clear(hash);
if
(nelems > PERL_HASH_DEFAULT_HvMAX) {
hv_ksplit(hash, nelems);
}
#ifndef PERL_RC_STACK
bool
dirty_tmps = FALSE;
#endif
if
(UNLIKELY(is_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)) {
rpp_replace_at_NN(topelem, key);
topelem += 2;
}
if
(hv_store_ent(hash, key, val, 0))
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_NN(val);
#else
PL_tmps_stack[tmps_base + i] = &PL_sv_undef;
else
dirty_tmps = TRUE;
#endif
;
SvSETMAGIC(val);
}
if
(topelem < svp) {
lastrelem = topelem - 1;
while
(relem < lastrelem) {
HE *he;
he = hv_fetch_ent(hash, *relem++, 0, 0);
rpp_replace_at_NN(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;
#ifdef PERL_RC_STACK
{
HE *stored = hv_store_ent(hash, key, val, 0);
;
SvSETMAGIC(val);
*svp = NULL;
if
(!stored)
SvREFCNT_dec_NN(val);
svp[-1] = NULL;
SvREFCNT_dec_NN(key);
}
#else
if
(hv_store_ent(hash, key, val, 0))
PL_tmps_stack[tmps_base + i] = &PL_sv_undef;
else
dirty_tmps = TRUE;
;
SvSETMAGIC(val);
#endif
}
#ifdef PERL_RC_STACK
assert
(first_discard == lastrelem + 1);
first_discard = relem;
#endif
}
#ifdef PERL_RC_STACK
if
(*lelem == (SV*)hash) {
*lelem = NULL;
SvREFCNT_dec_NN(hash);
}
#else
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);
#endif
lelem++;
relem = lastrelem + 1;
goto
no_relems;
}
default
:
if
(!SvIMMORTAL(lsv)) {
if
(UNLIKELY(
rpp_is_lone(lsv) && !SvSMAGICAL(lsv) &&
(!isGV_with_GP(lsv) || SvFAKE(lsv)) && ckWARN(WARN_MISC)
))
Perl_warner(aTHX_
packWARN(WARN_MISC),
"Useless assignment to a temporary"
);
#ifndef PERL_RC_STACK
SV *ref;
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 + 1));
PL_tmps_stack[ix] = ref;
}
#endif
sv_setsv(lsv, *relem);
SvSETMAGIC(lsv);
if
(UNLIKELY(is_list))
rpp_replace_at_NN(relem, lsv);
#ifdef PERL_RC_STACK
*lelem = NULL;
SvREFCNT_dec_NN(lsv);
#endif
}
lelem++;
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);
}
if
(UNLIKELY(is_list)) {
#ifdef PERL_RC_STACK
assert
(relem <= first_discard);
assert
(relem <= lelem);
if
(relem == first_discard)
first_discard++;
#endif
rpp_replace_at(relem++, lsv);
#ifdef PERL_RC_STACK
if
(relem == lelem + 1) {
lelem++;
continue
;
}
#endif
}
break
;
}
#ifdef PERL_RC_STACK
*lelem = NULL;
SvREFCNT_dec_NN(lsv);
#endif
lelem++;
}
TAINT_NOT;
if
(UNLIKELY(PL_delaymagic & ~DM_DELAY))
S_aassign_uid(aTHX);
PL_delaymagic = old_delaymagic;
#ifdef PERL_RC_STACK
# ifdef DEBUGGING
for
(SV **svp = first_discard; svp <= PL_stack_sp; svp++)
assert
(!*svp || SvIMMORTAL(*svp));
# endif
PL_stack_sp = first_discard - 1;
rpp_popfree_to_NN((is_list ? relem : firstrelem) - 1);
#else
rpp_popfree_to_NN((is_list ? relem : firstrelem) - 1);
#endif
if
(gimme == G_SCALAR) {
rpp_extend(1);
SV *sv;
if
(PL_op->op_private & OPpASSIGN_TRUEBOOL)
rpp_push_IMM((firstlelem - firstrelem) ? &PL_sv_yes : &PL_sv_zero);
else
{
dTARGET;
TARGi(firstlelem - firstrelem, 1);
sv = targ;
rpp_push_1(sv);
}
}
return
NORMAL;
}
PP(pp_qr)
{
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));
}
rpp_xpush_1(rv);
return
NORMAL;
}
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)
{
SV *targ;
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;
SSize_t sp_base;
if
(PL_op->op_flags & OPf_STACKED) {
targ = PL_stack_sp[0];
sp_base = PL_stack_sp - PL_stack_base;
assert
(sp_base > 0);
}
else
{
sp_base = 0;
if
(PL_op->op_targ)
targ = PAD_SV(PL_op->op_targ);
else
{
targ = DEFSV;
}
rpp_extend(1);
}
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_END(prog,0));
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);
if
(sp_base)
rpp_popfree_1();
rpp_push_IMM(&PL_sv_yes);
return
NORMAL;
}
{
const
I32 logical_nparens = RXp_LOGICAL_NPARENS(prog);
I32 logical_paren = (global && !logical_nparens) ? 1 : 0;
I32 *l2p = RXp_LOGICAL_TO_PARNO(prog);
I32 *p2l_next = RXp_PARNO_TO_LOGICAL_NEXT(prog);
rpp_extend(logical_nparens + logical_paren);
EXTEND_MORTAL(logical_nparens + logical_paren);
for
(logical_paren = !logical_paren;
logical_paren <= logical_nparens;
logical_paren++)
{
I32 phys_paren = l2p ? l2p[logical_paren] : logical_paren;
SSize_t offs_start, offs_end;
while
(1) {
if
(((offs_end = RXp_OFFS_END(prog, phys_paren)) != -1) &&
((offs_start = RXp_OFFS_START(prog, phys_paren)) != -1))
{
const
SSize_t len = offs_end - offs_start;
const
char
*
const
s = offs_start + truebase;
if
( UNLIKELY( len < 0 || len > strend - s) ) {
DIE(aTHX_
"panic: pp_match start/end pointers, paren=%"
I32df
", "
"start=%zd, end=%zd, s=%p, strend=%p, len=%zd"
,
phys_paren, offs_start, offs_end, s, strend, len);
}
rpp_push_1(newSVpvn_flags(s, len,
(DO_UTF8(TARG))
? SVf_UTF8|SVs_TEMP
: SVs_TEMP)
);
break
;
}
else
if
(!p2l_next || !(phys_paren = p2l_next[phys_paren])) {
rpp_push_1(sv_newmortal());
break
;
}
}
}
if
(global) {
curpos = (UV)RXp_OFFS_END(prog,0);
had_zerolen = RXp_ZERO_LEN(prog);
r_flags |= REXEC_IGNOREPOS | REXEC_NOT_FIRST;
goto
play_it_again;
}
LEAVE_SCOPE(oldsave);
goto
ret_list;
}
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) {
if
(sp_base)
rpp_popfree_1();
rpp_push_IMM(&PL_sv_no);
return
NORMAL;
}
ret_list:
if
(sp_base) {
SSize_t nitems = PL_stack_sp - (PL_stack_base + sp_base);
#ifdef PERL_RC_STACK
SV *old_sv = PL_stack_sp[-nitems];
#endif
if
(nitems)
Move(PL_stack_sp - nitems + 1,
PL_stack_sp - nitems, nitems, SV*);
PL_stack_sp--;
#ifdef PERL_RC_STACK
SvREFCNT_dec_NN(old_sv);
#endif
}
return
NORMAL;
}
OP *
Perl_do_readline(pTHX)
{
const
I32 type = PL_op->op_type;
if
(PL_op->op_flags & OPf_STACKED) {
assert
(type != OP_GLOB);
assert
(GIMME_V == G_SCALAR);
}
if
(type == OP_RCATLINE)
assert
(PL_op->op_flags & OPf_STACKED);
const
U8 gimme = GIMME_V;
SV *targ = (gimme == G_SCALAR)
? (PL_op->op_flags & OPf_STACKED)
? *PL_stack_sp
: PAD_SV(PL_op->op_targ)
: NULL;
SV *sv;
STRLEN tmplen = 0;
STRLEN offset;
PerlIO *fp;
IO *
const
io = GvIO(PL_last_in_gv);
if
(io) {
const
MAGIC *
const
mg = SvTIED_mg((
const
SV *)io, PERL_MAGIC_tiedscalar);
if
(mg) {
assert
(type != OP_GLOB);
assert
(!(gimme != G_SCALAR && (PL_op->op_flags & OPf_STACKED)));
Perl_tied_method(aTHX_ SV_CONST(READLINE),
PL_stack_sp,
MUTABLE_SV(io), mg, gimme, 0);
if
(gimme == G_SCALAR) {
SvSetSV_nosteal(targ, *PL_stack_sp);
SvSETMAGIC(targ);
if
(PL_op->op_flags & OPf_STACKED) {
rpp_popfree_1();
assert
(*PL_stack_sp == targ);
}
else
rpp_replace_1_1(targ);
}
else
assert
(!(PL_op->op_flags & OPf_STACKED));
return
NORMAL;
}
}
fp = NULL;
if
(io) {
fp = IoIFP(io);
if
(fp) {
if
(IoTYPE(io) == IoTYPE_WRONLY)
report_wrongway_fh(PL_last_in_gv,
'>'
);
}
else
{
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_ *PL_stack_sp, io);
rpp_popfree_1_NN();
}
}
}
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);
if
(!(PL_op->op_flags & OPf_STACKED))
rpp_push_1(targ);
}
return
NORMAL;
}
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
(;;) {
if
(!sv_gets(sv, fp, offset)
&& (type == OP_GLOB
|| SNARF_EOF(gimme, PL_rs, io, sv)
|| PerlIO_error(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) {
PerlIO_clearerr(fp);
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);
}
if
(!(PL_op->op_flags & OPf_STACKED))
rpp_push_1(targ);
}
else
if
(PL_op->op_flags & OPf_STACKED)
rpp_popfree_1_NN();
MAYBE_TAINT_LINE(io, sv);
return
NORMAL;
}
MAYBE_TAINT_LINE(io, sv);
IoLINES(io)++;
IoFLAGS(io) |= IOf_NOLINE;
SvSETMAGIC(sv);
rpp_extend(1);
if
(PL_op->op_flags & OPf_STACKED) {
assert
(*PL_stack_sp == targ);
PL_stack_sp[1] = targ;
*PL_stack_sp++ = NULL;
rpp_replace_at(PL_stack_sp - 1, sv);
}
else
rpp_push_1(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) {
assert
(!(PL_op->op_flags & OPf_STACKED));
rpp_popfree_1();
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
;
}
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);
}
if
(PL_op->op_flags & OPf_STACKED)
rpp_popfree_1_NN();
return
NORMAL;
}
}
PP(pp_helem)
{
HE* he;
SV **svp;
SV *
const
keysv = PL_stack_sp[0];
HV *
const
hv = MUTABLE_HV(PL_stack_sp[-1]);
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;
SV *retsv;
if
(SvTYPE(hv) != SVt_PVHV) {
retsv = &PL_sv_undef;
goto
ret;
}
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;
retsv = lv;
goto
ret;
}
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) {
retsv = vivify_ref(*svp, PL_op->op_private & OPpDEREF);
goto
ret;;
}
}
sv = (svp && *svp ? *svp : &PL_sv_undef);
if
(!lval && SvRMAGICAL(hv) && SvGMAGICAL(sv))
mg_get(sv);
retsv = sv;
ret:
rpp_replace_2_1_NN(retsv);
return
NORMAL;
}
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;
bool
replace = FALSE;
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:
{
sv = *PL_stack_sp;
replace = TRUE;
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:
{
if
(replace)
rpp_replace_1_1_NN(sv);
else
rpp_xpush_1(sv);
return
NORMAL;
}
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:
{
sv = *PL_stack_sp;
replace = TRUE;
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);
rpp_push_IMM(&PL_sv_yes);
return
PL_op->op_next;
}
retno:
assert
(PL_op->op_next->op_type == OP_AND);
EXTEND_SKIP(PL_stack_sp, 1);
rpp_push_IMM(&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)
{
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;
bool
doutf8 = FALSE;
#ifdef PERL_ANY_COW
bool
was_cow;
#endif
SV *nsv = NULL;
SSize_t sp_offset = 0;
SV *dstr;
SV *retval;
PERL_ASYNC_CHECK();
if
(pm->op_pmflags & PMf_CONST) {
dstr = *PL_stack_sp;
sp_offset++;
}
else
dstr = NULL;
if
(PL_op->op_flags & OPf_STACKED) {
TARG = PL_stack_sp[-sp_offset];
sp_offset++;
}
else
{
if
(ARGTARG)
GETTARGET;
else
{
TARG = DEFSV;
}
if
(!sp_offset)
rpp_extend(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();
}
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;
maxiters = 2 * len + 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))
{
SV *ret = rpm->op_pmflags & PMf_NONDESTRUCT ? TARG : &PL_sv_no;
if
(dstr)
rpp_popfree_1_NN();
if
(PL_op->op_flags & OPf_STACKED)
rpp_replace_1_1_NN(ret);
else
rpp_push_1(ret);
LEAVE_SCOPE(oldsave);
return
NORMAL;
}
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
&& (SSize_t)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_START(prog,0);
d = orig + RXp_OFFS_END(prog,0);
s = orig;
if
(m - s > strend - d) {
SSize_t 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
{
SSize_t 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
);
}
retval = &PL_sv_yes;
goto
ret;
}
else
{
char
*d, *m;
d = s = RXp_OFFS_START(prog,0) + orig;
do
{
SSize_t i;
if
(UNLIKELY(iters++ > maxiters))
DIE(aTHX_
"Substitution loop"
);
if
(UNLIKELY(RXp_MATCH_TAINTED(prog)))
rxtainted |= SUBST_TAINT_PAT;
m = RXp_OFFS_START(prog,0) + 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_END(prog,0) + orig;
}
while
(CALLREGEXEC(rx, s, strend, orig,
s == m,
TARG, NULL,
REXEC_NOT_FIRST|REXEC_IGNOREPOS|REXEC_FAIL_ON_UNDERFLOW));
if
(s != d) {
SSize_t i = strend - s;
SvCUR_set(TARG, d - SvPVX_const(TARG) + i);
Move(s, d, i+1,
char
);
}
assert
(iters);
goto
ret_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_START(prog,0) + orig;
dstr = newSVpvn_flags(orig, s-orig,
SVs_TEMP | (DO_UTF8(TARG) ? SVf_UTF8 : 0));
if
(!c) {
PERL_CONTEXT *cx;
m = orig;
CX_PUSHSUBST(cx);
return
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_START(prog,0) + orig;
sv_catpvn_nomg_maybeutf8(dstr, s, m - s, DO_UTF8(TARG));
s = RXp_OFFS_END(prog,0) + 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;
retval = dstr;
goto
ret;
}
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);
goto
ret_iters;
}
}
ret_iters:
if
(PL_op->op_private & OPpTRUEBOOL)
retval = &PL_sv_yes;
else
{
retval = sv_newmortal();
sv_setiv(retval, iters);
}
ret:
if
(dstr)
rpp_popfree_1_NN();
if
(PL_op->op_flags & OPf_STACKED)
rpp_replace_1_1_NN(retval);
else
rpp_push_1(retval);
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(retval);
else
SvTAINTED_off(retval);
TAINT_set(
cBOOL(rxtainted & (SUBST_TAINT_STR|SUBST_TAINT_PAT|SUBST_TAINT_REPL))
);
SvTAINT(TARG);
}
SvSETMAGIC(TARG);
TAINT_NOT;
LEAVE_SCOPE(oldsave);
return
NORMAL;
}
PP(pp_grepwhile)
{
bool
match = SvTRUE_NN(*PL_stack_sp);
rpp_popfree_1_NN();
if
(match) {
SV **from_p = PL_stack_base + PL_markstack_ptr[0];
SV **to_p = PL_stack_base + PL_markstack_ptr[-1]++;
SV *from = *from_p;
SV *to = *to_p;
if
(from != to) {
*to_p = from;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(from);
SvREFCNT_dec(to);
#endif
}
}
++*PL_markstack_ptr;
FREETMPS;
LEAVE_with_name(
"grep_item"
);
if
(UNLIKELY(PL_stack_base + *PL_markstack_ptr > PL_stack_sp)) {
SSize_t items;
const
U8 gimme = GIMME_V;
LEAVE_with_name(
"grep"
);
(
void
)POPMARK;
items = --*PL_markstack_ptr - PL_markstack_ptr[-1];
(
void
)POPMARK;
SV **base = PL_stack_base + POPMARK;
if
(gimme == G_LIST)
rpp_popfree_to_NN(base + items);
else
{
rpp_popfree_to_NN(base);
if
(gimme == G_SCALAR) {
if
(PL_op->op_private & OPpTRUEBOOL)
rpp_push_IMM(items ? &PL_sv_yes : &PL_sv_zero);
else
{
dTARGET;
TARGi(items,1);
rpp_push_1(TARG);
}
}
}
return
NORMAL;
}
else
{
SV *src;
ENTER_with_name(
"grep_item"
);
SAVEVPTR(PL_curpm);
src = PL_stack_base[TOPMARK];
if
(SvPADTMP(src)) {
SV *newsrc = sv_mortalcopy(src);
PL_stack_base[TOPMARK] = newsrc;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsrc);
SvREFCNT_dec(src);
#endif
src = newsrc;
PL_tmps_floor++;
}
SvTEMP_off(src);
DEFSV_set(src);
return
cLOGOP->op_other;
}
}
void
Perl_leave_adjust_stacks(pTHX_ SV **from_sp, SV **to_sp, U8 gimme,
int
pass)
{
SSize_t tmps_base;
SSize_t nargs;
PERL_ARGS_ASSERT_LEAVE_ADJUST_STACKS;
TAINT_NOT;
if
(gimme == G_LIST) {
nargs = PL_stack_sp - from_sp;
from_sp++;
}
else
{
assert
(gimme == G_SCALAR);
if
(UNLIKELY(from_sp >= PL_stack_sp)) {
assert
(from_sp == PL_stack_sp);
rpp_xpush_IMM(&PL_sv_undef);
}
from_sp = PL_stack_sp;
nargs = 1;
}
#ifdef PERL_RC_STACK
{
SV **p = from_sp - 1;
assert
(p >= to_sp);
while
(p > to_sp) {
SV *sv = *p;
*p-- = NULL;
SvREFCNT_dec(sv);
}
}
#endif
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 ? (rpp_is_lone(sv) && !SvMAGICAL(sv))
: pass == 1 ? ((SvTEMP(sv) || SvPADTMP(sv)) && !SvMAGICAL(sv) && SvREFCNT(sv) == 1)
: pass == 2 ? (!SvPADTMP(sv))
: 1)
{
#ifdef PERL_RC_STACK
from_sp[-1] = NULL;
#endif
*++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;
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;
}
#ifdef PERL_RC_STACK
from_sp[-1] = NULL;
SvREFCNT_dec_NN(sv);
assert
(!to_sp[1]);
*++to_sp = newsv;
SvREFCNT_inc_simple_void_NN(newsv);
#else
*++to_sp = newsv;
#endif
}
}
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)
rpp_popfree_to_NN(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))
#ifndef PERL_RC_STACK
&& !AvREAL(av)
#endif
) {
clear_defarray_simple(av);
#ifndef PERL_RC_STACK
AvREIFY_only(av);
#endif
}
else
{
const
SSize_t size = AvFILLp(av) + 1;
AV *newav = newAV_alloc_xz(size < PERL_ARRAY_NEW_MIN_KEY ?
PERL_ARRAY_NEW_MIN_KEY : size);
#ifndef PERL_RC_STACK
AvREIFY_only(newav);
#endif
PAD_SVl(0) = MUTABLE_SV(newav);
SvREFCNT_dec_NN(av);
}
}
PP(pp_entersub)
{
GV *gv;
CV *cv;
PERL_CONTEXT *cx;
I32 old_savestack_ix;
SV *sv = *PL_stack_sp;
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"
);
}
rpp_popfree_1_NN();
if
(!(CvISXSUB(cv))) {
dMARK;
PADLIST *padlist;
I32 depth;
bool
hasargs;
U8 gimme;
{
SV **svp = MARK;
while
(svp < PL_stack_sp) {
SV *sv = *++svp;
if
(!sv)
continue
;
if
(SvPADTMP(sv)) {
SV *newsv = sv_mortalcopy(sv);
*svp = newsv;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsv);
SvREFCNT_dec_NN(sv);
#endif
sv = newsv;
}
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));
#ifdef PERL_RC_STACK
assert
(AvREAL(av));
#else
assert
(!AvREAL(av));
#endif
assert
(AvFILLp(av) == -1);
items = PL_stack_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;
#ifdef PERL_RC_STACK
PL_stack_sp = MARK;
#endif
}
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);
return
CvSTART(cv);
}
else
{
SSize_t markix = TOPMARK;
bool
is_scalar;
ENTER;
PL_scopestack[PL_scopestack_ix - 1] = old_savestack_ix;
SAVETMPS;
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));
rpp_extend(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];
rpp_push_1(sv ? sv : av_nonelem(av, i));
}
}
}
else
{
SV **mark = PL_stack_base + markix;
SSize_t items = PL_stack_sp - mark;
while
(items--) {
mark++;
if
(*mark && SvPADTMP(*mark)) {
SV *oldsv = *mark;
SV *newsv = sv_mortalcopy(oldsv);
*mark = newsv;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsv);
SvREFCNT_dec_NN(oldsv);
#endif
}
}
}
if
(UNLIKELY(PL_curcopdb)) {
SAVEVPTR(PL_curcop);
PL_curcop = PL_curcopdb;
PL_curcopdb = NULL;
}
is_scalar = (GIMME_V == G_SCALAR);
assert
(CvXSUB(cv));
rpp_invoke_xs(cv);
#ifdef PERL_USE_HWM
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) {
#ifdef PERL_RC_STACK
if
(svp < PL_stack_sp) {
SV* retsv = *PL_stack_sp;
*PL_stack_sp = *svp;
*svp = retsv;
rpp_popfree_to_NN(svp);
}
else
rpp_push_IMM(&PL_sv_undef);
#else
*svp = svp > PL_stack_sp ? &PL_sv_undef : *PL_stack_sp;
PL_stack_sp = svp;
#endif
}
}
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)
{
SV** svp;
SV*
const
elemsv = PL_stack_sp[0];
IV elem = SvIV(elemsv);
AV *
const
av = MUTABLE_AV(PL_stack_sp[-1]);
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;
SV *retsv;
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)) {
retsv = &PL_sv_undef;
goto
ret;
}
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)
retsv = av_nonelem(av, elem);
else
retsv = sv_2mortal(newSVavdefelem(av, elem, 1));
goto
ret;
}
if
(UNLIKELY(localizing)) {
if
(preeminent)
save_aelem(av, elem, svp);
else
SAVEADELETE(av, elem);
}
else
if
(PL_op->op_private & OPpDEREF) {
retsv = vivify_ref(*svp, PL_op->op_private & OPpDEREF);
goto
ret;
}
}
sv = (svp ? *svp : &PL_sv_undef);
if
(!lval && SvRMAGICAL(av) && SvGMAGICAL(sv))
mg_get(sv);
retsv = sv;
ret:
rpp_replace_2_1_NN(retsv);
return
NORMAL;
}
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);
}
SV *newsv = sv_2mortal(newRV(ob));
SV **svp = (PL_stack_base + TOPMARK + 1);
#ifdef PERL_RC_STACK
SV *oldsv = *svp;
#endif
*svp = newsv;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsv);
SvREFCNT_dec_NN(oldsv);
#endif
}
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
((PL_op->op_private & OPpMETH_NO_BAREWORD_IO) ||
!(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);
}
SV *newsv = sv_2mortal(newRV(MUTABLE_SV(iogv)));
SV **svp = (PL_stack_base + TOPMARK + 1);
#ifdef PERL_RC_STACK
SV *oldsv = *svp;
#endif
*svp = newsv;
#ifdef PERL_RC_STACK
SvREFCNT_inc_simple_void_NN(newsv);
SvREFCNT_dec_NN(oldsv);
#endif
}
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)
{
GV* gv;
HV* stash;
SV*
const
meth = *PL_stack_sp;
if
(SvROK(meth)) {
SV*
const
rmeth = SvRV(meth);
if
(SvTYPE(rmeth) == SVt_PVCV) {
rpp_replace_1_1_NN(rmeth);
return
NORMAL;
}
}
stash = opmethod_stash(meth);
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK);
assert
(gv);
rpp_replace_1_1_NN(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
return
NORMAL;
}
#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))) \
{ \
rpp_xpush_1(MUTABLE_SV(GvCV(gv))); \
return
NORMAL; \
} \
} \
PP(pp_method_named)
{
GV* gv;
SV*
const
meth = cMETHOP_meth;
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);
rpp_xpush_1(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
return
NORMAL;
}
PP(pp_method_super)
{
GV* gv;
HV* cache;
SV*
const
meth = cMETHOP_meth;
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);
rpp_xpush_1(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
return
NORMAL;
}
PP(pp_method_redir)
{
GV* gv;
SV*
const
meth = cMETHOP_meth;
HV* stash = gv_stashsv(cMETHOP_rclass, 0);
opmethod_stash(meth);
if
(stash) { METHOD_CHECK_CACHE(stash, stash, meth); }
else
stash = MUTABLE_HV(cMETHOP_rclass);
gv = gv_fetchmethod_sv_flags(stash, meth, GV_AUTOLOAD|GV_CROAK);
assert
(gv);
rpp_xpush_1(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
return
NORMAL;
}
PP(pp_method_redir_super)
{
GV* gv;
HV* cache;
SV*
const
meth = cMETHOP_meth;
HV* stash = gv_stashsv(cMETHOP_rclass, 0);
opmethod_stash(meth);
if
(UNLIKELY(!stash)) stash = MUTABLE_HV(cMETHOP_rclass);
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);
rpp_xpush_1(isGV(gv) ? MUTABLE_SV(GvCV(gv)) : MUTABLE_SV(gv));
return
NORMAL;
}