#include "EXTERN.h"
#define PERL_IN_GV_C
#include "perl.h"
#include "overload.inc"
#include "keywords.h"
#include "feature.h"
static
const
char
S_autoload[] =
"AUTOLOAD"
;
#define S_autolen (sizeof("AUTOLOAD")-1)
GV *
Perl_gv_add_by_type(pTHX_ GV *gv, svtype type)
{
SV **where;
if
(
!gv
|| (
SvTYPE((
const
SV *)gv) != SVt_PVGV
&& SvTYPE((
const
SV *)gv) != SVt_PVLV
)
) {
const
char
*what;
if
(type == SVt_PVIO) {
what = OP_IS_DIRHOP(PL_op->op_type) ?
"dirhandle"
:
"filehandle"
;
}
else
if
(type == SVt_PVHV) {
what =
"hash"
;
}
else
{
what = type == SVt_PVAV ?
"array"
:
"scalar"
;
}
Perl_croak(aTHX_
"Bad symbol for %s"
, what);
}
if
(type == SVt_PVHV) {
where = (SV **)&GvHV(gv);
}
else
if
(type == SVt_PVAV) {
where = (SV **)&GvAV(gv);
}
else
if
(type == SVt_PVIO) {
where = (SV **)&GvIOp(gv);
}
else
{
where = &GvSV(gv);
}
if
(!*where)
{
*where = newSV_type(type);
if
( type == SVt_PVAV
&& memEQs(GvNAME(gv), GvNAMELEN(gv),
"ISA"
))
{
sv_magic(*where, (SV *)gv, PERL_MAGIC_isa, NULL, 0);
}
}
return
gv;
}
GV *
Perl_gv_fetchfile(pTHX_
const
char
*name)
{
PERL_ARGS_ASSERT_GV_FETCHFILE;
return
gv_fetchfile_flags(name,
strlen
(name), 0);
}
GV *
Perl_gv_fetchfile_flags(pTHX_
const
char
*
const
name,
const
STRLEN namelen,
const
U32 flags)
{
char
smallbuf[128];
char
*tmpbuf;
const
STRLEN tmplen = namelen + 2;
GV *gv;
PERL_ARGS_ASSERT_GV_FETCHFILE_FLAGS;
PERL_UNUSED_ARG(flags);
if
(!PL_defstash)
return
NULL;
if
(tmplen <=
sizeof
smallbuf)
tmpbuf = smallbuf;
else
Newx(tmpbuf, tmplen,
char
);
tmpbuf[0] =
'_'
;
tmpbuf[1] =
'<'
;
memcpy
(tmpbuf + 2, name, namelen);
GV **gvp = (GV**)hv_fetch(PL_defstash, tmpbuf, tmplen, (flags & GVF_NOADD) ? FALSE : TRUE);
if
(gvp) {
gv = *gvp;
if
(!isGV(gv)) {
gv_init(gv, PL_defstash, tmpbuf, tmplen, FALSE);
#ifdef PERL_DONT_CREATE_GVSV
GvSV(gv) = newSVpvn(name, namelen);
#else
sv_setpvn(GvSV(gv), name, namelen);
#endif
}
if
(PERLDB_LINE_OR_SAVESRC && !GvAV(gv))
hv_magic(GvHVn(gv), GvAVn(gv), PERL_MAGIC_dbfile);
}
else
{
gv = NULL;
}
if
(tmpbuf != smallbuf)
Safefree(tmpbuf);
return
gv;
}
SV *
Perl_gv_const_sv(pTHX_ GV *gv)
{
PERL_ARGS_ASSERT_GV_CONST_SV;
PERL_UNUSED_CONTEXT;
if
(SvTYPE(gv) == SVt_PVGV)
return
cv_const_sv(GvCVu(gv));
return
SvROK(gv) && SvTYPE(SvRV(gv)) != SVt_PVAV && SvTYPE(SvRV(gv)) != SVt_PVCV ? SvRV(gv) : NULL;
}
GP *
Perl_newGP(pTHX_ GV *
const
gv)
{
GP *gp;
U32 hash;
const
char
*file;
STRLEN len;
#ifndef USE_ITHREADS
GV *filegv;
#endif
PERL_ARGS_ASSERT_NEWGP;
Newxz(gp, 1, GP);
gp->gp_egv = gv;
#ifndef PERL_DONT_CREATE_GVSV
gp->gp_sv = newSV_type(SVt_NULL);
#endif
if
(PL_curcop) {
gp->gp_line = CopLINE(PL_curcop);
#ifdef USE_ITHREADS
if
(CopFILE(PL_curcop)) {
file = CopFILE(PL_curcop);
len =
strlen
(file);
}
#else
filegv = CopFILEGV(PL_curcop);
if
(filegv) {
file = GvNAME(filegv)+2;
len = GvNAMELEN(filegv)-2;
}
#endif
else
goto
no_file;
}
else
{
no_file:
file =
""
;
len = 0;
}
PERL_HASH(hash, file, len);
gp->gp_file_hek = share_hek(file, len, hash);
gp->gp_refcnt = 1;
return
gp;
}
void
Perl_cvgv_set(pTHX_ CV* cv, GV* gv)
{
GV *
const
oldgv = CvNAMED(cv) ? NULL : SvANY(cv)->xcv_gv_u.xcv_gv;
HEK *hek;
PERL_ARGS_ASSERT_CVGV_SET;
if
(oldgv == gv)
return
;
if
(oldgv) {
if
(CvCVGV_RC(cv)) {
SvREFCNT_dec_NN(oldgv);
CvCVGV_RC_off(cv);
}
else
{
sv_del_backref(MUTABLE_SV(oldgv), MUTABLE_SV(cv));
}
}
else
if
((hek = CvNAME_HEK(cv))) {
unshare_hek(hek);
CvLEXICAL_off(cv);
}
CvNAMED_off(cv);
SvANY(cv)->xcv_gv_u.xcv_gv = gv;
assert
(!CvCVGV_RC(cv));
if
(!gv)
return
;
if
(isGV_with_GP(gv) && GvGP(gv) && (GvCV(gv) == cv || GvFORM(gv) == cv))
Perl_sv_add_backref(aTHX_ MUTABLE_SV(gv), MUTABLE_SV(cv));
else
{
CvCVGV_RC_on(cv);
SvREFCNT_inc_simple_void_NN(gv);
}
}
GV *
Perl_cvgv_from_hek(pTHX_ CV *cv)
{
GV *gv;
SV **svp;
PERL_ARGS_ASSERT_CVGV_FROM_HEK;
assert
(SvTYPE(cv) == SVt_PVCV);
if
(!CvSTASH(cv))
return
NULL;
ASSUME(CvNAME_HEK(cv));
svp = hv_fetchhek(CvSTASH(cv), CvNAME_HEK(cv), 0);
gv = MUTABLE_GV(svp && *svp ? *svp : newSV_type(SVt_NULL));
if
(!isGV(gv))
gv_init_pvn(gv, CvSTASH(cv), HEK_KEY(CvNAME_HEK(cv)),
HEK_LEN(CvNAME_HEK(cv)),
SVf_UTF8 * !!HEK_UTF8(CvNAME_HEK(cv)));
if
(!CvNAMED(cv)) {
assert
(SvANY(cv)->xcv_gv_u.xcv_gv == gv);
return
gv;
}
unshare_hek(CvNAME_HEK(cv));
CvNAMED_off(cv);
SvANY(cv)->xcv_gv_u.xcv_gv = gv;
if
(svp && *svp) SvREFCNT_inc_simple_void_NN(gv);
CvCVGV_RC_on(cv);
return
gv;
}
void
Perl_cvstash_set(pTHX_ CV *cv, HV *st)
{
HV *oldst = CvSTASH(cv);
PERL_ARGS_ASSERT_CVSTASH_SET;
if
(oldst == st)
return
;
if
(oldst)
sv_del_backref(MUTABLE_SV(oldst), MUTABLE_SV(cv));
SvANY(cv)->xcv_stash = st;
if
(st)
Perl_sv_add_backref(aTHX_ MUTABLE_SV(st), MUTABLE_SV(cv));
}
void
Perl_gv_init_sv(pTHX_ GV *gv, HV *stash, SV* namesv, U32 flags)
{
char
*namepv;
STRLEN namelen;
PERL_ARGS_ASSERT_GV_INIT_SV;
namepv = SvPV(namesv, namelen);
if
(SvUTF8(namesv))
flags |= SVf_UTF8;
gv_init_pvn(gv, stash, namepv, namelen, flags);
}
void
Perl_gv_init_pv(pTHX_ GV *gv, HV *stash,
const
char
*name, U32 flags)
{
PERL_ARGS_ASSERT_GV_INIT_PV;
gv_init_pvn(gv, stash, name,
strlen
(name), flags);
}
void
Perl_gv_init_pvn(pTHX_ GV *gv, HV *stash,
const
char
*name, STRLEN len, U32 flags)
{
const
U32 old_type = SvTYPE(gv);
const
bool
doproto = old_type > SVt_NULL;
char
*
const
proto = (doproto && SvPOK(gv))
? ((
void
)(SvIsCOW(gv) && (sv_force_normal((SV *)gv), 0)), SvPVX(gv))
: NULL;
const
STRLEN protolen = proto ? SvCUR(gv) : 0;
const
U32 proto_utf8 = proto ? SvUTF8(gv) : 0;
SV *
const
has_constant = doproto && SvROK(gv) ? SvRV(gv) : NULL;
const
U32 exported_constant = has_constant ? SvPCS_IMPORTED(gv) : 0;
const
bool
really_sub =
has_constant && SvTYPE(has_constant) == SVt_PVCV;
COP *
const
old = PL_curcop;
PERL_ARGS_ASSERT_GV_INIT_PVN;
assert
(!(proto && has_constant));
if
(has_constant) {
switch
(SvTYPE(has_constant)) {
case
SVt_PVHV:
case
SVt_PVFM:
case
SVt_PVIO:
Perl_croak(aTHX_
"Cannot convert a reference to %s to typeglob"
,
sv_reftype(has_constant, 0));
NOT_REACHED;
break
;
default
: NOOP;
}
SvRV_set(gv, NULL);
SvROK_off(gv);
}
if
(old_type < SVt_PVGV) {
if
(old_type >= SVt_PV)
SvCUR_set(gv, 0);
sv_upgrade(MUTABLE_SV(gv), SVt_PVGV);
}
if
(SvLEN(gv)) {
if
(proto) {
SvPV_set(gv, NULL);
}
else
{
Safefree(SvPVX_mutable(gv));
}
SvLEN_set(gv, 0);
SvPOK_off(gv);
}
SvIOK_off(gv);
isGV_with_GP_on(gv);
if
(really_sub && !CvISXSUB(has_constant) && CvSTART(has_constant)
&& ( CvSTART(has_constant)->op_type == OP_NEXTSTATE
|| CvSTART(has_constant)->op_type == OP_DBSTATE))
PL_curcop = (COP *)CvSTART(has_constant);
GvGP_set(gv, Perl_newGP(aTHX_ gv));
PL_curcop = old;
GvSTASH(gv) = stash;
if
(stash)
Perl_sv_add_backref(aTHX_ MUTABLE_SV(stash), MUTABLE_SV(gv));
gv_name_set(gv, name, len, GV_ADD | ( flags & SVf_UTF8 ? SVf_UTF8 : 0 ));
if
(flags & GV_ADDMULTI || doproto)
GvMULTI_on(gv);
if
(really_sub) {
CV *
const
cv = (CV *)has_constant;
GvCV_set(gv,cv);
if
(CvNAMED(cv) && CvSTASH(cv) == stash && (
CvNAME_HEK(cv) == GvNAME_HEK(gv)
|| ( HEK_LEN(CvNAME_HEK(cv)) == HEK_LEN(GvNAME_HEK(gv))
&& HEK_FLAGS(CvNAME_HEK(cv)) != HEK_FLAGS(GvNAME_HEK(gv))
&& HEK_UTF8(CvNAME_HEK(cv)) == HEK_UTF8(GvNAME_HEK(gv))
&& memEQ(HEK_KEY(CvNAME_HEK(cv)), GvNAME(gv), GvNAMELEN(gv))
)
))
CvGV_set(cv,gv);
}
else
if
(doproto) {
CV *cv;
if
(has_constant) {
cv = newCONSTSUB_flags(stash, name, len, flags, has_constant);
if
(!GvCV(gv))
GvCV_set(gv, (CV *)SvREFCNT_inc_simple_NN(cv));
assert
(GvCV(gv) == cv);
if
(exported_constant)
GvIMPORTED_CV_on(gv);
CvSTASH_set(cv, PL_curstash);
}
else
{
cv = newSTUB(gv,1);
}
if
(proto) {
sv_usepvn_flags(MUTABLE_SV(cv), proto, protolen,
SV_HAS_TRAILING_NUL);
if
( proto_utf8 ) SvUTF8_on(MUTABLE_SV(cv));
}
}
}
STATIC
void
S_gv_init_svtype(pTHX_ GV *gv,
const
svtype sv_type)
{
PERL_ARGS_ASSERT_GV_INIT_SVTYPE;
switch
(sv_type) {
case
SVt_PVIO:
(
void
)GvIOn(gv);
break
;
case
SVt_PVAV:
(
void
)GvAVn(gv);
break
;
case
SVt_PVHV:
(
void
)GvHVn(gv);
break
;
#ifdef PERL_DONT_CREATE_GVSV
case
SVt_NULL:
case
SVt_PVCV:
case
SVt_PVFM:
case
SVt_PVGV:
break
;
default
:
if
(GvSVn(gv)) {
}
#endif
}
}
static
void
core_xsub(pTHX_ CV* cv);
static
GV *
S_maybe_add_coresub(pTHX_ HV *
const
stash, GV *gv,
const
char
*
const
name,
const
STRLEN len)
{
const
int
code = keyword(name, len, 1);
static
const
char
file[] = __FILE__;
CV *cv, *oldcompcv = NULL;
int
opnum = 0;
bool
ampable = TRUE;
COP *oldcurcop = NULL;
yy_parser *oldparser = NULL;
I32 oldsavestack_ix = 0;
assert
(gv || stash);
assert
(name);
if
(!code)
return
NULL;
switch
(code < 0 ? -code : code) {
case
KEY___DATA__:
case
KEY___END__:
case
KEY_and:
case
KEY_AUTOLOAD:
case
KEY_BEGIN :
case
KEY_CHECK :
case
KEY_catch :
case
KEY_cmp:
case
KEY_default :
case
KEY_defer :
case
KEY_DESTROY:
case
KEY_do :
case
KEY_dump :
case
KEY_else :
case
KEY_elsif :
case
KEY_END :
case
KEY_eq :
case
KEY_eval :
case
KEY_finally:
case
KEY_for :
case
KEY_foreach:
case
KEY_format:
case
KEY_ge :
case
KEY_given :
case
KEY_goto :
case
KEY_grep :
case
KEY_gt :
case
KEY_if :
case
KEY_isa :
case
KEY_INIT :
case
KEY_last :
case
KEY_le :
case
KEY_local :
case
KEY_lt :
case
KEY_m :
case
KEY_map :
case
KEY_my:
case
KEY_ne :
case
KEY_next :
case
KEY_no:
case
KEY_or:
case
KEY_our:
case
KEY_package:
case
KEY_print:
case
KEY_printf:
case
KEY_q :
case
KEY_qq :
case
KEY_qr :
case
KEY_qw :
case
KEY_qx :
case
KEY_redo :
case
KEY_require:
case
KEY_return:
case
KEY_s :
case
KEY_say :
case
KEY_sort :
case
KEY_state:
case
KEY_sub :
case
KEY_tr :
case
KEY_try :
case
KEY_UNITCHECK:
case
KEY_unless:
case
KEY_until:
case
KEY_use :
case
KEY_when :
case
KEY_while :
case
KEY_x :
case
KEY_xor :
case
KEY_y :
return
NULL;
case
KEY_chdir:
case
KEY_chomp:
case
KEY_chop:
case
KEY_defined:
case
KEY_delete:
case
KEY_eof :
case
KEY_exec:
case
KEY_exists :
case
KEY_lstat:
case
KEY_split:
case
KEY_stat:
case
KEY_system:
case
KEY_truncate:
case
KEY_unlink:
ampable = FALSE;
}
if
(!gv) {
gv = (GV *)newSV_type(SVt_NULL);
gv_init(gv, stash, name, len, TRUE);
}
GvMULTI_on(gv);
if
(ampable) {
ENTER;
oldcurcop = PL_curcop;
oldparser = PL_parser;
lex_start(NULL, NULL, 0);
oldcompcv = PL_compcv;
PL_compcv = NULL;
oldsavestack_ix = start_subparse(FALSE,0);
cv = PL_compcv;
}
else
{
cv = MUTABLE_CV(newSV_type(SVt_PVCV));
GvCV_set(gv,cv);
GvCVGEN(gv) = 0;
CvISXSUB_on(cv);
CvXSUB(cv) = core_xsub;
PoisonPADLIST(cv);
}
CvGV_set(cv, gv);
CvFILE(cv) = (
char
*)file;
(
void
)core_prototype((SV *)cv, name, code, &opnum);
if
(stash)
(
void
)hv_store(stash,name,len,(SV *)gv,0);
if
(ampable) {
#ifdef DEBUGGING
CV *orig_cv = cv;
#endif
CvLVALUE_on(cv);
if
((cv = newATTRSUB_x(
oldsavestack_ix, (OP *)gv,
NULL,NULL,
coresub_op(
opnum
? newSVuv((UV)opnum)
: newSVpvn(name,len),
code, opnum
),
TRUE
)) != NULL) {
assert
(GvCV(gv) == orig_cv);
if
(opnum != OP_VEC && opnum != OP_SUBSTR && opnum != OP_POS
&& opnum != OP_UNDEF && opnum != OP_KEYS)
CvLVALUE_off(cv);
}
LEAVE;
PL_parser = oldparser;
PL_curcop = oldcurcop;
PL_compcv = oldcompcv;
}
if
(cv) {
SV *opnumsv = newSViv(
(opnum == OP_ENTEREVAL && len == 9 && memEQ(name,
"evalbytes"
, 9)) ?
(OP_ENTEREVAL | (1<<16))
: opnum ? opnum : (((I32)name[2]) << 16));
cv_set_call_checker_flags(cv, Perl_ck_entersub_args_core, opnumsv, 0);
SvREFCNT_dec_NN(opnumsv);
}
return
gv;
}
GV *
Perl_gv_fetchmeth_sv(pTHX_ HV *stash, SV *namesv, I32 level, U32 flags)
{
char
*namepv;
STRLEN namelen;
PERL_ARGS_ASSERT_GV_FETCHMETH_SV;
if
(LIKELY(SvPOK_nog(namesv)))
return
gv_fetchmeth_internal(stash, namesv, NULL, 0, level,
flags | SvUTF8(namesv));
namepv = SvPV(namesv, namelen);
if
(SvUTF8(namesv)) flags |= SVf_UTF8;
return
gv_fetchmeth_pvn(stash, namepv, namelen, level, flags);
}
GV *
Perl_gv_fetchmeth_pv(pTHX_ HV *stash,
const
char
*name, I32 level, U32 flags)
{
PERL_ARGS_ASSERT_GV_FETCHMETH_PV;
return
gv_fetchmeth_internal(stash, NULL, name,
strlen
(name), level, flags);
}
PERL_STATIC_INLINE GV*
S_gv_fetchmeth_internal(pTHX_ HV* stash, SV* meth,
const
char
* name, STRLEN len, I32 level, U32 flags)
{
GV** gvp;
HE* he;
AV* linear_av;
SV** linear_svp;
SV* linear_sv;
HV* cstash, *cachestash;
GV* candidate = NULL;
CV* cand_cv = NULL;
GV* topgv = NULL;
const
char
*hvname;
STRLEN hvnamelen;
I32 create = (level >= 0) ? HV_FETCH_LVALUE : 0;
I32 items;
U32 topgen_cmp;
U32 is_utf8 = flags & SVf_UTF8;
if
(!stash) {
create = 0;
if
(!(stash = gv_stashpvs(
"UNIVERSAL"
, 0)))
return
0;
}
assert
(stash);
hvname = HvNAME_get(stash);
hvnamelen = HvNAMELEN_get(stash);
if
(!hvname)
Perl_croak(aTHX_
"Can't use anonymous symbol table for method lookup"
);
assert
(hvname);
assert
(name || meth);
DEBUG_o( Perl_deb(aTHX_
"Looking for %smethod %s in package %s\n"
,
flags & GV_SUPER ?
"SUPER "
:
""
,
name ? name : SvPV_nolen(meth), hvname) );
topgen_cmp = HvMROMETA(stash)->cache_gen + PL_sub_generation;
if
(flags & GV_SUPER) {
if
(!HvAUX(stash)->xhv_mro_meta->super)
HvAUX(stash)->xhv_mro_meta->super = newHV();
cachestash = HvAUX(stash)->xhv_mro_meta->super;
}
else
cachestash = stash;
he = (HE*)hv_common(
cachestash, meth, name, len, is_utf8 ? HVhek_UTF8 : 0, create, NULL, 0
);
if
(he) gvp = (GV**)&HeVAL(he);
else
gvp = NULL;
if
(gvp) {
topgv = *gvp;
have_gv:
assert
(topgv);
if
(SvTYPE(topgv) != SVt_PVGV)
{
if
(!name)
name = SvPV_nomg(meth, len);
gv_init_pvn(topgv, stash, name, len, GV_ADDMULTI|is_utf8);
}
if
((cand_cv = GvCV(topgv))) {
if
(!GvCVGEN(topgv) || GvCVGEN(topgv) == topgen_cmp) {
return
topgv;
}
else
{
SvREFCNT_dec_NN(cand_cv);
GvCV_set(topgv, NULL);
cand_cv = NULL;
GvCVGEN(topgv) = 0;
}
}
else
if
(GvCVGEN(topgv) == topgen_cmp) {
return
0;
}
else
if
(stash == cachestash
&& len > 1
&& memEQs(hvname, HvNAMELEN_get(stash),
"CORE"
)
&& S_maybe_add_coresub(aTHX_ NULL,topgv,name,len))
goto
have_gv;
}
linear_av = mro_get_linear_isa(stash);
linear_svp = AvARRAY(linear_av) + 1;
items = AvFILLp(linear_av);
while
(items--) {
linear_sv = *linear_svp++;
assert
(linear_sv);
cstash = gv_stashsv(linear_sv, 0);
if
(!cstash) {
if
( ckWARN(WARN_SYNTAX)) {
if
(
( len && name[0] ==
'('
)
|| ( memEQs( name, len,
"DESTROY"
) )
) {
Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
"Can't locate package %"
SVf
" for @%"
HEKf
"::ISA"
,
SVfARG(linear_sv),
HEKfARG(HvNAME_HEK(stash)));
}
else
if
( memEQs( name, len,
"AUTOLOAD"
) ) {
}
else
{
Perl_ck_warner(aTHX_ packWARN(WARN_SYNTAX),
"While trying to resolve method call %.*s->%.*s()"
" can not locate package \"%"
SVf
"\" yet it is mentioned in @%.*s::ISA"
" (perhaps you forgot to load \"%"
SVf
"\"?)"
,
(
int
) hvnamelen, hvname,
(
int
) len, name,
SVfARG(linear_sv),
(
int
) hvnamelen, hvname,
SVfARG(linear_sv));
}
}
continue
;
}
assert
(cstash);
gvp = (GV**)hv_common(
cstash, meth, name, len, is_utf8 ? HVhek_UTF8 : 0, HV_FETCH_JUST_SV, NULL, 0
);
if
(!gvp) {
if
(len > 1 && HvNAMELEN_get(cstash) == 4) {
const
char
*hvname = HvNAME(cstash);
assert
(hvname);
if
(strBEGINs(hvname,
"CORE"
)
&& (candidate =
S_maybe_add_coresub(aTHX_ cstash,NULL,name,len)
))
goto
have_candidate;
}
continue
;
}
else
candidate = *gvp;
have_candidate:
assert
(candidate);
if
(SvTYPE(candidate) != SVt_PVGV)
gv_init_pvn(candidate, cstash, name, len, GV_ADDMULTI|is_utf8);
if
(SvTYPE(candidate) == SVt_PVGV && (cand_cv = GvCV(candidate)) && !GvCVGEN(candidate)) {
if
(topgv && (GvREFCNT(topgv) == 1) && (CvROOT(cand_cv) || CvXSUB(cand_cv))) {
CV *old_cv = GvCV(topgv);
SvREFCNT_dec(old_cv);
SvREFCNT_inc_simple_void_NN(cand_cv);
GvCV_set(topgv, cand_cv);
GvCVGEN(topgv) = topgen_cmp;
}
return
candidate;
}
}
if
((level == 0 || level == -1) && !(flags & GV_NOUNIVERSAL)) {
candidate = gv_fetchmeth_internal(NULL, meth, name, len, 1,
flags &~GV_SUPER);
if
(candidate) {
cand_cv = GvCV(candidate);
if
(topgv && (GvREFCNT(topgv) == 1) && (CvROOT(cand_cv) || CvXSUB(cand_cv))) {
CV *old_cv = GvCV(topgv);
SvREFCNT_dec(old_cv);
SvREFCNT_inc_simple_void_NN(cand_cv);
GvCV_set(topgv, cand_cv);
GvCVGEN(topgv) = topgen_cmp;
}
return
candidate;
}
}
if
(topgv && GvREFCNT(topgv) == 1) {
GvCVGEN(topgv) = topgen_cmp;
}
return
0;
}
GV *
Perl_gv_fetchmeth_pvn(pTHX_ HV *stash,
const
char
*name, STRLEN len, I32 level, U32 flags)
{
PERL_ARGS_ASSERT_GV_FETCHMETH_PVN;
return
gv_fetchmeth_internal(stash, NULL, name, len, level, flags);
}
GV *
Perl_gv_fetchmeth_sv_autoload(pTHX_ HV *stash, SV *namesv, I32 level, U32 flags)
{
char
*namepv;
STRLEN namelen;
PERL_ARGS_ASSERT_GV_FETCHMETH_SV_AUTOLOAD;
namepv = SvPV(namesv, namelen);
if
(SvUTF8(namesv))
flags |= SVf_UTF8;
return
gv_fetchmeth_pvn_autoload(stash, namepv, namelen, level, flags);
}
GV *
Perl_gv_fetchmeth_pv_autoload(pTHX_ HV *stash,
const
char
*name, I32 level, U32 flags)
{
PERL_ARGS_ASSERT_GV_FETCHMETH_PV_AUTOLOAD;
return
gv_fetchmeth_pvn_autoload(stash, name,
strlen
(name), level, flags);
}
GV *
Perl_gv_fetchmeth_pvn_autoload(pTHX_ HV *stash,
const
char
*name, STRLEN len, I32 level, U32 flags)
{
GV *gv = gv_fetchmeth_pvn(stash, name, len, level, flags);
PERL_ARGS_ASSERT_GV_FETCHMETH_PVN_AUTOLOAD;
if
(!gv) {
CV *cv;
GV **gvp;
if
(!stash)
return
NULL;
if
(len == S_autolen && memEQ(name, S_autoload, S_autolen))
return
NULL;
if
(!(gv = gv_fetchmeth_pvn(stash, S_autoload, S_autolen, FALSE, flags)))
return
NULL;
cv = GvCV(gv);
if
(!(CvROOT(cv) || CvXSUB(cv)))
return
NULL;
if
(level < 0)
gv_fetchmeth_pvn(stash, name, len, 0, flags);
gvp = (GV**)hv_fetch(stash, name,
(flags & SVf_UTF8) ? -(I32)len : (I32)len, (level >= 0));
if
(!gvp)
return
NULL;
return
*gvp;
}
return
gv;
}
GV *
Perl_gv_fetchmethod_autoload(pTHX_ HV *stash,
const
char
*name, I32 autoload)
{
PERL_ARGS_ASSERT_GV_FETCHMETHOD_AUTOLOAD;
return
gv_fetchmethod_flags(stash, name, autoload ? GV_AUTOLOAD : 0);
}
GV *
Perl_gv_fetchmethod_sv_flags(pTHX_ HV *stash, SV *namesv, U32 flags)
{
char
*namepv;
STRLEN namelen;
PERL_ARGS_ASSERT_GV_FETCHMETHOD_SV_FLAGS;
namepv = SvPV(namesv, namelen);
if
(SvUTF8(namesv))
flags |= SVf_UTF8;
return
gv_fetchmethod_pvn_flags(stash, namepv, namelen, flags);
}
GV *
Perl_gv_fetchmethod_pv_flags(pTHX_ HV *stash,
const
char
*name, U32 flags)
{
PERL_ARGS_ASSERT_GV_FETCHMETHOD_PV_FLAGS;
return
gv_fetchmethod_pvn_flags(stash, name,
strlen
(name), flags);
}
GV *
Perl_gv_fetchmethod_pvn_flags(pTHX_ HV *stash,
const
char
*name,
const
STRLEN len, U32 flags)
{
const
char
*
const
origname = name;
const
char
*
const
name_end = name + len;
const
char
*last_separator = NULL;
GV* gv;
HV* ostash = stash;
SV *
const
error_report = MUTABLE_SV(stash);
const
U32 autoload = flags & GV_AUTOLOAD;
const
U32 do_croak = flags & GV_CROAK;
const
U32 is_utf8 = flags & SVf_UTF8;
PERL_ARGS_ASSERT_GV_FETCHMETHOD_PVN_FLAGS;
if
(SvTYPE(stash) < SVt_PVHV)
stash = NULL;
else
{
}
{
const
char
*name_cursor = name;
const
char
*
const
name_em1 = name_end - 1;
for
(name_cursor = name; name_cursor < name_end ; name_cursor++) {
if
(*name_cursor ==
'\''
) {
last_separator = name_cursor;
name = name_cursor + 1;
}
else
if
(name_cursor < name_em1 && *name_cursor ==
':'
&& name_cursor[1] ==
':'
) {
last_separator = name_cursor++;
name = name_cursor + 1;
}
}
}
if
(last_separator) {
STRLEN sep_len= last_separator - origname;
if
( memEQs(origname, sep_len,
"SUPER"
)) {
stash = CopSTASH(PL_curcop);
flags |= GV_SUPER;
DEBUG_o( Perl_deb(aTHX_
"Treating %s as %s::%s\n"
,
origname, HvENAME_get(stash), name) );
}
else
if
( sep_len >= 7 &&
strBEGINs(last_separator - 7,
"::SUPER"
)) {
stash = gv_stashpvn(origname, sep_len - 7, is_utf8);
if
(stash) flags |= GV_SUPER;
}
else
{
stash = gv_stashpvn(origname, sep_len, is_utf8);
}
ostash = stash;
}
gv = gv_fetchmeth_pvn(stash, name, name_end - name, 0, flags);
if
(!gv) {
if
(strEQ(name,
"import"
) || strEQ(name,
"unimport"
)) {
gv = (GV*)sv_2mortal((SV*)newCONSTSUB_flags(NULL,
NULL, 0, 0, NULL));
}
else
if
(autoload)
gv = gv_autoload_pvn(
ostash, name, name_end - name, GV_AUTOLOAD_ISMETHOD|flags
);
if
(!gv && do_croak) {
if
(stash) {
const
char
*stash_name = HvNAME_get(stash);
if
(stash_name && memEQs(stash_name, HvNAMELEN_get(stash),
"IO::File"
)
&& !Perl_hv_common(aTHX_ GvHVn(PL_incgv), NULL,
STR_WITH_LEN(
"IO/File.pm"
), 0,
HV_FETCH_ISEXISTS, NULL, 0)
) {
require_pv(
"IO/File.pm"
);
gv = gv_fetchmeth_pvn(stash, name, name_end - name, 0, flags);
if
(gv)
return
gv;
}
Perl_croak(aTHX_
"Can't locate object method \"%"
UTF8f
"\" via package \"%"
HEKf
"\""
,
UTF8fARG(is_utf8, name_end - name, name),
HEKfARG(HvNAME_HEK(stash)));
}
else
{
SV* packnamesv;
if
(last_separator) {
packnamesv = newSVpvn_flags(origname, last_separator - origname,
SVs_TEMP | is_utf8);
}
else
{
packnamesv = error_report;
}
Perl_croak(aTHX_
"Can't locate object method \"%"
UTF8f
"\" via package \"%"
SVf
"\""
" (perhaps you forgot to load \"%"
SVf
"\"?)"
,
UTF8fARG(is_utf8, name_end - name, name),
SVfARG(packnamesv), SVfARG(packnamesv));
}
}
}
else
if
(autoload) {
CV*
const
cv = GvCV(gv);
if
(!CvROOT(cv) && !CvXSUB(cv)) {
GV* stubgv;
GV* autogv;
if
(CvANON(cv) || CvLEXICAL(cv))
stubgv = gv;
else
{
stubgv = CvGV(cv);
if
(GvCV(stubgv) != cv)
stubgv = gv;
}
autogv = gv_autoload_pvn(GvSTASH(stubgv),
GvNAME(stubgv), GvNAMELEN(stubgv),
GV_AUTOLOAD_ISMETHOD
| (GvNAMEUTF8(stubgv) ? SVf_UTF8 : 0));
if
(autogv)
gv = autogv;
}
}
return
gv;
}
GV*
Perl_gv_autoload_sv(pTHX_ HV *stash, SV* namesv, U32 flags)
{
char
*namepv;
STRLEN namelen;
PERL_ARGS_ASSERT_GV_AUTOLOAD_SV;
namepv = SvPV(namesv, namelen);
if
(SvUTF8(namesv))
flags |= SVf_UTF8;
return
gv_autoload_pvn(stash, namepv, namelen, flags);
}
GV*
Perl_gv_autoload_pv(pTHX_ HV *stash,
const
char
*namepv, U32 flags)
{
PERL_ARGS_ASSERT_GV_AUTOLOAD_PV;
return
gv_autoload_pvn(stash, namepv,
strlen
(namepv), flags);
}
GV*
Perl_gv_autoload_pvn(pTHX_ HV *stash,
const
char
*name, STRLEN len, U32 flags)
{
GV* gv;
CV* cv;
HV* varstash;
GV* vargv;
SV* varsv;
SV *packname = NULL;
U32 is_utf8 = flags & SVf_UTF8 ? SVf_UTF8 : 0;
PERL_ARGS_ASSERT_GV_AUTOLOAD_PVN;
if
(len == S_autolen && memEQ(name, S_autoload, S_autolen))
return
NULL;
if
(stash) {
if
(SvTYPE(stash) < SVt_PVHV) {
STRLEN packname_len = 0;
const
char
*
const
packname_ptr = SvPV_const(MUTABLE_SV(stash), packname_len);
packname = newSVpvn_flags(packname_ptr, packname_len,
SVs_TEMP | SvUTF8(stash));
stash = NULL;
}
else
packname = sv_2mortal(newSVhek(HvNAME_HEK(stash)));
if
(flags & GV_SUPER) sv_catpvs(packname,
"::SUPER"
);
}
if
(!(gv = gv_fetchmeth_pvn(stash, S_autoload, S_autolen, FALSE,
is_utf8 | (flags & GV_SUPER))))
return
NULL;
cv = GvCV(gv);
if
(!(CvROOT(cv) || CvXSUB(cv)))
return
NULL;
if
(
!(flags & GV_AUTOLOAD_ISMETHOD)
&& (GvCVGEN(gv) || GvSTASH(gv) != stash)
)
Perl_croak(aTHX_
"Use of inherited AUTOLOAD for non-method %"
SVf
"::%"
UTF8f
"() is no longer allowed"
,
SVfARG(packname),
UTF8fARG(is_utf8, len, name));
if
(CvISXSUB(cv)) {
CvSTASH_set(cv, stash);
if
(SvPOK(cv)) {
SV *
const
tmpsv = newSVpvn_flags(name, len, is_utf8);
STRLEN ulen;
const
char
*proto = CvPROTO(cv);
assert
(proto);
if
(SvUTF8(cv))
sv_utf8_upgrade_flags_grow(tmpsv, 0, CvPROTOLEN(cv) + 2);
ulen = SvCUR(tmpsv);
SvCUR_set(tmpsv, SvCUR(tmpsv) + 1);
sv_catpvn_flags(
tmpsv, proto, CvPROTOLEN(cv), SV_CATBYTES*!SvUTF8(cv)
);
SvTEMP_on(tmpsv);
sv_setsv_nomg((SV *)cv, tmpsv);
SvTEMP_off(tmpsv);
SvREFCNT_dec_NN(tmpsv);
SvLEN_set(cv, SvCUR(cv) + 1);
SvCUR_set(cv, ulen);
}
else
{
sv_setpvn((SV *)cv, name, len);
SvPOK_off(cv);
if
(is_utf8)
SvUTF8_on(cv);
else
SvUTF8_off(cv);
}
CvAUTOLOAD_on(cv);
}
varstash = CvNAMED(cv) ? CvSTASH(cv) : GvSTASH(CvGV(cv));
vargv = *(GV**)hv_fetch(varstash, S_autoload, S_autolen, TRUE);
ENTER;
if
(!isGV(vargv)) {
gv_init_pvn(vargv, varstash, S_autoload, S_autolen, 0);
#ifdef PERL_DONT_CREATE_GVSV
GvSV(vargv) = newSV_type(SVt_NULL);
#endif
}
LEAVE;
varsv = GvSVn(vargv);
SvTAINTED_off(varsv);
sv_setsv(varsv, packname);
sv_catpvs(varsv,
"::"
);
sv_catpvn_flags(
varsv, name, len,
SV_SMAGIC|(is_utf8 ? SV_CATUTF8 : SV_CATBYTES)
);
if
(is_utf8)
SvUTF8_on(varsv);
return
gv;
}
STATIC
void
S_require_tie_mod(pTHX_ GV *gv,
const
char
varname,
const
char
* name,
STRLEN len,
const
U32 flags)
{
const
SV *
const
target = varname ==
'['
? GvSV(gv) : (SV *)GvHV(gv);
PERL_ARGS_ASSERT_REQUIRE_TIE_MOD;
if
(!target || !SvRMAGICAL(target)
|| !mg_find(target,
varname ==
'['
? PERL_MAGIC_tiedscalar : PERL_MAGIC_tied))
{
HV *stash;
GV **gvp;
dSP;
PUSHSTACKi(PERLSI_MAGIC);
ENTER;
#define GET_HV_FETCH_TIE_FUNC \
( (gvp = (GV **)hv_fetchs(stash,
"_tie_it"
, 0)) \
&& *gvp \
&& ( (isGV(*gvp) && GvCV(*gvp)) \
|| (SvROK(*gvp) && SvTYPE(SvRV(*gvp)) == SVt_PVCV) ) \
)
if
(!(stash = gv_stashpvn(name, len, 0))
|| ! GET_HV_FETCH_TIE_FUNC)
{
SV *
const
module = newSVpvn(name, len);
const
char
type = varname ==
'['
?
'$'
:
'%'
;
if
( flags & 1 )
save_scalar(gv);
Perl_load_module(aTHX_ PERL_LOADMOD_NOIMPORT, module, NULL);
assert
(sp == PL_stack_sp);
stash = gv_stashpvn(name, len, 0);
if
(!stash)
Perl_croak(aTHX_
"panic: Can't use %c%c because %s is not available"
,
type, varname, name);
else
if
(! GET_HV_FETCH_TIE_FUNC)
Perl_croak(aTHX_
"panic: Can't use %c%c because %s does not define _tie_it"
,
type, varname, name);
}
assert
(gvp);
assert
(*gvp);
PUSHMARK(SP);
XPUSHs((SV *)gv);
PUTBACK;
call_sv((SV *)*gvp, G_VOID|G_DISCARD);
LEAVE;
POPSTACK;
}
}
#define require_tie_mod_s(gv, varname, name, flags) \
S_require_tie_mod(aTHX_ gv, varname, STR_WITH_LEN(name), flags)
HV*
Perl_gv_stashpv(pTHX_
const
char
*name, I32 create)
{
PERL_ARGS_ASSERT_GV_STASHPV;
return
gv_stashpvn(name,
strlen
(name), create);
}
PERL_STATIC_INLINE HV*
S_gv_stashpvn_internal(pTHX_
const
char
*name, U32 namelen, I32 flags)
{
char
smallbuf[128];
char
*tmpbuf;
HV *stash;
GV *tmpgv;
U32 tmplen = namelen + 2;
PERL_ARGS_ASSERT_GV_STASHPVN_INTERNAL;
if
(tmplen <=
sizeof
smallbuf)
tmpbuf = smallbuf;
else
Newx(tmpbuf, tmplen,
char
);
Copy(name, tmpbuf, namelen,
char
);
tmpbuf[namelen] =
':'
;
tmpbuf[namelen+1] =
':'
;
tmpgv = gv_fetchpvn_flags(tmpbuf, tmplen, flags, SVt_PVHV);
if
(tmpbuf != smallbuf)
Safefree(tmpbuf);
if
(!tmpgv || !isGV_with_GP(tmpgv))
return
NULL;
stash = GvHV(tmpgv);
if
(!(flags & ~GV_NOADD_MASK) && !stash)
return
NULL;
assert
(stash);
if
(!HvNAME_get(stash)) {
hv_name_set(stash, name, namelen, flags & SVf_UTF8 ? SVf_UTF8 : 0 );
if
(HvAUX(GvSTASH(tmpgv))->xhv_name_count)
mro_package_moved(stash, NULL, tmpgv, 1);
}
return
stash;
}
#define PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED \
assert
(namesv || name)
HV*
Perl_gv_stashsvpvn_cached(pTHX_ SV *namesv,
const
char
*name, U32 namelen, I32 flags)
{
HV* stash;
HE* he;
PERL_ARGS_ASSERT_GV_STASHSVPVN_CACHED;
he = (HE *)hv_common(
PL_stashcache, namesv, name, namelen,
(flags & SVf_UTF8) ? HVhek_UTF8 : 0, 0, NULL, 0
);
if
(he) {
SV *sv = HeVAL(he);
HV *hv;
assert
(SvIOK(sv));
hv = INT2PTR(HV*, SvIVX(sv));
assert
(SvTYPE(hv) == SVt_PVHV);
return
hv;
}
else
if
(flags & GV_CACHE_ONLY)
return
NULL;
if
(namesv) {
if
(SvOK(namesv)) {
STRLEN len;
name = SvPV_const(namesv, len);
namelen = len;
flags |= SvUTF8(namesv);
}
else
{
name =
""
; namelen = 0;
}
}
stash = gv_stashpvn_internal(name, namelen, flags);
if
(stash && namelen) {
SV*
const
ref = newSViv(PTR2IV(stash));
(
void
)hv_store(PL_stashcache, name,
(flags & SVf_UTF8) ? -(I32)namelen : (I32)namelen, ref, 0);
}
return
stash;
}
HV*
Perl_gv_stashpvn(pTHX_
const
char
*name, U32 namelen, I32 flags)
{
PERL_ARGS_ASSERT_GV_STASHPVN;
return
gv_stashsvpvn_cached(NULL, name, namelen, flags);
}
HV*
Perl_gv_stashsv(pTHX_ SV *sv, I32 flags)
{
PERL_ARGS_ASSERT_GV_STASHSV;
return
gv_stashsvpvn_cached(sv, NULL, 0, flags);
}
GV *
Perl_gv_fetchpv(pTHX_
const
char
*nambeg, I32 flags,
const
svtype sv_type) {
PERL_ARGS_ASSERT_GV_FETCHPV;
return
gv_fetchpvn_flags(nambeg,
strlen
(nambeg), flags, sv_type);
}
GV *
Perl_gv_fetchsv(pTHX_ SV *name, I32 flags,
const
svtype sv_type) {
STRLEN len;
const
char
*
const
nambeg =
SvPV_flags_const(name, len, flags & GV_NO_SVGMAGIC ? 0 : SV_GMAGIC);
PERL_ARGS_ASSERT_GV_FETCHSV;
return
gv_fetchpvn_flags(nambeg, len, flags | SvUTF8(name), sv_type);
}
PERL_STATIC_INLINE
void
S_gv_magicalize_isa(pTHX_ GV *gv)
{
AV* av;
PERL_ARGS_ASSERT_GV_MAGICALIZE_ISA;
av = GvAVn(gv);
GvMULTI_on(gv);
sv_magic(MUTABLE_SV(av), MUTABLE_SV(gv), PERL_MAGIC_isa,
NULL, 0);
}
PERL_STATIC_INLINE
bool
S_parse_gv_stash_name(pTHX_ HV **stash, GV **gv,
const
char
**name,
STRLEN *len,
const
char
*nambeg, STRLEN full_len,
const
U32 is_utf8,
const
I32 add)
{
char
*tmpfullbuf = NULL;
const
char
*name_cursor;
const
char
*
const
name_end = nambeg + full_len;
const
char
*
const
name_em1 = name_end - 1;
char
smallbuf[64];
PERL_ARGS_ASSERT_PARSE_GV_STASH_NAME;
if
( full_len > 2
&& **name ==
'*'
&& isIDFIRST_lazy_if_safe(*name + 1, name_end, is_utf8))
{
(*name)++;
}
for
(name_cursor = *name; name_cursor < name_end; name_cursor++) {
if
(name_cursor < name_em1 &&
((*name_cursor ==
':'
&& name_cursor[1] ==
':'
)
|| *name_cursor ==
'\''
))
{
if
(!*stash)
*stash = PL_defstash;
if
(!*stash || !SvREFCNT(*stash))
goto
notok;
*len = name_cursor - *name;
if
(name_cursor > nambeg) {
const
char
*key;
GV**gvp;
if
(*name_cursor ==
':'
) {
key = *name;
*len += 2;
}
else
{
char
*tmpbuf;
if
( *len+2 <=
sizeof
smallbuf)
tmpbuf = smallbuf;
else
{
if
(tmpfullbuf == NULL)
Newx(tmpfullbuf, full_len+2,
char
);
tmpbuf = tmpfullbuf;
}
Copy(*name, tmpbuf, *len,
char
);
tmpbuf[(*len)++] =
':'
;
tmpbuf[(*len)++] =
':'
;
key = tmpbuf;
}
gvp = (GV**)hv_fetch(*stash, key, is_utf8 ? -((I32)*len) : (I32)*len, add);
*gv = gvp ? *gvp : NULL;
if
(!*gv || *gv == (
const
GV *)&PL_sv_undef) {
goto
notok;
}
if
(SvTYPE(*gv) != SVt_PVGV)
gv_init_pvn(*gv, *stash, key, *len, (add & GV_ADDMULTI)|is_utf8);
else
GvMULTI_on(*gv);
if
(!(*stash = GvHV(*gv))) {
*stash = GvHV(*gv) = newHV();
if
(!HvNAME_get(*stash)) {
if
(GvSTASH(*gv) == PL_defstash && *len == 6
&& strBEGINs(*name,
"CORE"
))
hv_name_sets(*stash,
"CORE"
, 0);
else
hv_name_set(
*stash, nambeg, name_cursor-nambeg, is_utf8
);
if
(HvAUX(GvSTASH(*gv))->xhv_name_count)
mro_package_moved(*stash, NULL, *gv, 1);
}
}
else
if
(!HvNAME_get(*stash))
hv_name_set(*stash, nambeg, name_cursor - nambeg, is_utf8);
}
if
(*name_cursor ==
':'
)
name_cursor++;
*name = name_cursor+1;
if
(*name == name_end) {
if
(!*gv) {
*gv = MUTABLE_GV(*hv_fetchs(PL_defstash,
"main::"
, TRUE));
if
(SvTYPE(*gv) != SVt_PVGV) {
gv_init_pvn(*gv, PL_defstash,
"main::"
, 6,
GV_ADDMULTI);
GvHV(*gv) =
MUTABLE_HV(SvREFCNT_inc_simple(PL_defstash));
}
}
goto
ok;
}
}
}
*len = name_cursor - *name;
ok:
Safefree(tmpfullbuf);
return
TRUE;
notok:
Safefree(tmpfullbuf);
return
FALSE;
}
PERL_STATIC_INLINE
bool
S_gv_is_in_main(pTHX_
const
char
*name, STRLEN len,
const
U32 is_utf8)
{
PERL_ARGS_ASSERT_GV_IS_IN_MAIN;
if
( len && isIDFIRST_lazy_if_safe(name, name + len, is_utf8) ) {
switch
(len) {
case
1:
if
(*name ==
'_'
)
return
TRUE;
break
;
case
3:
if
((name[0] ==
'I'
&& name[1] ==
'N'
&& name[2] ==
'C'
)
|| (name[0] ==
'E'
&& name[1] ==
'N'
&& name[2] ==
'V'
)
|| (name[0] ==
'S'
&& name[1] ==
'I'
&& name[2] ==
'G'
))
return
TRUE;
break
;
case
4:
if
(name[0] ==
'A'
&& name[1] ==
'R'
&& name[2] ==
'G'
&& name[3] ==
'V'
)
return
TRUE;
break
;
case
5:
if
(name[0] ==
'S'
&& name[1] ==
'T'
&& name[2] ==
'D'
&& name[3] ==
'I'
&& name[4] ==
'N'
)
return
TRUE;
break
;
case
6:
if
((name[0] ==
'S'
&& name[1] ==
'T'
&& name[2] ==
'D'
)
&&((name[3] ==
'O'
&& name[4] ==
'U'
&& name[5] ==
'T'
)
||(name[3] ==
'E'
&& name[4] ==
'R'
&& name[5] ==
'R'
)))
return
TRUE;
break
;
case
7:
if
(name[0] ==
'A'
&& name[1] ==
'R'
&& name[2] ==
'G'
&& name[3] ==
'V'
&& name[4] ==
'O'
&& name[5] ==
'U'
&& name[6] ==
'T'
)
return
TRUE;
break
;
}
}
else
return
TRUE;
return
FALSE;
}
PERL_STATIC_INLINE
bool
S_find_default_stash(pTHX_ HV **stash,
const
char
*name, STRLEN len,
const
U32 is_utf8,
const
I32 add,
const
svtype sv_type)
{
PERL_ARGS_ASSERT_FIND_DEFAULT_STASH;
if
( gv_is_in_main(name, len, is_utf8) ) {
*stash = PL_defstash;
}
else
{
if
(IN_PERL_COMPILETIME) {
*stash = PL_curstash;
if
(add && (PL_hints & HINT_STRICT_VARS) &&
sv_type != SVt_PVCV &&
sv_type != SVt_PVGV &&
sv_type != SVt_PVFM &&
sv_type != SVt_PVIO &&
!(len == 1 && sv_type == SVt_PV &&
(*name ==
'a'
|| *name ==
'b'
)) )
{
GV**gvp = (GV**)hv_fetch(*stash,name,is_utf8 ? -(I32)len : (I32)len,0);
if
(!gvp || *gvp == (
const
GV *)&PL_sv_undef ||
SvTYPE(*gvp) != SVt_PVGV)
{
*stash = NULL;
}
else
if
((sv_type == SVt_PV && !GvIMPORTED_SV(*gvp)) ||
(sv_type == SVt_PVAV && !GvIMPORTED_AV(*gvp)) ||
(sv_type == SVt_PVHV && !GvIMPORTED_HV(*gvp)) )
{
Perl_ck_warner_d(
aTHX_ packWARN(WARN_MISC),
"Variable \"%c%"
UTF8f
"\" is not imported"
,
sv_type == SVt_PVAV ?
'@'
:
sv_type == SVt_PVHV ?
'%'
:
'$'
,
UTF8fARG(is_utf8, len, name));
if
(GvCVu(*gvp))
Perl_ck_warner_d(
aTHX_ packWARN(WARN_MISC),
"\t(Did you mean &%"
UTF8f
" instead?)\n"
,
UTF8fARG(is_utf8, len, name)
);
*stash = NULL;
}
}
}
else
{
*stash = CopSTASH(PL_curcop);
}
}
if
(!*stash) {
if
(add && !PL_in_clean_all) {
GV *gv;
qerror(Perl_mess(aTHX_
"Global symbol \"%s%"
UTF8f
"\" requires explicit package name (did you forget to "
"declare \"my %s%"
UTF8f
"\"?)"
,
(sv_type == SVt_PV ?
"$"
: sv_type == SVt_PVAV ?
"@"
: sv_type == SVt_PVHV ?
"%"
:
""
), UTF8fARG(is_utf8, len, name),
(sv_type == SVt_PV ?
"$"
: sv_type == SVt_PVAV ?
"@"
: sv_type == SVt_PVHV ?
"%"
:
""
), UTF8fARG(is_utf8, len, name)));
gv = gv_fetchpvs(
"<none>::"
, GV_ADDMULTI, SVt_PVHV);
if
(!gv) {
return
FALSE;
}
*stash = GvHV(gv);
}
else
return
FALSE;
}
if
(!SvREFCNT(*stash))
return
FALSE;
return
TRUE;
}
#undef SvREADONLY_on
#define SvREADONLY_on(sv) (SvFLAGS(sv) |= SVf_READONLY)
PERL_STATIC_INLINE
bool
S_gv_magicalize(pTHX_ GV *gv, HV *stash,
const
char
*name, STRLEN len,
const
svtype sv_type)
{
SSize_t paren;
PERL_ARGS_ASSERT_GV_MAGICALIZE;
if
(stash != PL_defstash) {
if
(len) {
switch
(*name) {
case
'E'
:
if
(
len >= 6 && name[1] ==
'X'
&&
(memEQs(name, len,
"EXPORT"
)
||memEQs(name, len,
"EXPORT_OK"
)
||memEQs(name, len,
"EXPORT_FAIL"
)
||memEQs(name, len,
"EXPORT_TAGS"
))
)
GvMULTI_on(gv);
break
;
case
'I'
:
if
(memEQs(name, len,
"ISA"
))
gv_magicalize_isa(gv);
break
;
case
'V'
:
if
(memEQs(name, len,
"VERSION"
))
GvMULTI_on(gv);
break
;
case
'a'
:
if
(stash == PL_debstash && memEQs(name, len,
"args"
)) {
GvMULTI_on(gv_AVadd(gv));
break
;
}
case
'b'
:
if
(len == 1 && sv_type == SVt_PV)
GvMULTI_on(gv);
default
:
goto
try_core;
}
goto
ret;
}
try_core:
if
(len > 1
&& HvNAMELEN_get(stash) == 4) {
const
char
*
const
stashname = HvNAME(stash);
assert
(stashname);
if
(strBEGINs(stashname,
"CORE"
))
S_maybe_add_coresub(aTHX_ 0, gv, name, len);
}
}
else
if
(len > 1) {
#ifndef EBCDIC
if
(*name >
'V'
) {
NOOP;
}
else
#endif
{
switch
(*name) {
case
'A'
:
if
(memEQs(name, len,
"ARGV"
)) {
IoFLAGS(GvIOn(gv)) |= IOf_ARGV|IOf_START;
}
else
if
(memEQs(name, len,
"ARGVOUT"
)) {
GvMULTI_on(gv);
}
break
;
case
'E'
:
if
(
len >= 6 && name[1] ==
'X'
&&
(memEQs(name, len,
"EXPORT"
)
||memEQs(name, len,
"EXPORT_OK"
)
||memEQs(name, len,
"EXPORT_FAIL"
)
||memEQs(name, len,
"EXPORT_TAGS"
))
)
GvMULTI_on(gv);
break
;
case
'I'
:
if
(memEQs(name, len,
"ISA"
)) {
gv_magicalize_isa(gv);
}
break
;
case
'S'
:
if
(memEQs(name, len,
"SIG"
)) {
HV *hv;
I32 i;
if
(!PL_psig_name) {
Newxz(PL_psig_name, 2 * SIG_SIZE, SV*);
Newxz(PL_psig_pend, SIG_SIZE,
int
);
PL_psig_ptr = PL_psig_name + SIG_SIZE;
}
else
{
Zero(PL_psig_name, 2 * SIG_SIZE, SV*);
Zero(PL_psig_pend, SIG_SIZE,
int
);
}
GvMULTI_on(gv);
hv = GvHVn(gv);
hv_magic(hv, NULL, PERL_MAGIC_sig);
for
(i = 1; i < SIG_SIZE; i++) {
SV *
const
*
const
init = hv_fetch(hv, PL_sig_name[i],
strlen
(PL_sig_name[i]), 1);
if
(init)
sv_setsv(*init, &PL_sv_undef);
}
}
break
;
case
'V'
:
if
(memEQs(name, len,
"VERSION"
))
GvMULTI_on(gv);
break
;
case
'\003'
:
if
(memEQs(name, len,
"\003HILD_ERROR_NATIVE"
))
goto
magicalize;
if
(memEQs(name, len,
"\003APTURE"
)) {
AV*
const
av = GvAVn(gv);
const
Size_t n = *name;
sv_magic(MUTABLE_SV(av), (SV*)n, PERL_MAGIC_regdata, NULL, 0);
SvREADONLY_on(av);
require_tie_mod_s(gv,
'+'
,
"Tie::Hash::NamedCapture"
,0);
}
else
if
(memEQs(name, len,
"\003APTURE_ALL"
)) {
require_tie_mod_s(gv,
'-'
,
"Tie::Hash::NamedCapture"
,0);
}
break
;
case
'\005'
:
if
(memEQs(name, len,
"\005NCODING"
))
goto
magicalize;
break
;
case
'\007'
:
if
(memEQs(name, len,
"\007LOBAL_PHASE"
))
goto
ro_magicalize;
break
;
case
'\014'
:
if
(memEQs(name, len,
"\014AST_FH"
))
goto
ro_magicalize;
break
;
case
'\015'
:
if
(memEQs(name, len,
"\015ATCH"
)) {
paren = RX_BUFF_IDX_CARET_FULLMATCH;
goto
storeparen;
}
break
;
case
'\017'
:
if
(memEQs(name, len,
"\017PEN"
))
goto
magicalize;
break
;
case
'\020'
:
if
(memEQs(name, len,
"\020REMATCH"
)) {
paren = RX_BUFF_IDX_CARET_PREMATCH;
goto
storeparen;
}
if
(memEQs(name, len,
"\020OSTMATCH"
)) {
paren = RX_BUFF_IDX_CARET_POSTMATCH;
goto
storeparen;
}
break
;
case
'\023'
:
if
(memEQs(name, len,
"\023AFE_LOCALES"
))
goto
ro_magicalize;
break
;
case
'\024'
:
if
(memEQs(name, len,
"\024AINT"
))
goto
ro_magicalize;
break
;
case
'\025'
:
if
(memEQs(name, len,
"\025NICODE"
))
goto
ro_magicalize;
if
(memEQs(name, len,
"\025TF8LOCALE"
))
goto
ro_magicalize;
if
(memEQs(name, len,
"\025TF8CACHE"
))
goto
magicalize;
break
;
case
'\027'
:
if
(memEQs(name, len,
"\027ARNING_BITS"
))
goto
magicalize;
#ifdef WIN32
else
if
(memEQs(name, len,
"\027IN32_SLOPPY_STAT"
))
goto
magicalize;
#endif
break
;
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
{
UV uv;
if
(!grok_atoUV(name, &uv, NULL) || uv > I32_MAX)
goto
ret;
paren = (SSize_t)(I32)uv;
goto
storeparen;
}
}
}
}
else
{
switch
(*name) {
case
'&'
:
paren = RX_BUFF_IDX_FULLMATCH;
goto
sawampersand;
case
'`'
:
paren = RX_BUFF_IDX_PREMATCH;
goto
sawampersand;
case
'\''
:
paren = RX_BUFF_IDX_POSTMATCH;
sawampersand:
#ifdef PERL_SAWAMPERSAND
if
(!(
sv_type == SVt_PVAV ||
sv_type == SVt_PVHV ||
sv_type == SVt_PVCV ||
sv_type == SVt_PVFM ||
sv_type == SVt_PVIO
)) { PL_sawampersand |=
(*name ==
'`'
)
? SAWAMPERSAND_LEFT
: (*name ==
'&'
)
? SAWAMPERSAND_MIDDLE
: SAWAMPERSAND_RIGHT;
}
#endif
goto
storeparen;
case
'1'
:
case
'2'
:
case
'3'
:
case
'4'
:
case
'5'
:
case
'6'
:
case
'7'
:
case
'8'
:
case
'9'
:
paren = *name -
'0'
;
storeparen:
sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, NULL, paren);
break
;
case
':'
:
sv_setpv(GvSVn(gv),PL_chopset);
goto
magicalize;
case
'?'
:
#ifdef COMPLEX_STATUS
SvUPGRADE(GvSVn(gv), SVt_PVLV);
#endif
goto
magicalize;
case
'!'
:
GvMULTI_on(gv);
sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, name, len);
if
(sv_type == SVt_PVHV || sv_type == SVt_PVGV)
require_tie_mod_s(gv,
'!'
,
"Errno"
, 1);
break
;
case
'-'
:
case
'+'
:
GvMULTI_on(gv);
{
sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, name, len);
if
(*name ==
'+'
)
SvREADONLY_on(GvSVn(gv));
}
{
if
(sv_type == SVt_PVHV || sv_type == SVt_PVGV)
require_tie_mod_s(gv, *name,
"Tie::Hash::NamedCapture"
,0);
}
{
AV*
const
av = GvAVn(gv);
const
Size_t n = *name;
sv_magic(MUTABLE_SV(av), (SV*)n, PERL_MAGIC_regdata, NULL, 0);
SvREADONLY_on(av);
}
break
;
case
'*'
:
case
'#'
:
if
(sv_type == SVt_PV)
Perl_croak(aTHX_
"$%c is no longer supported as of Perl 5.30"
, *name);
break
;
case
'\010'
:
{
HV *
const
hv = GvHVn(gv);
hv_magic(hv, NULL, PERL_MAGIC_hints);
}
goto
magicalize;
case
'\023'
:
ro_magicalize:
SvREADONLY_on(GvSVn(gv));
case
'0'
:
case
'^'
:
case
'~'
:
case
'='
:
case
'%'
:
case
'.'
:
case
'('
:
case
')'
:
case
'<'
:
case
'>'
:
case
'\\'
:
case
'/'
:
case
'|'
:
case
'$'
:
case
'['
:
case
'\001'
:
case
'\003'
:
case
'\004'
:
case
'\005'
:
case
'\006'
:
case
'\011'
:
case
'\016'
:
case
'\017'
:
case
'\020'
:
case
'\024'
:
case
'\027'
:
magicalize:
sv_magic(GvSVn(gv), MUTABLE_SV(gv), PERL_MAGIC_sv, name, len);
break
;
case
'\014'
:
sv_setpvs(GvSVn(gv),
"\f"
);
break
;
case
';'
:
sv_setpvs(GvSVn(gv),
"\034"
);
break
;
case
']'
:
{
SV *
const
sv = GvSV(gv);
if
(!sv_derived_from(PL_patchlevel,
"version"
))
upg_version(PL_patchlevel, TRUE);
GvSV(gv) = vnumify(PL_patchlevel);
SvREADONLY_on(GvSV(gv));
SvREFCNT_dec(sv);
}
break
;
case
'\026'
:
{
SV *
const
sv = GvSV(gv);
GvSV(gv) = new_version(PL_patchlevel);
SvREADONLY_on(GvSV(gv));
SvREFCNT_dec(sv);
}
break
;
case
'a'
:
case
'b'
:
if
(sv_type == SVt_PV)
GvMULTI_on(gv);
}
}
ret:
return
GvAV(gv) || GvHV(gv) || GvIO(gv) || GvCV(gv)
|| ( GvSV(gv) && (
SvOK(GvSV(gv)) || SvMAGICAL(GvSV(gv))
)
);
}
#undef SvREADONLY_on
PERL_STATIC_INLINE
void
S_maybe_multimagic_gv(pTHX_ GV *gv,
const
char
*name,
const
svtype sv_type)
{
PERL_ARGS_ASSERT_MAYBE_MULTIMAGIC_GV;
if
(sv_type == SVt_PVHV || sv_type == SVt_PVGV) {
if
(*name ==
'!'
)
require_tie_mod_s(gv,
'!'
,
"Errno"
, 1);
else
if
(*name ==
'-'
|| *name ==
'+'
)
require_tie_mod_s(gv, *name,
"Tie::Hash::NamedCapture"
, 0);
}
else
if
(sv_type == SVt_PV) {
if
(*name ==
'*'
|| *name ==
'#'
) {
Perl_croak(aTHX_
"$%c is no longer supported as of Perl 5.30"
, *name);
}
}
if
(sv_type==SVt_PV || sv_type==SVt_PVGV) {
switch
(*name) {
#ifdef PERL_SAWAMPERSAND
case
'`'
:
PL_sawampersand |= SAWAMPERSAND_LEFT;
(
void
)GvSVn(gv);
break
;
case
'&'
:
PL_sawampersand |= SAWAMPERSAND_MIDDLE;
(
void
)GvSVn(gv);
break
;
case
'\''
:
PL_sawampersand |= SAWAMPERSAND_RIGHT;
(
void
)GvSVn(gv);
break
;
#endif
}
}
}
GV *
Perl_gv_fetchpvn_flags(pTHX_
const
char
*nambeg, STRLEN full_len, I32 flags,
const
svtype sv_type)
{
const
char
*name = nambeg;
GV *gv = NULL;
GV**gvp;
STRLEN len;
HV *stash = NULL;
const
I32 no_init = flags & (GV_NOADD_NOINIT | GV_NOINIT);
const
I32 no_expand = flags & GV_NOEXPAND;
const
I32 add = flags & ~GV_NOADD_MASK;
const
U32 is_utf8 = flags & SVf_UTF8;
bool
addmg = cBOOL(flags & GV_ADDMG);
const
char
*
const
name_end = nambeg + full_len;
U32 faking_it;
PERL_ARGS_ASSERT_GV_FETCHPVN_FLAGS;
if
((flags & GV_NOTQUAL) || !full_len) {
len = full_len;
}
else
if
(parse_gv_stash_name(&stash, &gv, &name, &len, nambeg, full_len, is_utf8, add)) {
if
(name == name_end)
return
gv;
}
else
{
return
NULL;
}
if
(!stash && !find_default_stash(&stash, name, len, is_utf8, add, sv_type)) {
return
NULL;
}
gvp = (GV**)hv_fetch(stash,name,is_utf8 ? -(I32)len : (I32)len,add);
if
(!gvp || *gvp == (
const
GV *)&PL_sv_undef) {
if
(addmg) gv = (GV *)newSV_type(SVt_NULL);
else
return
NULL;
}
else
gv = *gvp, addmg = 0;
if
(SvTYPE(gv) == SVt_PVGV) {
if
(add) {
GvMULTI_on(gv);
gv_init_svtype(gv, sv_type);
if
(len == 1 && stash == PL_defstash) {
maybe_multimagic_gv(gv, name, sv_type);
}
else
if
(sv_type == SVt_PVAV
&& memEQs(name, len,
"ISA"
)
&& (!GvAV(gv) || !SvSMAGICAL(GvAV(gv))))
gv_magicalize_isa(gv);
}
return
gv;
}
else
if
(no_init) {
assert
(!addmg);
return
gv;
}
else
if
(no_expand && SvROK(gv)) {
assert
(!addmg);
return
gv;
}
faking_it = SvOK(gv);
if
(add & GV_ADDWARN)
Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
"Had to create %"
UTF8f
" unexpectedly"
,
UTF8fARG(is_utf8, name_end-nambeg, nambeg));
gv_init_pvn(gv, stash, name, len, (add & GV_ADDMULTI)|is_utf8);
if
( full_len != 0
&& isIDFIRST_lazy_if_safe(name, name + full_len, is_utf8)
&& !ckWARN(WARN_ONCE) )
{
GvMULTI_on(gv) ;
}
if
( gv_magicalize(gv, stash, name, len, sv_type) ) {
if
(addmg) {
(
void
)hv_store(stash,name,len,(SV *)gv,0);
}
}
else
if
(addmg) {
SvREFCNT_dec_NN(gv);
gv = NULL;
}
if
(gv) gv_init_svtype(gv, faking_it ? SVt_PVCV : sv_type);
return
gv;
}
void
Perl_gv_fullname4(pTHX_ SV *sv,
const
GV *gv,
const
char
*prefix,
bool
keepmain)
{
const
char
*name;
const
HV *
const
hv = GvSTASH(gv);
PERL_ARGS_ASSERT_GV_FULLNAME4;
sv_setpv(sv, prefix ? prefix :
""
);
if
(hv && (name = HvNAME(hv))) {
const
STRLEN len = HvNAMELEN(hv);
if
(keepmain || ! memBEGINs(name, len,
"main"
)) {
sv_catpvn_flags(sv,name,len,HvNAMEUTF8(hv)?SV_CATUTF8:SV_CATBYTES);
sv_catpvs(sv,
"::"
);
}
}
else
sv_catpvs(sv,
"__ANON__::"
);
sv_catsv(sv,sv_2mortal(newSVhek(GvNAME_HEK(gv))));
}
void
Perl_gv_efullname4(pTHX_ SV *sv,
const
GV *gv,
const
char
*prefix,
bool
keepmain)
{
const
GV *
const
egv = GvEGVx(gv);
PERL_ARGS_ASSERT_GV_EFULLNAME4;
gv_fullname4(sv, egv ? egv : gv, prefix, keepmain);
}
void
Perl_gv_check(pTHX_ HV *stash)
{
I32 i;
PERL_ARGS_ASSERT_GV_CHECK;
if
(!SvOOK(stash))
return
;
assert
(HvARRAY(stash));
HvAUX(stash)->xhv_aux_flags |= HvAUXf_SCAN_STASH;
for
(i = 0; i <= (I32) HvMAX(stash); i++) {
const
HE *entry;
for
(entry = HvARRAY(stash)[i]; entry; entry = HeNEXT(entry)) {
GV *gv;
HV *hv;
STRLEN keylen = HeKLEN(entry);
const
char
*
const
key = HeKEY(entry);
if
(keylen >= 2 && key[keylen-2] ==
':'
&& key[keylen-1] ==
':'
&&
(gv = MUTABLE_GV(HeVAL(entry))) && isGV(gv) && (hv = GvHV(gv)))
{
if
(hv != PL_defstash && hv != stash
&& !(SvOOK(hv)
&& (HvAUX(hv)->xhv_aux_flags & HvAUXf_SCAN_STASH))
)
gv_check(hv);
}
else
if
( HeKLEN(entry) != 0
&& *HeKEY(entry) !=
'_'
&& isIDFIRST_lazy_if_safe(HeKEY(entry),
HeKEY(entry) + HeKLEN(entry),
HeUTF8(entry)) )
{
const
char
*file;
gv = MUTABLE_GV(HeVAL(entry));
if
(SvTYPE(gv) != SVt_PVGV || GvMULTI(gv))
continue
;
file = GvFILE(gv);
CopLINE_set(PL_curcop, GvLINE(gv));
#ifdef USE_ITHREADS
CopFILE(PL_curcop) = (
char
*)file;
#else
CopFILEGV(PL_curcop)
= gv_fetchfile_flags(file, HEK_LEN(GvFILE_HEK(gv)), 0);
#endif
Perl_warner(aTHX_ packWARN(WARN_ONCE),
"Name \"%"
HEKf
"::%"
HEKf
"\" used only once: possible typo"
,
HEKfARG(HvNAME_HEK(stash)),
HEKfARG(GvNAME_HEK(gv)));
}
}
}
HvAUX(stash)->xhv_aux_flags &= ~HvAUXf_SCAN_STASH;
}
GV *
Perl_newGVgen_flags(pTHX_
const
char
*pack, U32 flags)
{
PERL_ARGS_ASSERT_NEWGVGEN_FLAGS;
assert
(!(flags & ~SVf_UTF8));
return
gv_fetchpv(Perl_form(aTHX_
"%"
UTF8f
"::_GEN_%ld"
,
UTF8fARG(flags,
strlen
(pack), pack),
(
long
)PL_gensym++),
GV_ADD, SVt_PVGV);
}
GP*
Perl_gp_ref(pTHX_ GP *gp)
{
if
(!gp)
return
NULL;
gp->gp_refcnt++;
if
(gp->gp_cv) {
if
(gp->gp_cvgen) {
SvREFCNT_dec_NN(gp->gp_cv);
gp->gp_cv = NULL;
gp->gp_cvgen = 0;
}
}
return
gp;
}
void
Perl_gp_free(pTHX_ GV *gv)
{
GP* gp;
int
attempts = 100;
bool
in_global_destruction = PL_phase == PERL_PHASE_DESTRUCT;
if
(!gv || !isGV_with_GP(gv) || !(gp = GvGP(gv)))
return
;
if
(gp->gp_refcnt == 0) {
Perl_ck_warner_d(aTHX_ packWARN(WARN_INTERNAL),
"Attempt to free unreferenced glob pointers"
pTHX__FORMAT pTHX__VALUE);
return
;
}
if
(gp->gp_refcnt > 1) {
borrowed:
if
(gp->gp_egv == gv)
gp->gp_egv = 0;
gp->gp_refcnt--;
GvGP_set(gv, NULL);
return
;
}
while
(1) {
HEK *
const
file_hek = gp->gp_file_hek;
SV * sv = gp->gp_sv;
AV * av = gp->gp_av;
HV * hv = gp->gp_hv;
IO * io = gp->gp_io;
CV * cv = gp->gp_cv;
CV * form = gp->gp_form;
int
need = 0;
gp->gp_file_hek = NULL;
gp->gp_sv = NULL;
gp->gp_av = NULL;
gp->gp_hv = NULL;
gp->gp_io = NULL;
gp->gp_cv = NULL;
gp->gp_form = NULL;
if
(file_hek)
unshare_hek(file_hek);
if
(sv) {
SV *referant;
if
(SvREFCNT(sv) > 1 || SvOBJECT(sv) || UNLIKELY(in_global_destruction)) {
SvREFCNT_dec_NN(sv);
sv = NULL;
}
else
if
(SvROK(sv) && (referant = SvRV(sv))
&& (SvREFCNT(referant) > 1 || SvOBJECT(referant))) {
SvREFCNT_dec_NN(sv);
sv = NULL;
}
else
{
++need;
}
}
if
(av) {
if
(SvREFCNT(av) > 1 || SvOBJECT(av) || UNLIKELY(in_global_destruction)) {
SvREFCNT_dec_NN(av);
av = NULL;
}
else
{
++need;
}
}
if
(hv && SvTYPE(hv) == SVt_PVHV) {
const
HEK *hvname_hek = HvNAME_HEK(hv);
if
(PL_stashcache && hvname_hek) {
DEBUG_o(Perl_deb(aTHX_
"gp_free clearing PL_stashcache for '%"
HEKf
"'\n"
,
HEKfARG(hvname_hek)));
(
void
)hv_deletehek(PL_stashcache, hvname_hek, G_DISCARD);
}
if
(SvREFCNT(hv) > 1 || SvOBJECT(hv) || UNLIKELY(in_global_destruction)) {
SvREFCNT_dec_NN(hv);
hv = NULL;
}
else
{
++need;
}
}
if
(io && SvREFCNT(io) == 1 && IoIFP(io)
&& (IoTYPE(io) == IoTYPE_WRONLY ||
IoTYPE(io) == IoTYPE_RDWR ||
IoTYPE(io) == IoTYPE_APPEND)
&& ckWARN_d(WARN_IO)
&& IoIFP(io) != PerlIO_stdin()
&& IoIFP(io) != PerlIO_stdout()
&& IoIFP(io) != PerlIO_stderr()
&& !(IoFLAGS(io) & IOf_FAKE_DIRP))
io_close(io, gv, FALSE, TRUE);
if
(io) {
if
(SvREFCNT(io) > 1 || SvOBJECT(io) || UNLIKELY(in_global_destruction)) {
SvREFCNT_dec_NN(io);
io = NULL;
}
else
{
++need;
}
}
if
(cv) {
if
(SvREFCNT(cv) > 1 || SvOBJECT(cv) || UNLIKELY(in_global_destruction)) {
SvREFCNT_dec_NN(cv);
cv = NULL;
}
else
{
++need;
}
}
if
(form) {
if
(SvREFCNT(form) > 1 || SvOBJECT(form) || UNLIKELY(in_global_destruction)) {
SvREFCNT_dec_NN(form);
form = NULL;
}
else
{
++need;
}
}
if
(need) {
SSize_t max_ix = PL_tmps_ix + need;
if
(max_ix >= PL_tmps_max) {
tmps_grow_p(max_ix);
}
if
(sv) {
PL_tmps_stack[++PL_tmps_ix] = sv;
}
if
(av) {
PL_tmps_stack[++PL_tmps_ix] = (SV *) av;
}
if
(hv) {
PL_tmps_stack[++PL_tmps_ix] = (SV *) hv;
}
if
(io) {
PL_tmps_stack[++PL_tmps_ix] = (SV *) io;
}
if
(cv) {
PL_tmps_stack[++PL_tmps_ix] = (SV *) cv;
}
if
(form) {
PL_tmps_stack[++PL_tmps_ix] = (SV *) form;
}
}
gp = GvGP(gv);
if
(!gp->gp_file_hek
&& !gp->gp_sv
&& !gp->gp_av
&& !gp->gp_hv
&& !gp->gp_io
&& !gp->gp_cv
&& !gp->gp_form)
break
;
if
(--attempts == 0) {
Perl_die(aTHX_
"panic: gp_free failed to free glob pointer - "
"something is repeatedly re-creating entries"
);
}
}
if
(gp->gp_refcnt > 1)
goto
borrowed;
Safefree(gp);
GvGP_set(gv, NULL);
}
int
Perl_magic_freeovrld(pTHX_ SV *sv, MAGIC *mg)
{
AMT *
const
amtp = (AMT*)mg->mg_ptr;
PERL_UNUSED_ARG(sv);
PERL_ARGS_ASSERT_MAGIC_FREEOVRLD;
if
(amtp && AMT_AMAGIC(amtp)) {
int
i;
for
(i = 1; i < NofAMmeth; i++) {
CV *
const
cv = amtp->table[i];
if
(cv) {
SvREFCNT_dec_NN(MUTABLE_SV(cv));
amtp->table[i] = NULL;
}
}
}
return
0;
}
int
Perl_Gv_AMupdate(pTHX_ HV *stash,
bool
destructing)
{
MAGIC*
const
mg = mg_find((
const
SV *)stash, PERL_MAGIC_overload_table);
AMT amt;
const
struct
mro_meta* stash_meta = HvMROMETA(stash);
U32 newgen;
PERL_ARGS_ASSERT_GV_AMUPDATE;
newgen = PL_sub_generation + stash_meta->pkg_gen + stash_meta->cache_gen;
if
(mg) {
const
AMT *
const
amtp = (AMT*)mg->mg_ptr;
if
(amtp->was_ok_sub == newgen) {
return
AMT_AMAGIC(amtp) ? 1 : 0;
}
sv_unmagic(MUTABLE_SV(stash), PERL_MAGIC_overload_table);
}
DEBUG_o( Perl_deb(aTHX_
"Recalcing overload magic in package %s\n"
,HvNAME_get(stash)) );
Zero(&amt,1,AMT);
amt.was_ok_sub = newgen;
amt.fallback = AMGfallNO;
amt.flags = 0;
{
int
filled = 0;
int
i;
bool
deref_seen = 0;
GV *gv = gv_fetchmeth_pvn(stash, PL_AMG_names[0], 2, -1, 0);
SV *
const
sv = gv ? GvSV(gv) : NULL;
CV* cv;
if
(!gv)
{
if
(!gv_fetchmeth_pvn(stash,
"(("
, 2, -1, 0))
goto
no_table;
}
#ifdef PERL_DONT_CREATE_GVSV
else
if
(!sv) {
NOOP;
}
#endif
else
if
(SvTRUE(sv))
amt.fallback=AMGfallYES;
else
if
(SvOK(sv)) {
amt.fallback=AMGfallNEVER;
filled = 1;
}
else
{
filled = 1;
}
assert
(SvOOK(stash));
HvAUX(stash)->xhv_aux_flags &= ~HvAUXf_NO_DEREF;
for
(i = 1; i < NofAMmeth; i++) {
const
char
*
const
cooky = PL_AMG_names[i];
const
char
*
const
cp = AMG_id2name(i);
const
STRLEN l = PL_AMG_namelens[i];
DEBUG_o( Perl_deb(aTHX_
"Checking overloading of \"%s\" in package \"%.256s\"\n"
,
cp, HvNAME_get(stash)) );
gv = Perl_gv_fetchmeth_pvn(aTHX_ stash, cooky, l, -1, 0);
cv = 0;
if
(gv && (cv = GvCV(gv)) && CvHASGV(cv)) {
const
HEK *
const
gvhek = CvGvNAME_HEK(cv);
const
HEK *
const
stashek =
HvNAME_HEK(CvNAMED(cv) ? CvSTASH(cv) : GvSTASH(CvGV(cv)));
if
(memEQs(HEK_KEY(gvhek), HEK_LEN(gvhek),
"nil"
)
&& stashek
&& memEQs(HEK_KEY(stashek), HEK_LEN(stashek),
"overload"
)) {
GV *ngv = NULL;
SV *gvsv = GvSV(gv);
DEBUG_o( Perl_deb(aTHX_
"Resolving method \"%"
SVf256\
"\" for overloaded \"%s\" in package \"%.256s\"\n"
,
(
void
*)GvSV(gv), cp, HvNAME(stash)) );
if
(!gvsv || !SvPOK(gvsv)
|| !(ngv = gv_fetchmethod_sv_flags(stash, gvsv, 0)))
{
if
(destructing) {
return
-1;
}
else
{
const
SV *
const
name = (gvsv && SvPOK(gvsv))
? gvsv
: newSVpvs_flags(
"???"
, SVs_TEMP);
Perl_croak(aTHX_
"%s method \"%"
SVf256
"\" overloading \"%s\" "
\
"in package \"%"
HEKf256
"\""
,
(GvCVGEN(gv) ?
"Stub found while resolving"
:
"Can't resolve"
),
SVfARG(name), cp,
HEKfARG(
HvNAME_HEK(stash)
));
}
}
cv = GvCV(gv = ngv);
}
DEBUG_o( Perl_deb(aTHX_
"Overloading \"%s\" in package \"%.256s\" via \"%.256s::%.256s\"\n"
,
cp, HvNAME_get(stash), HvNAME_get(GvSTASH(CvGV(cv))),
GvNAME(CvGV(cv))) );
filled = 1;
}
else
if
(gv) {
cv = MUTABLE_CV(gv);
filled = 1;
}
amt.table[i]=MUTABLE_CV(SvREFCNT_inc_simple(cv));
if
(gv) {
switch
(i) {
case
to_sv_amg:
case
to_av_amg:
case
to_hv_amg:
case
to_gv_amg:
case
to_cv_amg:
case
nomethod_amg:
deref_seen = 1;
break
;
}
}
}
if
(!deref_seen)
HvAUX(stash)->xhv_aux_flags |= HvAUXf_NO_DEREF;
if
(filled) {
AMT_AMAGIC_on(&amt);
sv_magic(MUTABLE_SV(stash), 0, PERL_MAGIC_overload_table,
(
char
*)&amt,
sizeof
(AMT));
return
TRUE;
}
}
no_table:
AMT_AMAGIC_off(&amt);
sv_magic(MUTABLE_SV(stash), 0, PERL_MAGIC_overload_table,
(
char
*)&amt,
sizeof
(AMTS));
return
0;
}
CV*
Perl_gv_handler(pTHX_ HV *stash, I32 id)
{
MAGIC *mg;
AMT *amtp;
U32 newgen;
struct
mro_meta* stash_meta;
if
(!stash || !HvNAME_get(stash))
return
NULL;
stash_meta = HvMROMETA(stash);
newgen = PL_sub_generation + stash_meta->pkg_gen + stash_meta->cache_gen;
mg = mg_find((
const
SV *)stash, PERL_MAGIC_overload_table);
if
(!mg) {
do_update:
if
(Gv_AMupdate(stash, 0) == -1)
return
NULL;
mg = mg_find((
const
SV *)stash, PERL_MAGIC_overload_table);
}
assert
(mg);
amtp = (AMT*)mg->mg_ptr;
if
( amtp->was_ok_sub != newgen )
goto
do_update;
if
(AMT_AMAGIC(amtp)) {
CV *
const
ret = amtp->table[id];
if
(ret && isGV(ret)) {
GV *
const
gv = gv_fetchmethod(stash, PL_AMG_names[id]);
if
(gv && GvCV(gv))
return
GvCV(gv);
}
return
ret;
}
return
NULL;
}
bool
Perl_try_amagic_un(pTHX_
int
method,
int
flags) {
dSP;
SV* tmpsv;
SV*
const
arg = TOPs;
SvGETMAGIC(arg);
if
(SvAMAGIC(arg) && (tmpsv = amagic_call(arg, &PL_sv_undef, method,
AMGf_noright | AMGf_unary
| (flags & AMGf_numarg))))
{
if
( (PL_opargs[PL_op->op_type] & OA_TARGLEX)
&& (PL_op->op_private & OPpTARGET_MY))
{
dTARGET;
sv_setsv(TARG, tmpsv);
SETTARG;
}
else
SETs(tmpsv);
PUTBACK;
return
TRUE;
}
if
((flags & AMGf_numeric) && SvROK(arg))
*sp = sv_2num(arg);
return
FALSE;
}
bool
Perl_try_amagic_bin(pTHX_
int
method,
int
flags) {
dSP;
SV*
const
left = TOPm1s;
SV*
const
right = TOPs;
SvGETMAGIC(left);
if
(left != right)
SvGETMAGIC(right);
if
(SvAMAGIC(left) || SvAMAGIC(right)) {
SV * tmpsv;
bool
mutator = (flags & AMGf_assign) && (PL_op->op_flags & OPf_STACKED);
tmpsv = amagic_call(left, right, method,
(mutator ? AMGf_assign: 0)
| (flags & AMGf_numarg));
if
(tmpsv) {
(
void
)POPs;
if
( mutator
|| ( (PL_opargs[PL_op->op_type] & OA_TARGLEX)
&& (PL_op->op_private & OPpTARGET_MY)))
{
dTARG;
TARG = mutator ? *SP : PAD_SV(PL_op->op_targ);
sv_setsv(TARG, tmpsv);
SETTARG;
}
else
SETs(tmpsv);
PUTBACK;
return
TRUE;
}
}
if
(left==right && SvGMAGICAL(left)) {
SV *
const
left = sv_newmortal();
*(sp-1) = left;
if
(!SvOK(right)) {
if
(ckWARN(WARN_UNINITIALIZED)) report_uninit(right);
sv_setbool(left, FALSE);
}
else
sv_setsv_flags(left, right, 0);
SvGETMAGIC(right);
}
if
(flags & AMGf_numeric) {
if
(SvROK(TOPm1s))
*(sp-1) = sv_2num(TOPm1s);
if
(SvROK(right))
*sp = sv_2num(right);
}
return
FALSE;
}
SV *
Perl_amagic_deref_call(pTHX_ SV *ref,
int
method) {
SV *tmpsv = NULL;
HV *stash;
PERL_ARGS_ASSERT_AMAGIC_DEREF_CALL;
if
(!SvAMAGIC(ref))
return
ref;
stash = SvSTASH(SvRV(ref));
assert
(SvOOK(stash));
if
(HvAUX(stash)->xhv_aux_flags & HvAUXf_NO_DEREF)
return
ref;
while
((tmpsv = amagic_call(ref, &PL_sv_undef, method,
AMGf_noright | AMGf_unary))) {
if
(!SvROK(tmpsv))
Perl_croak(aTHX_
"Overloaded dereference did not return a reference"
);
if
(tmpsv == ref || SvRV(tmpsv) == SvRV(ref)) {
return
tmpsv;
}
ref = tmpsv;
if
(!SvAMAGIC(ref))
break
;
}
return
tmpsv ? tmpsv : ref;
}
bool
Perl_amagic_is_enabled(pTHX_
int
method)
{
SV *lex_mask = cop_hints_fetch_pvs(PL_curcop,
"overloading"
, 0);
assert
(PL_curcop->cop_hints & HINT_NO_AMAGIC);
if
( !lex_mask || !SvOK(lex_mask) )
return
FALSE;
else
if
( lex_mask && SvPOK(lex_mask) ) {
STRLEN len;
const
int
offset = method / 8;
const
int
bit = method % 8;
char
*pv = SvPV(lex_mask, len);
if
( (STRLEN)offset < len && pv[offset] & ( 1 << bit ) )
return
FALSE;
}
return
TRUE;
}
SV*
Perl_amagic_call(pTHX_ SV *left, SV *right,
int
method,
int
flags)
{
MAGIC *mg;
CV *cv=NULL;
CV **cvp=NULL, **ocvp=NULL;
AMT *amtp=NULL, *oamtp=NULL;
int
off = 0, off1, lr = 0, notfound = 0;
int
postpr = 0, force_cpy = 0;
int
assign = AMGf_assign & flags;
const
int
assignshift = assign ? 1 : 0;
int
use_default_op = 0;
int
force_scalar = 0;
#ifdef DEBUGGING
int
fl=0;
#endif
HV* stash=NULL;
PERL_ARGS_ASSERT_AMAGIC_CALL;
if
( PL_curcop->cop_hints & HINT_NO_AMAGIC ) {
if
(!amagic_is_enabled(method))
return
NULL;
}
if
(!(AMGf_noleft & flags) && SvAMAGIC(left)
&& (stash = SvSTASH(SvRV(left))) && Gv_AMG(stash)
&& (mg = mg_find((
const
SV *)stash, PERL_MAGIC_overload_table))
&& (ocvp = cvp = (AMT_AMAGIC((AMT*)mg->mg_ptr)
? (oamtp = amtp = (AMT*)mg->mg_ptr)->table
: NULL))
&& ((cv = cvp[off=method+assignshift])
|| (assign && amtp->fallback > AMGfallNEVER &&
(
#ifdef DEBUGGING
fl = 1,
#endif
cv = cvp[off=method])))) {
lr = -1;
}
else
{
if
(cvp && amtp->fallback > AMGfallNEVER && flags & AMGf_unary) {
int
logic;
switch
(method) {
case
inc_amg:
force_cpy = 1;
if
((cv = cvp[off=add_ass_amg])
|| ((cv = cvp[off = add_amg])
&& (force_cpy = 0, (postpr = 1)))) {
right = &PL_sv_yes; lr = -1; assign = 1;
}
break
;
case
dec_amg:
force_cpy = 1;
if
((cv = cvp[off = subtr_ass_amg])
|| ((cv = cvp[off = subtr_amg])
&& (force_cpy = 0, (postpr=1)))) {
right = &PL_sv_yes; lr = -1; assign = 1;
}
break
;
case
bool__amg:
(
void
)((cv = cvp[off=numer_amg]) || (cv = cvp[off=string_amg]));
break
;
case
numer_amg:
(
void
)((cv = cvp[off=string_amg]) || (cv = cvp[off=bool__amg]));
break
;
case
string_amg:
(
void
)((cv = cvp[off=numer_amg]) || (cv = cvp[off=bool__amg]));
break
;
case
not_amg:
(
void
)((cv = cvp[off=bool__amg])
|| (cv = cvp[off=numer_amg])
|| (cv = cvp[off=string_amg]));
if
(cv)
postpr = 1;
break
;
case
copy_amg:
{
SV*
const
tmpRef=SvRV(left);
if
(!SvROK(tmpRef) && SvTYPE(tmpRef) <= SVt_PVMG) {
SV*
const
newref = newSVsv(tmpRef);
SvOBJECT_on(newref);
SvSTASH_set(newref, MUTABLE_HV(SvREFCNT_inc(SvSTASH(tmpRef))));
return
newref;
}
}
break
;
case
abs_amg:
if
((cvp[off1=lt_amg] || cvp[off1=ncmp_amg])
&& ((cv = cvp[off=neg_amg]) || (cv = cvp[off=subtr_amg]))) {
SV*
const
nullsv=&PL_sv_zero;
if
(off1==lt_amg) {
SV*
const
lessp = amagic_call(left,nullsv,
lt_amg,AMGf_noright);
logic = SvTRUE_NN(lessp);
}
else
{
SV*
const
lessp = amagic_call(left,nullsv,
ncmp_amg,AMGf_noright);
logic = (SvNV(lessp) < 0);
}
if
(logic) {
if
(off==subtr_amg) {
right = left;
left = nullsv;
lr = 1;
}
}
else
{
return
left;
}
}
break
;
case
neg_amg:
if
((cv = cvp[off=subtr_amg])) {
right = left;
left = &PL_sv_zero;
lr = 1;
}
break
;
case
int_amg:
case
iter_amg:
case
ftest_amg:
case
regexp_amg:
return
NULL;
case
to_sv_amg:
case
to_av_amg:
case
to_hv_amg:
case
to_gv_amg:
case
to_cv_amg:
return
left;
default
:
goto
not_found;
}
if
(!cv)
goto
not_found;
}
else
if
(!(AMGf_noright & flags) && SvAMAGIC(right)
&& (stash = SvSTASH(SvRV(right))) && Gv_AMG(stash)
&& (mg = mg_find((
const
SV *)stash, PERL_MAGIC_overload_table))
&& (cvp = (AMT_AMAGIC((AMT*)mg->mg_ptr)
? (amtp = (AMT*)mg->mg_ptr)->table
: NULL))
&& (cv = cvp[off=method])) {
lr=1;
}
else
if
(((cvp && amtp->fallback > AMGfallNEVER)
|| (ocvp && oamtp->fallback > AMGfallNEVER))
&& !(flags & AMGf_unary)) {
if
(method==concat_amg || method==concat_ass_amg
|| method==repeat_amg || method==repeat_ass_amg) {
return
NULL;
}
off = -1;
switch
(method) {
case
lt_amg:
case
le_amg:
case
gt_amg:
case
ge_amg:
case
eq_amg:
case
ne_amg:
off = ncmp_amg;
break
;
case
slt_amg:
case
sle_amg:
case
sgt_amg:
case
sge_amg:
case
seq_amg:
case
sne_amg:
off = scmp_amg;
break
;
}
if
(off != -1) {
if
(ocvp && (oamtp->fallback > AMGfallNEVER)) {
cv = ocvp[off];
lr = -1;
}
if
(!cv && (cvp && amtp->fallback > AMGfallNEVER)) {
cv = cvp[off];
lr = 1;
}
}
if
(cv)
postpr = 1;
else
goto
not_found;
}
else
{
not_found:
switch
(method) {
case
to_sv_amg:
case
to_av_amg:
case
to_hv_amg:
case
to_gv_amg:
case
to_cv_amg:
return
left;
}
if
(ocvp && (cv=ocvp[nomethod_amg])) {
notfound = 1; lr = -1;
}
else
if
(cvp && (cv=cvp[nomethod_amg])) {
notfound = 1; lr = 1;
}
else
if
((use_default_op =
(!ocvp || oamtp->fallback >= AMGfallYES)
&& (!cvp || amtp->fallback >= AMGfallYES))
&& !DEBUG_o_TEST) {
return
NULL;
}
else
{
SV *msg;
if
(off==-1) off=method;
msg = sv_2mortal(Perl_newSVpvf(aTHX_
"Operation \"%s\": no method found,%sargument %s%"
SVf
"%s%"
SVf,
AMG_id2name(method + assignshift),
(flags & AMGf_unary ?
" "
:
"\n\tleft "
),
SvAMAGIC(left)?
"in overloaded package "
:
"has no overloaded magic"
,
SvAMAGIC(left)?
SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(SvSTASH(SvRV(left)))))):
SVfARG(&PL_sv_no),
SvAMAGIC(right)?
",\n\tright argument in overloaded package "
:
(flags & AMGf_unary
?
""
:
",\n\tright argument has no overloaded magic"
),
SvAMAGIC(right)?
SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(SvSTASH(SvRV(right)))))):
SVfARG(&PL_sv_no)));
if
(use_default_op) {
DEBUG_o( Perl_deb(aTHX_
"%"
SVf, SVfARG(msg)) );
}
else
{
Perl_croak(aTHX_
"%"
SVf, SVfARG(msg));
}
return
NULL;
}
force_cpy = force_cpy || assign;
}
}
switch
(method) {
case
inc_amg:
if
(off == add_amg)
force_scalar = 1;
break
;
case
dec_amg:
if
(off == subtr_amg)
force_scalar = 1;
break
;
case
add_amg:
case
subtr_amg:
case
mult_amg:
case
div_amg:
case
modulo_amg:
case
pow_amg:
case
lshift_amg:
case
rshift_amg:
case
repeat_amg:
case
concat_amg:
case
band_amg:
case
bor_amg:
case
bxor_amg:
case
sband_amg:
case
sbor_amg:
case
sbxor_amg:
if
(assign)
force_scalar = 1;
break
;
case
copy_amg:
force_scalar = 1;
break
;
case
to_sv_amg:
case
to_av_amg:
case
to_hv_amg:
case
to_gv_amg:
case
to_cv_amg:
force_scalar = 1;
break
;
case
bool__amg:
case
numer_amg:
case
string_amg:
force_scalar = 1;
break
;
}
#ifdef DEBUGGING
if
(!notfound) {
DEBUG_o(Perl_deb(aTHX_
"Overloaded operator \"%s\"%s%s%s:\n\tmethod%s found%s in package %"
SVf
"%s\n"
,
AMG_id2name(off),
method+assignshift==off?
""
:
" (initially \""
,
method+assignshift==off?
""
:
AMG_id2name(method+assignshift),
method+assignshift==off?
""
:
"\")"
,
flags & AMGf_unary?
""
:
lr==1 ?
" for right argument"
:
" for left argument"
,
flags & AMGf_unary?
" for argument"
:
""
,
stash ? SVfARG(sv_2mortal(newSVhek(HvNAME_HEK(stash)))) : SVfARG(newSVpvs_flags(
"null"
, SVs_TEMP)),
fl?
",\n\tassignment variant used"
:
""
) );
}
#endif
if
( (lr == -1) && ( ( (method + assignshift == off)
&& (assign || (method == inc_amg) || (method == dec_amg)))
|| force_cpy) )
{
SV *tmpRef = SvRV(left);
SV *rv_copy;
if
(SvREFCNT(tmpRef) > 1 && (rv_copy = AMG_CALLunary(left,copy_amg))) {
SvRV_set(left, rv_copy);
SvSETMAGIC(left);
SvREFCNT_dec_NN(tmpRef);
}
}
{
dSP;
BINOP myop;
SV* res;
const
bool
oldcatch = CATCH_GET;
I32 oldmark, nret;
U8 gimme = (force_scalar || PL_op->op_type == OP_MULTICONCAT)
? G_SCALAR : GIMME_V;
CATCH_SET(TRUE);
Zero(&myop, 1, BINOP);
myop.op_last = (OP *) &myop;
myop.op_next = NULL;
myop.op_flags = OPf_STACKED;
switch
(gimme) {
case
G_VOID:
myop.op_flags |= OPf_WANT_VOID;
break
;
case
G_LIST:
if
(flags & AMGf_want_list) {
myop.op_flags |= OPf_WANT_LIST;
break
;
}
default
:
myop.op_flags |= OPf_WANT_SCALAR;
break
;
}
PUSHSTACKi(PERLSI_OVERLOAD);
ENTER;
SAVEOP();
PL_op = (OP *) &myop;
if
(PERLDB_SUB && PL_curstash != PL_debstash)
PL_op->op_private |= OPpENTERSUB_DB;
Perl_pp_pushmark(aTHX);
EXTEND(SP, notfound + 5);
PUSHs(lr>0? right: left);
PUSHs(lr>0? left: right);
PUSHs( lr > 0 ? &PL_sv_yes : ( assign ? &PL_sv_undef : &PL_sv_no ));
if
(notfound) {
PUSHs(newSVpvn_flags(AMG_id2name(method + assignshift),
AMG_id2namelen(method + assignshift), SVs_TEMP));
}
else
if
(flags & AMGf_numarg)
PUSHs(&PL_sv_undef);
if
(flags & AMGf_numarg)
PUSHs(&PL_sv_yes);
PUSHs(MUTABLE_SV(cv));
PUTBACK;
oldmark = TOPMARK;
if
((PL_op = PL_ppaddr[OP_ENTERSUB](aTHX)))
CALLRUNOPS(aTHX);
LEAVE;
SPAGAIN;
nret = SP - (PL_stack_base + oldmark);
switch
(gimme) {
case
G_VOID:
res = &PL_sv_undef;
SP = PL_stack_base + oldmark;
break
;
case
G_LIST:
if
(flags & AMGf_want_list) {
res = newSV_type_mortal(SVt_PVAV);
av_extend((AV *)res, nret);
while
(nret--)
av_store((AV *)res, nret, POPs);
break
;
}
default
:
res = POPs;
break
;
}
PUTBACK;
POPSTACK;
CATCH_SET(oldcatch);
if
(postpr) {
int
ans;
switch
(method) {
case
le_amg:
case
sle_amg:
ans=SvIV(res)<=0;
break
;
case
lt_amg:
case
slt_amg:
ans=SvIV(res)<0;
break
;
case
ge_amg:
case
sge_amg:
ans=SvIV(res)>=0;
break
;
case
gt_amg:
case
sgt_amg:
ans=SvIV(res)>0;
break
;
case
eq_amg:
case
seq_amg:
ans=SvIV(res)==0;
break
;
case
ne_amg:
case
sne_amg:
ans=SvIV(res)!=0;
break
;
case
inc_amg:
case
dec_amg:
SvSetSV(left,res);
return
left;
case
not_amg:
ans=!SvTRUE_NN(res);
break
;
default
:
ans=0;
break
;
}
return
boolSV(ans);
}
else
if
(method==copy_amg) {
if
(!SvROK(res)) {
Perl_croak(aTHX_
"Copy method did not return a reference"
);
}
return
SvREFCNT_inc(SvRV(res));
}
else
{
return
res;
}
}
}
void
Perl_gv_name_set(pTHX_ GV *gv,
const
char
*name, U32 len, U32 flags)
{
U32 hash;
PERL_ARGS_ASSERT_GV_NAME_SET;
if
(len > I32_MAX)
Perl_croak(aTHX_
"panic: gv name too long (%"
UVuf
")"
, (UV) len);
if
(!(flags & GV_ADD) && GvNAME_HEK(gv)) {
unshare_hek(GvNAME_HEK(gv));
}
PERL_HASH(hash, name, len);
GvNAME_HEK(gv) = share_hek(name, (flags & SVf_UTF8 ? -(I32)len : (I32)len), hash);
}
void
Perl_gv_try_downgrade(pTHX_ GV *gv)
{
HV *stash;
CV *cv;
HEK *namehek;
SV **gvp;
PERL_ARGS_ASSERT_GV_TRY_DOWNGRADE;
if
(PL_phase == PERL_PHASE_DESTRUCT)
return
;
if
(!(SvREFCNT(gv) == 1 && SvTYPE(gv) == SVt_PVGV && !SvFAKE(gv) &&
!SvOBJECT(gv) && !SvREADONLY(gv) &&
isGV_with_GP(gv) && GvGP(gv) &&
!GvINTRO(gv) && GvREFCNT(gv) == 1 &&
!GvSV(gv) && !GvAV(gv) && !GvHV(gv) && !GvIOp(gv) && !GvFORM(gv) &&
GvEGVx(gv) == gv && (stash = GvSTASH(gv))))
return
;
if
(gv == PL_statgv || gv == PL_last_in_gv || gv == PL_stderrgv)
return
;
if
(SvMAGICAL(gv)) {
MAGIC *mg;
if
(SvGMAGICAL(gv) || SvSMAGICAL(gv))
return
;
for
(mg = SvMAGIC(gv); mg; mg = mg->mg_moremagic) {
if
(mg->mg_type != PERL_MAGIC_backref)
return
;
}
}
cv = GvCV(gv);
if
(!cv) {
HEK *gvnhek = GvNAME_HEK(gv);
(
void
)hv_deletehek(stash, gvnhek, G_DISCARD);
}
else
if
(GvMULTI(gv) && cv && SvREFCNT(cv) == 1 &&
!SvOBJECT(cv) && !SvMAGICAL(cv) && !SvREADONLY(cv) &&
CvSTASH(cv) == stash && !CvNAMED(cv) && CvGV(cv) == gv &&
CvCONST(cv) && !CvMETHOD(cv) && !CvLVALUE(cv) && !CvUNIQUE(cv) &&
!CvNODEBUG(cv) && !CvCLONE(cv) && !CvCLONED(cv) && !CvANON(cv) &&
(namehek = GvNAME_HEK(gv)) &&
(gvp = hv_fetchhek(stash, namehek, 0)) &&
*gvp == (SV*)gv) {
SV *value = SvREFCNT_inc(CvXSUBANY(cv).any_ptr);
const
bool
imported = !!GvIMPORTED_CV(gv);
SvREFCNT(gv) = 0;
sv_clear((SV*)gv);
SvREFCNT(gv) = 1;
SvFLAGS(gv) = SVt_IV|SVf_ROK|SVprv_PCS_IMPORTED * imported;
SvANY(gv) = (XPVGV*)((
char
*)&(gv->sv_u.svu_iv) -
STRUCT_OFFSET(XPVIV, xiv_iv));
SvRV_set(gv, value);
}
}
GV *
Perl_gv_override(pTHX_
const
char
*
const
name,
const
STRLEN len)
{
GV *gv = gv_fetchpvn(name, len, GV_NOTQUAL, SVt_PVCV);
GV *
const
*gvp;
PERL_ARGS_ASSERT_GV_OVERRIDE;
if
(gv && GvCVu(gv) && GvIMPORTED_CV(gv))
return
gv;
gvp = (GV**)hv_fetch(PL_globalstash, name, len, FALSE);
gv = gvp ? *gvp : NULL;
if
(gv && !isGV(gv)) {
if
(!SvPCS_IMPORTED(gv))
return
NULL;
gv_init(gv, PL_globalstash, name, len, 0);
return
gv;
}
return
gv && GvCVu(gv) && GvIMPORTED_CV(gv) ? gv : NULL;
}
#include "XSUB.h"
static
void
core_xsub(pTHX_ CV* cv)
{
Perl_croak(aTHX_
"&CORE::%s cannot be called directly"
, GvNAME(CvGV(cv))
);
}