# define ASSERT_UTF8_CACHE(cache) NOOP
#endif
+static const char S_destroy[] = "DESTROY";
+#define S_destroy_len (sizeof(S_destroy)-1)
+
/* ============================================================================
=head1 Allocation and deallocation of SVs.
#endif /* DEBUGGING */
-/*
- * Bodyless IVs and NVs!
- *
- * Since 5.9.2, we can avoid allocating a body for SVt_IV-type SVs.
- * Since the larger IV-holding variants of SVs store their integer
- * values in their respective bodies, the family of SvIV() accessor
- * macros would naively have to branch on the SV type to find the
- * integer value either in the HEAD or BODY. In order to avoid this
- * expensive branch, a clever soul has deployed a great hack:
- * We set up the SvANY pointer such that instead of pointing to a
- * real body, it points into the memory before the location of the
- * head. We compute this pointer such that the location of
- * the integer member of the hypothetical body struct happens to
- * be the same as the location of the integer member of the bodyless
- * SV head. This now means that the SvIV() family of accessors can
- * always read from the (hypothetical or real) body via SvANY.
- *
- * Since the 5.21 dev series, we employ the same trick for NVs
- * if the architecture can support it (NVSIZE <= IVSIZE).
- */
-
-/* The following two macros compute the necessary offsets for the above
- * trick and store them in SvANY for SvIV() (and friends) to use. */
-#define SET_SVANY_FOR_BODYLESS_IV(sv) \
- SvANY(sv) = (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv))
-
-#define SET_SVANY_FOR_BODYLESS_NV(sv) \
- SvANY(sv) = (XPVNV*)((char*)&(sv->sv_u.svu_nv) - STRUCT_OFFSET(XPVNV, xnv_u.xnv_nv))
/*
=head1 SV Manipulation Functions
* Only increment if the allocation isn't MEM_SIZE_MAX,
* otherwise it will wrap to 0.
*/
- if (newlen & 0xff && newlen != MEM_SIZE_MAX)
+ if ( (newlen < 0x1000 || (newlen & (newlen - 1)))
+ && newlen != MEM_SIZE_MAX
+ )
newlen++;
#endif
DECLARATION_FOR_LC_NUMERIC_MANIPULATION;
STORE_LC_NUMERIC_SET_TO_NEEDED();
- local_radix =
- PL_numeric_local &&
- PL_numeric_radix_sv &&
- SvUTF8(PL_numeric_radix_sv);
+ local_radix = PL_numeric_local && PL_numeric_radix_sv;
if (local_radix && SvLEN(PL_numeric_radix_sv) > 1) {
size += SvLEN(PL_numeric_radix_sv) - 1;
s = SvGROW_mutable(sv, size);
/* If the radix character is UTF-8, and actually is in the
* output, turn on the UTF-8 flag for the scalar */
- if (local_radix &&
- instr(s, SvPVX_const(PL_numeric_radix_sv))) {
+ if ( local_radix
+ && SvUTF8(PL_numeric_radix_sv)
+ && instr(s, SvPVX_const(PL_numeric_radix_sv)))
+ {
SvUTF8_on(sv);
}
}
else
{
+ SSize_t i;
sv_magic(
sref, omg ? omg->mg_obj : dstr, PERL_MAGIC_isa, NULL, 0
);
+ for (i = 0; i <= AvFILL(sref); ++i) {
+ SV **elem = av_fetch ((AV*)sref, i, 0);
+ if (elem) {
+ sv_magic(
+ *elem, sref, PERL_MAGIC_isaelem, NULL, i
+ );
+ }
+ }
mg = mg_find(sref, PERL_MAGIC_isa);
}
/* Since the *ISA assignment could have affected more than
U32 sflags;
int dtype;
svtype stype;
+ unsigned int both_type;
PERL_ARGS_ASSERT_SV_SETSV_FLAGS;
if (UNLIKELY( sstr == dstr ))
return;
- if (SvIS_FREED(dstr)) {
- Perl_croak(aTHX_ "panic: attempt to copy value %" SVf
- " to a freed scalar %p", SVfARG(sstr), (void *)dstr);
- }
- SV_CHECK_THINKFIRST_COW_DROP(dstr);
if (UNLIKELY( !sstr ))
sstr = &PL_sv_undef;
- if (SvIS_FREED(sstr)) {
- Perl_croak(aTHX_ "panic: attempt to copy freed scalar %p to %p",
- (void*)sstr, (void*)dstr);
- }
+
stype = SvTYPE(sstr);
dtype = SvTYPE(dstr);
+ both_type = (stype | dtype);
+
+ /* with these values, we can check that both SVs are NULL/IV (and not
+ * freed) just by testing the or'ed types */
+ STATIC_ASSERT_STMT(SVt_NULL == 0);
+ STATIC_ASSERT_STMT(SVt_IV == 1);
+ if (both_type <= 1) {
+ /* both src and dst are UNDEF/IV/RV, so we can do a lot of
+ * special-casing */
+ U32 sflags;
+ U32 new_dflags;
+
+ /* minimal subset of SV_CHECK_THINKFIRST_COW_DROP(dstr) */
+ if (SvREADONLY(dstr))
+ Perl_croak_no_modify();
+ if (SvROK(dstr))
+ sv_unref_flags(dstr, 0);
+
+ assert(!SvGMAGICAL(sstr));
+ assert(!SvGMAGICAL(dstr));
+
+ sflags = SvFLAGS(sstr);
+ if (sflags & (SVf_IOK|SVf_ROK)) {
+ SET_SVANY_FOR_BODYLESS_IV(dstr);
+ new_dflags = SVt_IV;
+
+ if (sflags & SVf_ROK) {
+ dstr->sv_u.svu_rv = SvREFCNT_inc(SvRV(sstr));
+ new_dflags |= SVf_ROK;
+ }
+ else {
+ /* both src and dst are <= SVt_IV, so sv_any points to the
+ * head; so access the head directly
+ */
+ assert( &(sstr->sv_u.svu_iv)
+ == &(((XPVIV*) SvANY(sstr))->xiv_iv));
+ assert( &(dstr->sv_u.svu_iv)
+ == &(((XPVIV*) SvANY(dstr))->xiv_iv));
+ dstr->sv_u.svu_iv = sstr->sv_u.svu_iv;
+ new_dflags |= (SVf_IOK|SVp_IOK|(sflags & SVf_IVisUV));
+ }
+ }
+ else {
+ new_dflags = dtype; /* turn off everything except the type */
+ }
+ SvFLAGS(dstr) = new_dflags;
+
+ return;
+ }
+
+ if (UNLIKELY(both_type == SVTYPEMASK)) {
+ if (SvIS_FREED(dstr)) {
+ Perl_croak(aTHX_ "panic: attempt to copy value %" SVf
+ " to a freed scalar %p", SVfARG(sstr), (void *)dstr);
+ }
+ if (SvIS_FREED(sstr)) {
+ Perl_croak(aTHX_ "panic: attempt to copy freed scalar %p to %p",
+ (void*)sstr, (void*)dstr);
+ }
+ }
+
+
+
+ SV_CHECK_THINKFIRST_COW_DROP(dstr);
+ dtype = SvTYPE(dstr); /* THINKFIRST may have changed type */
/* There's a lot of redundancy below but we're going for speed here */
if (SvMAGICAL(sv)) /* if we're under save_magic, wait for restore_magic; */
mg_magical(sv); /* else fix the flags now */
}
- else {
+ else
SvMAGICAL_off(sv);
- SvFLAGS(sv) |= (SvFLAGS(sv) & (SVp_IOK|SVp_NOK|SVp_POK)) >> PRIVSHIFT;
- }
+
return 0;
}
assert(SvTYPE(stash) == SVt_PVHV);
if (HvNAME(stash)) {
CV* destructor = NULL;
+ struct mro_meta *meta;
+
assert (SvOOK(stash));
- if (!SvOBJECT(stash)) destructor = (CV *)SvSTASH(stash);
- if (!destructor || HvMROMETA(stash)->destroy_gen
- != PL_sub_generation)
- {
- GV * const gv =
- gv_fetchmeth_autoload(stash, "DESTROY", 7, 0);
- if (gv) destructor = GvCV(gv);
- if (!SvOBJECT(stash))
- {
- SvSTASH(stash) =
- destructor ? (HV *)destructor : ((HV *)0)+1;
- HvAUX(stash)->xhv_mro_meta->destroy_gen =
- PL_sub_generation;
- }
+
+ DEBUG_o( Perl_deb(aTHX_ "Looking for DESTROY method for %s\n",
+ HvNAME(stash)) );
+
+ /* don't make this an initialization above the assert, since it needs
+ an AUX structure */
+ meta = HvMROMETA(stash);
+ if (meta->destroy_gen && meta->destroy_gen == PL_sub_generation) {
+ destructor = meta->destroy;
+ DEBUG_o( Perl_deb(aTHX_ "Using cached DESTROY method %p for %s\n",
+ (void *)destructor, HvNAME(stash)) );
+ }
+ else {
+ bool autoload = FALSE;
+ GV *gv =
+ gv_fetchmeth_pvn(stash, S_destroy, S_destroy_len, -1, 0);
+ if (gv)
+ destructor = GvCV(gv);
+ if (!destructor) {
+ gv = gv_autoload_pvn(stash, S_destroy, S_destroy_len,
+ GV_AUTOLOAD_ISMETHOD);
+ if (gv)
+ destructor = GvCV(gv);
+ if (destructor)
+ autoload = TRUE;
+ }
+ /* we don't cache AUTOLOAD for DESTROY, since this code
+ would then need to set $__PACKAGE__::AUTOLOAD, or the
+ equivalent for XS AUTOLOADs */
+ if (!autoload) {
+ meta->destroy_gen = PL_sub_generation;
+ meta->destroy = destructor;
+
+ DEBUG_o( Perl_deb(aTHX_ "Set cached DESTROY method %p for %s\n",
+ (void *)destructor, HvNAME(stash)) );
+ }
+ else {
+ DEBUG_o( Perl_deb(aTHX_ "Not caching AUTOLOAD for DESTROY method for %s\n",
+ HvNAME(stash)) );
+ }
}
- assert(!destructor || destructor == ((CV *)0)+1
- || SvTYPE(destructor) == SVt_PVCV);
- if (destructor && destructor != ((CV *)0)+1
+ assert(!destructor || SvTYPE(destructor) == SVt_PVCV);
+ if (destructor
/* A constant subroutine can have no side effects, so
don't bother calling it. */
&& !CvCONST(destructor)
PERL_ARGS_ASSERT_SV_COLLXFRM_FLAGS;
mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_collxfrm) : (MAGIC *) NULL;
+
+ /* If we don't have collation magic on 'sv', or the locale has changed
+ * since the last time we calculated it, get it and save it now */
if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
const char *s;
char *xf;
STRLEN len, xlen;
+ /* Free the old space */
if (mg)
Safefree(mg->mg_ptr);
+
s = SvPV_flags_const(sv, len, flags);
- if ((xf = mem_collxfrm(s, len, &xlen))) {
+ if ((xf = _mem_collxfrm(s, len, &xlen, cBOOL(SvUTF8(sv))))) {
if (! mg) {
mg = sv_magicext(sv, 0, PERL_MAGIC_collxfrm, &PL_vtbl_collxfrm,
0, 0);
}
}
}
+
if (mg && mg->mg_ptr) {
*nxp = mg->mg_len;
return mg->mg_ptr + sizeof(PL_collation_ix);
return;
}
+ /* treat AV/HV/CV/FM/IO and non-fake GVs as immutable */
+ if (SvTYPE(sv) >= SVt_PVAV || (isGV_with_GP(sv) && !SvFAKE(sv)))
+ Perl_croak_no_modify();
+
if (!(flags & SVp_POK) || !*SvPVX_const(sv)) {
if ((flags & SVTYPEMASK) < SVt_PVIV)
sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV ? SVt_PVIV : SVt_IV));
return;
}
}
+
+ /* treat AV/HV/CV/FM/IO and non-fake GVs as immutable */
+ if (SvTYPE(sv) >= SVt_PVAV || (isGV_with_GP(sv) && !SvFAKE(sv)))
+ Perl_croak_no_modify();
+
if (!(flags & SVp_POK)) {
if ((flags & SVTYPEMASK) < SVt_PVIV)
sv_upgrade(sv, ((flags & SVTYPEMASK) > SVt_IV) ? SVt_PVIV : SVt_IV);
if (!todo[(U8)*HeKEY(entry)])
continue;
gv = MUTABLE_GV(HeVAL(entry));
+ if (!isGV(gv))
+ continue;
sv = GvSV(gv);
if (sv && !SvREADONLY(sv)) {
SV_CHECK_THINKFIRST_COW_DROP(sv);
return FALSE;
}
+#ifndef NO_MATHOMS /* Can't move these to mathoms.c because call uiv_2buf(),
+ private to this file */
+
/*
=for apidoc sv_setpviv
SvSETMAGIC(sv);
}
+#endif /* NO_MATHOMS */
+
#if defined(PERL_IMPLICIT_CONTEXT)
/* pTHX_ magic can't cope with varargs, so this is a no-context
=for apidoc sv_vcatpvf
Processes its arguments like C<sv_catpvfn> called with a non-null C-style
-variable argument list, and appends the formatted
+variable argument list, and appends the formatted output
to an SV. Does not handle 'set' magic. See C<L</sv_vcatpvf_mg>>.
Usually used via its frontend C<sv_catpvf>.
U8* v = vhex; /* working pointer to vhex */
U8* vend; /* pointer to one beyond last digit of vhex */
U8* vfnz = NULL; /* first non-zero */
+ U8* vlnz = NULL; /* last non-zero */
const bool lower = (c == 'a');
/* At output the values of vhex (up to vend) will
* be mapped through the xdig to get the actual
const char* xdig = PL_hexdigit;
int zerotail = 0; /* how many extra zeros to append */
int exponent = 0; /* exponent of the floating point input */
+ bool hexradix = FALSE; /* should we output the radix */
/* XXX: denormals, NaN, Inf.
*
# endif
#endif
- if (fv < 0)
+ if (fv < 0
+ || Perl_signbit(nv)
+ )
*p++ = '-';
else if (plus)
*p++ = plus;
}
if (vfnz) {
- U8* vlnz = NULL; /* The last non-zero. */
-
/* Find the last non-zero xdigit. */
for (v = vend - 1; v >= vhex; v--) {
if (*v) {
v = vhex;
*p++ = xdig[*v++];
- /* The radix is always output after the first
- * non-zero xdigit, or if alt. */
- if (vfnz < vlnz || alt) {
+ /* If there are non-zero xdigits, the radix
+ * is output after the first one. */
+ if (vfnz < vlnz) {
+ hexradix = TRUE;
+ }
+ }
+ else {
+ *p++ = '0';
+ exponent = 0;
+ zerotail = precis;
+ }
+
+ /* The radix is always output if precis, or if alt. */
+ if (precis > 0 || alt) {
+ hexradix = TRUE;
+ }
+
+ if (hexradix) {
#ifndef USE_LOCALE_NUMERIC
*p++ = '.';
#else
}
RESTORE_LC_NUMERIC();
#endif
- }
+ }
+ if (vlnz) {
while (v <= vlnz)
*p++ = xdig[*v++];
-
- while (zerotail--)
- *p++ = '0';
}
- else {
+
+ if (zerotail > 0) {
+ while (zerotail--) {
*p++ = '0';
- exponent = 0;
+ }
}
elen = p - PL_efloatbuf;
#if defined(HAS_FCHDIR) && defined(HAS_TELLDIR) && defined(HAS_SEEKDIR)
DIR *pwd;
const Direntry_t *dirent;
- char smallbuf[256];
+ char smallbuf[256]; /* XXX MAXPATHLEN, surely? */
char *name = NULL;
STRLEN len = 0;
long pos;
pos = PerlDir_tell(dp);
if ((dirent = PerlDir_read(dp))) {
len = d_namlen(dirent);
+ if (len > sizeof(dirent->d_name) && sizeof(dirent->d_name) > PTRSIZE) {
+ /* If the len is somehow magically longer than the
+ * maximum length of the directory entry, even though
+ * we could fit it in a buffer, we could not copy it
+ * from the dirent. Bail out. */
+ PerlDir_close(ret);
+ return (DIR*)NULL;
+ }
if (len <= sizeof smallbuf) name = smallbuf;
else Newx(name, len, char);
Move(dirent->d_name, name, len, char);
ncx->blk_oldcop = (COP*)any_dup(ncx->blk_oldcop, param->proto_perl);
switch (CxTYPE(ncx)) {
case CXt_SUB:
- ncx->blk_sub.cv = (ncx->blk_sub.olddepth == 0
- ? cv_dup_inc(ncx->blk_sub.cv, param)
- : cv_dup(ncx->blk_sub.cv,param));
+ ncx->blk_sub.cv = cv_dup_inc(ncx->blk_sub.cv, param);
if(CxHASARGS(ncx)){
- ncx->blk_sub.argarray = av_dup_inc(ncx->blk_sub.argarray,param);
ncx->blk_sub.savearray = av_dup_inc(ncx->blk_sub.savearray,param);
} else {
- ncx->blk_sub.argarray = NULL;
ncx->blk_sub.savearray = NULL;
}
- ncx->blk_sub.oldcomppad = (PAD*)ptr_table_fetch(PL_ptr_table,
- ncx->blk_sub.oldcomppad);
+ ncx->blk_sub.prevcomppad = (PAD*)ptr_table_fetch(PL_ptr_table,
+ ncx->blk_sub.prevcomppad);
break;
case CXt_EVAL:
ncx->blk_eval.old_namesv = sv_dup_inc(ncx->blk_eval.old_namesv,
param);
+ /* XXX should this sv_dup_inc? Or only if SvSCREAM ???? */
ncx->blk_eval.cur_text = sv_dup(ncx->blk_eval.cur_text, param);
ncx->blk_eval.cv = cv_dup(ncx->blk_eval.cv, param);
+ /* XXX what do do with cur_top_env ???? */
break;
case CXt_LOOP_LAZYSV:
ncx->blk_loop.state_u.lazysv.end
assert ((void *) &ncx->blk_loop.state_u.ary.ary ==
(void *) &ncx->blk_loop.state_u.lazysv.cur);
/* FALLTHROUGH */
- case CXt_LOOP_FOR:
+ case CXt_LOOP_ARY:
ncx->blk_loop.state_u.ary.ary
= av_dup_inc(ncx->blk_loop.state_u.ary.ary, param);
/* FALLTHROUGH */
+ case CXt_LOOP_LIST:
case CXt_LOOP_LAZYIV:
- case CXt_LOOP_PLAIN:
- /* code common to all CXt_LOOP_* types */
+ /* code common to all 'for' CXt_LOOP_* types */
+ ncx->blk_loop.itersave =
+ sv_dup_inc(ncx->blk_loop.itersave, param);
if (CxPADLOOP(ncx)) {
- ncx->blk_loop.itervar_u.oldcomppad
- = (PAD*)ptr_table_fetch(PL_ptr_table,
- ncx->blk_loop.itervar_u.oldcomppad);
- } else {
+ PADOFFSET off = ncx->blk_loop.itervar_u.svp
+ - &CX_CURPAD_SV(ncx->blk_loop, 0);
+ ncx->blk_loop.oldcomppad =
+ (PAD*)ptr_table_fetch(PL_ptr_table,
+ ncx->blk_loop.oldcomppad);
+ ncx->blk_loop.itervar_u.svp =
+ &CX_CURPAD_SV(ncx->blk_loop, off);
+ }
+ else {
+ /* this copies the GV if CXp_FOR_GV, or the SV for an
+ * alias (for \$x (...)) - relies on gv_dup being the
+ * same as sv_dup */
ncx->blk_loop.itervar_u.gv
= gv_dup((const GV *)ncx->blk_loop.itervar_u.gv,
param);
}
break;
+ case CXt_LOOP_PLAIN:
+ break;
case CXt_FORMAT:
- ncx->blk_format.cv = cv_dup(ncx->blk_format.cv, param);
+ ncx->blk_format.prevcomppad =
+ (PAD*)ptr_table_fetch(PL_ptr_table,
+ ncx->blk_format.prevcomppad);
+ ncx->blk_format.cv = cv_dup_inc(ncx->blk_format.cv, param);
ncx->blk_format.gv = gv_dup(ncx->blk_format.gv, param);
ncx->blk_format.dfoutgv = gv_dup_inc(ncx->blk_format.dfoutgv,
param);
break;
+ case CXt_GIVEN:
+ ncx->blk_givwhen.defsv_save =
+ sv_dup_inc(ncx->blk_givwhen.defsv_save, param);
+ break;
case CXt_BLOCK:
case CXt_NULL:
case CXt_WHEN:
- case CXt_GIVEN:
break;
}
}
{
dVAR;
ANY * const ss = proto_perl->Isavestack;
- const I32 max = proto_perl->Isavestack_max;
+ const I32 max = proto_perl->Isavestack_max + SS_MAXPUSH;
I32 ix = proto_perl->Isavestack_ix;
ANY *nss;
const SV *sv;
iv = POPIV(ss,ix);
TOPIV(nss,ix) = iv;
break;
+ case SAVEt_TMPSFLOOR:
+ iv = POPIV(ss,ix);
+ TOPIV(nss,ix) = iv;
+ break;
case SAVEt_HPTR: /* HV* reference */
case SAVEt_APTR: /* AV* reference */
case SAVEt_SPTR: /* SV* reference */
PL_collation_standard = proto_perl->Icollation_standard;
PL_collxfrm_base = proto_perl->Icollxfrm_base;
PL_collxfrm_mult = proto_perl->Icollxfrm_mult;
+ PL_strxfrm_max_cp = proto_perl->Istrxfrm_max_cp;
#endif /* USE_LOCALE_COLLATE */
#ifdef USE_LOCALE_NUMERIC
/* Did the locale setup indicate UTF-8? */
PL_utf8locale = proto_perl->Iutf8locale;
PL_in_utf8_CTYPE_locale = proto_perl->Iin_utf8_CTYPE_locale;
+ PL_in_utf8_COLLATE_locale = proto_perl->Iin_utf8_COLLATE_locale;
/* Unicode features (see perlrun/-C) */
PL_unicode = proto_perl->Iunicode;
If C<sv> already is UTF-8 (or if it is not C<POK>), or if C<encoding>
is not a reference, nothing is done to C<sv>. If C<encoding> is not
an C<Encode::XS> Encoding object, bad things will happen.
-(See F<lib/encoding.pm> and L<Encode>.)
+(See F<cpan/Encode/encoding.pm> and L<Encode>.)
The PV of C<sv> is returned.
sv_insert(varname, 0, 0, " ", 1);
}
}
- else if (PL_curstackinfo->si_type == PERLSI_SORT
- && CxMULTICALL(&cxstack[cxstack_ix]))
- {
+ else if (PL_curstackinfo->si_type == PERLSI_SORT && cxstack_ix == 0)
/* we've reached the end of a sort block or sub,
* and the uninit value is probably what that code returned */
desc = "sort";
- }
/* PL_warn_uninit_sv is constant */
GCC_DIAG_IGNORE(-Wformat-nonliteral);