/* sv.c
*
* Copyright (C) 1991, 1992, 1993, 1994, 1995, 1996, 1997, 1998, 1999,
- * 2000, 2001, 2002, 2003, 2004, 2005, 2006, by Larry Wall and others
+ * 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, by Larry Wall and others
*
* You may distribute under the terms of either the GNU General Public
* License or the Artistic License, as specified in the README file.
* lib/utf8.t lib/Unicode/Collate/t/index.t
* --jhi
*/
-#define ASSERT_UTF8_CACHE(cache) \
+# define ASSERT_UTF8_CACHE(cache) \
STMT_START { if (cache) { assert((cache)[0] <= (cache)[1]); \
assert((cache)[2] <= (cache)[3]); \
assert((cache)[3] <= (cache)[1]);} \
} STMT_END
#else
-#define ASSERT_UTF8_CACHE(cache) NOOP
+# define ASSERT_UTF8_CACHE(cache) NOOP
#endif
#ifdef PERL_OLD_COPY_ON_WRITE
perl_destruct() to physically free all the arenas allocated since the
start of the interpreter.
-Manipulation of any of the PL_*root pointers is protected by enclosing
-LOCK_SV_MUTEX; ... UNLOCK_SV_MUTEX calls which should Do the Right Thing
-if threads are enabled.
-
The function visit() scans the SV arenas list, and calls a specified
function for each SV it finds which is still live - ie which has an SvTYPE
other than all 1's, and a non-zero SvREFCNT. visit() is used by the
* "A time to plant, and a time to uproot what was planted..."
*/
-/*
- * nice_chunk and nice_chunk size need to be set
- * and queried under the protection of sv_mutex
- */
void
-Perl_offer_nice_chunk(pTHX_ void *chunk, U32 chunk_size)
+Perl_offer_nice_chunk(pTHX_ void *const chunk, const U32 chunk_size)
{
dVAR;
void *new_chunk;
U32 new_chunk_size;
- LOCK_SV_MUTEX;
+
+ PERL_ARGS_ASSERT_OFFER_NICE_CHUNK;
+
new_chunk = (void *)(chunk);
new_chunk_size = (chunk_size);
if (new_chunk_size > PL_nice_chunk_size) {
} else {
Safefree(chunk);
}
- UNLOCK_SV_MUTEX;
}
#ifdef DEBUG_LEAKING_SCALARS
--PL_sv_count; \
} STMT_END
-/* sv_mutex must be held while calling uproot_SV() */
#define uproot_SV(p) \
STMT_START { \
(p) = PL_sv_root; \
/* make some more SVs by adding another arena */
-/* sv_mutex must be held while calling more_sv() */
STATIC SV*
S_more_sv(pTHX)
{
{
SV* sv;
- LOCK_SV_MUTEX;
if (PL_sv_root)
uproot_SV(sv);
else
sv = S_more_sv(aTHX);
- UNLOCK_SV_MUTEX;
SvANY(sv) = 0;
SvREFCNT(sv) = 1;
SvFLAGS(sv) = 0;
sv->sv_debug_optype = PL_op ? PL_op->op_type : 0;
- sv->sv_debug_line = (U16) ((PL_copline == NOLINE) ?
- (PL_curcop ? CopLINE(PL_curcop) : 0) : PL_copline);
+ sv->sv_debug_line = (U16) (PL_parser
+ ? PL_parser->copline == NOLINE
+ ? PL_curcop
+ ? CopLINE(PL_curcop)
+ : 0
+ : PL_parser->copline
+ : 0);
sv->sv_debug_inpad = 0;
sv->sv_debug_cloned = 0;
sv->sv_debug_file = PL_curcop ? savepv(CopFILE(PL_curcop)): NULL;
#else
# define new_SV(p) \
STMT_START { \
- LOCK_SV_MUTEX; \
if (PL_sv_root) \
uproot_SV(p); \
else \
(p) = S_more_sv(aTHX); \
- UNLOCK_SV_MUTEX; \
SvANY(p) = 0; \
SvREFCNT(p) = 1; \
SvFLAGS(p) = 0; \
#define del_SV(p) \
STMT_START { \
- LOCK_SV_MUTEX; \
if (DEBUG_D_TEST) \
del_sv(p); \
else \
plant_SV(p); \
- UNLOCK_SV_MUTEX; \
} STMT_END
STATIC void
S_del_sv(pTHX_ SV *p)
{
dVAR;
+
+ PERL_ARGS_ASSERT_DEL_SV;
+
if (DEBUG_D_TEST) {
SV* sva;
bool ok = 0;
*/
void
-Perl_sv_add_arena(pTHX_ char *ptr, U32 size, U32 flags)
+Perl_sv_add_arena(pTHX_ char *const ptr, const U32 size, const U32 flags)
{
dVAR;
SV* const sva = (SV*)ptr;
register SV* sv;
register SV* svend;
+ PERL_ARGS_ASSERT_SV_ADD_ARENA;
+
/* The first SV in an arena isn't an SV. */
SvANY(sva) = (void *) PL_sv_arenaroot; /* ptr to next arena */
SvREFCNT(sva) = size / sizeof(SV); /* number of SV slots */
#ifdef DEBUGGING
SvREFCNT(sv) = 0;
#endif
- /* Must always set typemask because it's awlays checked in on cleanup
+ /* Must always set typemask because it's always checked in on cleanup
when the arenas are walked looking for objects. */
SvFLAGS(sv) = SVTYPEMASK;
sv++;
* whose flags field matches the flags/mask args. */
STATIC I32
-S_visit(pTHX_ SVFUNC_t f, U32 flags, U32 mask)
+S_visit(pTHX_ SVFUNC_t f, const U32 flags, const U32 mask)
{
dVAR;
SV* sva;
I32 visited = 0;
+ PERL_ARGS_ASSERT_VISIT;
+
for (sva = PL_sv_arenaroot; sva; sva = (SV*)SvANY(sva)) {
register const SV * const svend = &sva[SvREFCNT(sva)];
register SV* sv;
/* called by sv_clean_objs() for each live SV */
static void
-do_clean_objs(pTHX_ SV *ref)
+do_clean_objs(pTHX_ SV *const ref)
{
dVAR;
- if (SvROK(ref)) {
+ assert (SvROK(ref));
+ {
SV * const target = SvRV(ref);
if (SvOBJECT(target)) {
DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning object ref:\n "), sv_dump(ref)));
#ifndef DISABLE_DESTRUCTOR_KLUDGE
static void
-do_clean_named_objs(pTHX_ SV *sv)
+do_clean_named_objs(pTHX_ SV *const sv)
{
dVAR;
- if (SvTYPE(sv) == SVt_PVGV && isGV_with_GP(sv) && GvGP(sv)) {
+ assert(SvTYPE(sv) == SVt_PVGV);
+ assert(isGV_with_GP(sv));
+ if (GvGP(sv)) {
if ((
#ifdef PERL_DONT_CREATE_GVSV
GvSV(sv) &&
SvOBJECT(GvSV(sv))) ||
(GvAV(sv) && SvOBJECT(GvAV(sv))) ||
(GvHV(sv) && SvOBJECT(GvHV(sv))) ||
- (GvIO(sv) && SvOBJECT(GvIO(sv))) ||
+ /* In certain rare cases GvIOp(sv) can be NULL, which would make SvOBJECT(GvIO(sv)) dereference NULL. */
+ (GvIO(sv) ? (SvFLAGS(GvIOp(sv)) & SVs_OBJECT) : 0) ||
(GvCV(sv) && SvOBJECT(GvCV(sv))) )
{
DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning named glob object:\n "), sv_dump(sv)));
visit(do_clean_objs, SVf_ROK, SVf_ROK);
#ifndef DISABLE_DESTRUCTOR_KLUDGE
/* some barnacles may yet remain, clinging to typeglobs */
- visit(do_clean_named_objs, SVt_PVGV, SVTYPEMASK);
+ visit(do_clean_named_objs, SVt_PVGV|SVpgv_GP, SVTYPEMASK|SVp_POK|SVpgv_GP);
#endif
PL_in_clean_objs = FALSE;
}
/* called by sv_clean_all() for each live SV */
static void
-do_clean_all(pTHX_ SV *sv)
+do_clean_all(pTHX_ SV *const sv)
{
dVAR;
DEBUG_D((PerlIO_printf(Perl_debug_log, "Cleaning loops: SV at 0x%"UVxf"\n", PTR2UV(sv)) ));
SvFLAGS(sv) |= SVf_BREAK;
- if (PL_comppad == (AV*)sv) {
- PL_comppad = NULL;
- PL_curpad = NULL;
- }
SvREFCNT_dec(sv);
}
arena_descs, each holding info for a single arena. By separating
the meta-info from the arena, we recover the 1st slot, formerly
borrowed for list management. The arena_set is about the size of an
- arena, avoiding the needless malloc overhead of a naive linked-list
+ arena, avoiding the needless malloc overhead of a naive linked-list.
The cost is 1 arena-set malloc per ~320 arena-mallocs, + the unused
memory in the last arena-set (1/2 on average). In trade, we get
back the 1st slot in each arena (ie 1.7% of a CV-arena, less for
smaller types). The recovery of the wasted space allows use of
- small arenas for large, rare body types,
+ small arenas for large, rare body types, by changing array* fields
+ in body_details_by_type[] below.
*/
struct arena_desc {
char *arena; /* the raw storage, allocated aligned */
size_t size; /* its size ~4k typ */
- int unit_type; /* useful for arena audits */
- /* info for sv-heads (eventually)
- int count, flags;
- */
+ U32 misc; /* type, and in future other things. */
};
struct arena_set;
/* Get the maximum number of elements in set[] such that struct arena_set
- will fit within PERL_ARENA_SIZE, which is probabably just under 4K, and
+ will fit within PERL_ARENA_SIZE, which is probably just under 4K, and
therefore likely to be 1 aligned memory page. */
#define ARENAS_PER_SET ((PERL_ARENA_SIZE - sizeof(struct arena_set*) \
struct arena_set {
struct arena_set* next;
- int set_size; /* ie ARENAS_PER_SET */
- int curr; /* index of next available arena-desc */
+ unsigned int set_size; /* ie ARENAS_PER_SET */
+ unsigned int curr; /* index of next available arena-desc */
struct arena_desc set[ARENAS_PER_SET];
};
dVAR;
SV* sva;
SV* svanext;
- int i;
+ unsigned int i;
/* Free arenas here, but be careful about fake ones. (We assume
contiguity of the fake ones with the corresponding real ones.) */
}
{
- struct arena_set *next, *aroot = (struct arena_set*) PL_body_arenas;
-
- for (; aroot; aroot = next) {
- const int max = aroot->curr;
- for (i=0; i<max; i++) {
+ struct arena_set *aroot = (struct arena_set*) PL_body_arenas;
+
+ while (aroot) {
+ struct arena_set *current = aroot;
+ i = aroot->curr;
+ while (i--) {
assert(aroot->set[i].arena);
Safefree(aroot->set[i].arena);
}
- next = aroot->next;
- Safefree(aroot);
+ aroot = aroot->next;
+ Safefree(current);
}
}
PL_body_arenas = 0;
- for (i=0; i<PERL_ARENA_ROOTS_SIZE; i++)
+ i = PERL_ARENA_ROOTS_SIZE;
+ while (i--)
PL_body_roots[i] = 0;
Safefree(PL_nice_chunk);
TBD: export properly for hv.c: S_more_he().
*/
void*
-Perl_get_arena(pTHX_ int arena_size)
+Perl_get_arena(pTHX_ const size_t arena_size, const U32 misc)
{
+ dVAR;
struct arena_desc* adesc;
- struct arena_set *newroot, **aroot = (struct arena_set**) &PL_body_arenas;
- int curr;
+ struct arena_set *aroot = (struct arena_set*) PL_body_arenas;
+ unsigned int curr;
/* shouldnt need this
if (!arena_size) arena_size = PERL_ARENA_SIZE;
*/
/* may need new arena-set to hold new arena */
- if (!*aroot || (*aroot)->curr >= (*aroot)->set_size) {
+ if (!aroot || aroot->curr >= aroot->set_size) {
+ struct arena_set *newroot;
Newxz(newroot, 1, struct arena_set);
newroot->set_size = ARENAS_PER_SET;
- newroot->next = *aroot;
- *aroot = newroot;
- DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", *aroot));
+ newroot->next = aroot;
+ aroot = newroot;
+ PL_body_arenas = (void *) newroot;
+ DEBUG_m(PerlIO_printf(Perl_debug_log, "new arenaset %p\n", (void*)aroot));
}
/* ok, now have arena-set with at least 1 empty/available arena-desc */
- curr = (*aroot)->curr++;
- adesc = &((*aroot)->set[curr]);
+ curr = aroot->curr++;
+ adesc = &(aroot->set[curr]);
assert(!adesc->arena);
- Newxz(adesc->arena, arena_size, char);
+ Newx(adesc->arena, arena_size, char);
adesc->size = arena_size;
- DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p size %d\n",
- curr, adesc->arena, arena_size));
+ adesc->misc = misc;
+ DEBUG_m(PerlIO_printf(Perl_debug_log, "arena %d added: %p size %"UVuf"\n",
+ curr, (void*)adesc->arena, (UV)arena_size));
return adesc->arena;
}
#define del_body(thing, root) \
STMT_START { \
void ** const thing_copy = (void **)thing;\
- LOCK_SV_MUTEX; \
*thing_copy = *root; \
*root = (void*)thing_copy; \
- UNLOCK_SV_MUTEX; \
} STMT_END
/*
For the sv-types that have no bodies, arenas are not used, so those
PL_body_roots[sv_type] are unused, and can be overloaded. In
something of a special case, SVt_NULL is borrowed for HE arenas;
-PL_body_roots[SVt_NULL] is filled by S_more_he, but the
+PL_body_roots[HE_SVSLOT=SVt_NULL] is filled by S_more_he, but the
bodies_by_type[SVt_NULL] slot is not used, as the table is not
-available in hv.c,
+available in hv.c.
-PTEs also use arenas, but are never seen in Perl_sv_upgrade.
-Nonetheless, they get their own slot in bodies_by_type[SVt_NULL], so
-they can just use the same allocation semantics. At first, PTEs were
-also overloaded to a non-body sv-type, but this yielded hard-to-find
-malloc bugs, so was simplified by claiming a new slot. This choice
-has no consequence at this time.
+PTEs also use arenas, but are never seen in Perl_sv_upgrade. Nonetheless,
+they get their own slot in bodies_by_type[PTE_SVSLOT =SVt_IV], so they can
+just use the same allocation semantics. At first, PTEs were also
+overloaded to a non-body sv-type, but this yielded hard-to-find malloc
+bugs, so was simplified by claiming a new slot. This choice has no
+consequence at this time.
*/
{ sizeof(HE), 0, 0, SVt_NULL,
FALSE, NONV, NOARENA, FIT_ARENA(0, sizeof(HE)) },
+ /* The bind placeholder pretends to be an RV for now.
+ Also it's marked as "can't upgrade" to stop anyone using it before it's
+ implemented. */
+ { 0, 0, 0, SVt_BIND, TRUE, NONV, NOARENA, 0 },
+
/* IVs are in the head, so the allocation size is 0.
However, the slot is overloaded for PTEs. */
{ sizeof(struct ptr_tbl_ent), /* This is used for PTEs. */
{ sizeof(NV), sizeof(NV), 0, SVt_NV, FALSE, HADNV, HASARENA,
FIT_ARENA(0, sizeof(NV)) },
- /* RVs are in the head now. */
- { 0, 0, 0, SVt_RV, FALSE, NONV, NOARENA, 0 },
-
/* 8 bytes on most ILP32 with IEEE doubles */
{ sizeof(xpv_allocated),
copy_length(XPV, xpv_len)
/* 28 */
{ sizeof(XPVMG), copy_length(XPVMG, xmg_stash), 0, SVt_PVMG, FALSE, HADNV,
HASARENA, FIT_ARENA(0, sizeof(XPVMG)) },
-
- /* 36 */
- { sizeof(XPVBM), sizeof(XPVBM), 0, SVt_PVBM, TRUE, HADNV,
- HASARENA, FIT_ARENA(0, sizeof(XPVBM)) },
+
+ /* something big */
+ { sizeof(struct regexp_allocated), sizeof(struct regexp_allocated),
+ + relative_STRUCT_OFFSET(struct regexp_allocated, regexp, xpv_cur),
+ SVt_REGEXP, FALSE, NONV, HASARENA,
+ FIT_ARENA(0, sizeof(struct regexp_allocated))
+ },
/* 48 */
{ sizeof(XPVGV), sizeof(XPVGV), 0, SVt_PVGV, TRUE, HADNV,
copy_length(XPVAV, xmg_stash)
- relative_STRUCT_OFFSET(xpvav_allocated, XPVAV, xav_fill),
+ relative_STRUCT_OFFSET(xpvav_allocated, XPVAV, xav_fill),
- SVt_PVAV, TRUE, HADNV, HASARENA, FIT_ARENA(0, sizeof(xpvav_allocated)) },
+ SVt_PVAV, TRUE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpvav_allocated)) },
{ sizeof(xpvhv_allocated),
copy_length(XPVHV, xmg_stash)
- relative_STRUCT_OFFSET(xpvhv_allocated, XPVHV, xhv_fill),
+ relative_STRUCT_OFFSET(xpvhv_allocated, XPVHV, xhv_fill),
- SVt_PVHV, TRUE, HADNV, HASARENA, FIT_ARENA(0, sizeof(xpvhv_allocated)) },
+ SVt_PVHV, TRUE, NONV, HASARENA, FIT_ARENA(0, sizeof(xpvhv_allocated)) },
/* 56 */
{ sizeof(xpvcv_allocated), sizeof(xpvcv_allocated),
SVt_PVFM, TRUE, NONV, NOARENA, FIT_ARENA(20, sizeof(xpvfm_allocated)) },
/* XPVIO is 84 bytes, fits 48x */
- { sizeof(XPVIO), sizeof(XPVIO), 0, SVt_PVIO, TRUE, HADNV,
- HASARENA, FIT_ARENA(24, sizeof(XPVIO)) },
+ { sizeof(xpvio_allocated), sizeof(xpvio_allocated),
+ + relative_STRUCT_OFFSET(xpvio_allocated, XPVIO, xpv_cur),
+ SVt_PVIO, TRUE, NONV, HASARENA, FIT_ARENA(24, sizeof(xpvio_allocated)) },
};
#define new_body_type(sv_type) \
#define new_NOARENAZ(details) \
my_safecalloc((details)->body_size + (details)->offset)
-#ifdef DEBUGGING
-static bool done_sanity_check;
-#endif
-
STATIC void *
-S_more_bodies (pTHX_ svtype sv_type)
+S_more_bodies (pTHX_ const svtype sv_type)
{
dVAR;
void ** const root = &PL_body_roots[sv_type];
const size_t body_size = bdp->body_size;
char *start;
const char *end;
+#if defined(DEBUGGING) && !defined(PERL_GLOBAL_STRUCT_PRIVATE)
+ static bool done_sanity_check;
- assert(bdp->arena_size);
-
-#ifdef DEBUGGING
+ /* PERL_GLOBAL_STRUCT_PRIVATE cannot coexist with global
+ * variables like done_sanity_check. */
if (!done_sanity_check) {
unsigned int i = SVt_LAST;
}
#endif
- start = (char*) Perl_get_arena(aTHX_ bdp->arena_size);
+ assert(bdp->arena_size);
+
+ start = (char*) Perl_get_arena(aTHX_ bdp->arena_size, sv_type);
end = start + bdp->arena_size - body_size;
/* computed count doesnt reflect the 1st slot reservation */
DEBUG_m(PerlIO_printf(Perl_debug_log,
"arena %p end %p arena-size %d type %d size %d ct %d\n",
- start, end, bdp->arena_size, sv_type, body_size,
- bdp->arena_size / body_size));
+ (void*)start, (void*)end,
+ (int)bdp->arena_size, sv_type, (int)body_size,
+ (int)bdp->arena_size / (int)body_size));
*root = (void *)start;
#define new_body_inline(xpv, sv_type) \
STMT_START { \
void ** const r3wt = &PL_body_roots[sv_type]; \
- LOCK_SV_MUTEX; \
- xpv = *((void **)(r3wt)) \
- ? *((void **)(r3wt)) : more_bodies(sv_type); \
+ xpv = (PTR_TBL_ENT_t*) (*((void **)(r3wt)) \
+ ? *((void **)(r3wt)) : more_bodies(sv_type)); \
*(r3wt) = *(void**)(xpv); \
- UNLOCK_SV_MUTEX; \
} STMT_END
#ifndef PURIFY
STATIC void *
-S_new_body(pTHX_ svtype sv_type)
+S_new_body(pTHX_ const svtype sv_type)
{
dVAR;
void *xpv;
#endif
+static const struct body_details fake_rv =
+ { 0, 0, 0, SVt_IV, FALSE, NONV, NOARENA, 0 };
+
/*
=for apidoc sv_upgrade
*/
void
-Perl_sv_upgrade(pTHX_ register SV *sv, U32 new_type)
+Perl_sv_upgrade(pTHX_ register SV *const sv, svtype new_type)
{
dVAR;
void* old_body;
void* new_body;
- const U32 old_type = SvTYPE(sv);
+ const svtype old_type = SvTYPE(sv);
const struct body_details *new_type_details;
- const struct body_details *const old_type_details
+ const struct body_details *old_type_details
= bodies_by_type + old_type;
+ SV *referant = NULL;
+
+ PERL_ARGS_ASSERT_SV_UPGRADE;
if (new_type != SVt_PV && SvIsCOW(sv)) {
sv_force_normal_flags(sv, 0);
if (old_type == new_type)
return;
- if (old_type > new_type)
- Perl_croak(aTHX_ "sv_upgrade from type %d down to type %d",
- (int)old_type, (int)new_type);
-
-
old_body = SvANY(sv);
/* Copying structures onto other structures that have been neatly zeroed
(In fact, GP ends up pointing at a previous GP structure, because the
principle cause of the padding in XPVMG getting garbage is a copy of
- sizeof(XPVMG) bytes from a XPVGV structure in sv_unglob)
+ sizeof(XPVMG) bytes from a XPVGV structure in sv_unglob. Right now
+ this happens to be moot because XPVGV has been re-ordered, with GP
+ no longer after STASH)
So we are careful and work out the size of used parts of all the
structures. */
case SVt_NULL:
break;
case SVt_IV:
- if (new_type < SVt_PVIV) {
- new_type = (new_type == SVt_NV)
- ? SVt_PVNV : SVt_PVIV;
+ if (SvROK(sv)) {
+ referant = SvRV(sv);
+ old_type_details = &fake_rv;
+ if (new_type == SVt_NV)
+ new_type = SVt_PVNV;
+ } else {
+ if (new_type < SVt_PVIV) {
+ new_type = (new_type == SVt_NV)
+ ? SVt_PVNV : SVt_PVIV;
+ }
}
break;
case SVt_NV:
new_type = SVt_PVNV;
}
break;
- case SVt_RV:
- break;
case SVt_PV:
assert(new_type > SVt_PV);
assert(SVt_IV < SVt_PV);
Perl_croak(aTHX_ "Can't upgrade %s (%" UVuf ") to %" UVuf,
sv_reftype(sv, 0), (UV) old_type, (UV) new_type);
}
+
+ if (old_type > new_type)
+ Perl_croak(aTHX_ "sv_upgrade from type %d down to type %d",
+ (int)old_type, (int)new_type);
+
new_type_details = bodies_by_type + new_type;
SvFLAGS(sv) &= ~SVTYPEMASK;
SvANY(sv) = new_XNV();
SvNV_set(sv, 0);
return;
- case SVt_RV:
- assert(old_type == SVt_NULL);
- SvANY(sv) = &sv->sv_u.svu_rv;
- SvRV_set(sv, 0);
- return;
case SVt_PVHV:
case SVt_PVAV:
assert(new_type_details->body_size);
AvMAX(sv) = -1;
AvFILLp(sv) = -1;
AvREAL_only(sv);
+ if (old_type_details->body_size) {
+ AvALLOC(sv) = 0;
+ } else {
+ /* It will have been zeroed when the new body was allocated.
+ Lets not write to it, in case it confuses a write-back
+ cache. */
+ }
+ } else {
+ assert(!SvOK(sv));
+ SvOK_off(sv);
+#ifndef NODEFAULT_SHAREKEYS
+ HvSHAREKEYS_on(sv); /* key-sharing on by default */
+#endif
+ HvMAX(sv) = 7; /* (start with 8 buckets) */
+ if (old_type_details->body_size) {
+ HvFILL(sv) = 0;
+ } else {
+ /* It will have been zeroed when the new body was allocated.
+ Lets not write to it, in case it confuses a write-back
+ cache. */
+ }
}
/* SVt_NULL isn't the only thing upgraded to AV or HV.
The target created by newSVrv also is, and it can have magic.
However, it never has SvPVX set.
*/
- if (old_type >= SVt_RV) {
+ if (old_type == SVt_IV) {
+ assert(!SvROK(sv));
+ } else if (old_type >= SVt_PV) {
assert(SvPVX_const(sv) == 0);
}
- /* Could put this in the else clause below, as PVMG must have SvPVX
- 0 already (the assertion above) */
- SvPV_set(sv, NULL);
-
if (old_type >= SVt_PVMG) {
SvMAGIC_set(sv, ((XPVMG*)old_body)->xmg_u.xmg_magic);
SvSTASH_set(sv, ((XPVMG*)old_body)->xmg_stash);
+ } else {
+ sv->sv_u.svu_array = NULL; /* or svu_hash */
}
break;
assert(!SvNOK(sv));
case SVt_PVIO:
case SVt_PVFM:
- case SVt_PVBM:
case SVt_PVGV:
case SVt_PVCV:
case SVt_PVLV:
+ case SVt_REGEXP:
case SVt_PVMG:
case SVt_PVNV:
case SVt_PV:
* NV slot, but the new one does, then we need to initialise the
* freshly created NV slot with whatever the correct bit pattern is
* for 0.0 */
- if (old_type_details->zero_nv && !new_type_details->zero_nv)
+ if (old_type_details->zero_nv && !new_type_details->zero_nv
+ && !isGV_with_GP(sv))
SvNV_set(sv, 0);
#endif
if (new_type == SVt_PVIO)
IoPAGE_LEN(sv) = 60;
- if (old_type < SVt_RV)
- SvPV_set(sv, NULL);
+ if (old_type < SVt_PV) {
+ /* referant will be NULL unless the old type was SVt_IV emulating
+ SVt_RV */
+ sv->sv_u.svu_rv = referant;
+ }
break;
default:
Perl_croak(aTHX_ "panic: sv_upgrade to unknown type %lu",
*/
int
-Perl_sv_backoff(pTHX_ register SV *sv)
+Perl_sv_backoff(pTHX_ register SV *const sv)
{
+ STRLEN delta;
+ const char * const s = SvPVX_const(sv);
+
+ PERL_ARGS_ASSERT_SV_BACKOFF;
PERL_UNUSED_CONTEXT;
+
assert(SvOOK(sv));
assert(SvTYPE(sv) != SVt_PVHV);
assert(SvTYPE(sv) != SVt_PVAV);
- if (SvIVX(sv)) {
- const char * const s = SvPVX_const(sv);
- SvLEN_set(sv, SvLEN(sv) + SvIVX(sv));
- SvPV_set(sv, SvPVX(sv) - SvIVX(sv));
- SvIV_set(sv, 0);
- Move(s, SvPVX(sv), SvCUR(sv)+1, char);
- }
+
+ SvOOK_offset(sv, delta);
+
+ SvLEN_set(sv, SvLEN(sv) + delta);
+ SvPV_set(sv, SvPVX(sv) - delta);
+ Move(s, SvPVX(sv), SvCUR(sv)+1, char);
SvFLAGS(sv) &= ~SVf_OOK;
return 0;
}
*/
char *
-Perl_sv_grow(pTHX_ register SV *sv, register STRLEN newlen)
+Perl_sv_grow(pTHX_ register SV *const sv, register STRLEN newlen)
{
register char *s;
+ PERL_ARGS_ASSERT_SV_GROW;
+
if (PL_madskills && newlen >= 0x100000) {
PerlIO_printf(Perl_debug_log,
"Allocation too large: %"UVxf"\n", (UV)newlen);
return s;
} else
#endif
- s = saferealloc(s, newlen);
+ s = (char*)saferealloc(s, newlen);
}
else {
- s = safemalloc(newlen);
+ s = (char*)safemalloc(newlen);
if (SvPVX_const(sv) && SvCUR(sv)) {
Move(SvPVX_const(sv), s, (newlen < SvCUR(sv)) ? newlen : SvCUR(sv), char);
}
*/
void
-Perl_sv_setiv(pTHX_ register SV *sv, IV i)
+Perl_sv_setiv(pTHX_ register SV *const sv, const IV i)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_SETIV;
+
SV_CHECK_THINKFIRST_COW_DROP(sv);
switch (SvTYPE(sv)) {
case SVt_NULL:
- sv_upgrade(sv, SVt_IV);
- break;
case SVt_NV:
- sv_upgrade(sv, SVt_PVNV);
+ sv_upgrade(sv, SVt_IV);
break;
- case SVt_RV:
case SVt_PV:
sv_upgrade(sv, SVt_PVIV);
break;
case SVt_PVIO:
Perl_croak(aTHX_ "Can't coerce %s to integer in %s", sv_reftype(sv,0),
OP_DESC(PL_op));
+ default: NOOP;
}
(void)SvIOK_only(sv); /* validate number */
SvIV_set(sv, i);
*/
void
-Perl_sv_setiv_mg(pTHX_ register SV *sv, IV i)
+Perl_sv_setiv_mg(pTHX_ register SV *const sv, const IV i)
{
+ PERL_ARGS_ASSERT_SV_SETIV_MG;
+
sv_setiv(sv,i);
SvSETMAGIC(sv);
}
*/
void
-Perl_sv_setuv(pTHX_ register SV *sv, UV u)
+Perl_sv_setuv(pTHX_ register SV *const sv, const UV u)
{
+ PERL_ARGS_ASSERT_SV_SETUV;
+
/* With these two if statements:
u=1.49 s=0.52 cu=72.49 cs=10.64 scripts=270 tests=20865
*/
void
-Perl_sv_setuv_mg(pTHX_ register SV *sv, UV u)
+Perl_sv_setuv_mg(pTHX_ register SV *const sv, const UV u)
{
- sv_setiv(sv, 0);
- SvIsUV_on(sv);
+ PERL_ARGS_ASSERT_SV_SETUV_MG;
+
sv_setuv(sv,u);
SvSETMAGIC(sv);
}
*/
void
-Perl_sv_setnv(pTHX_ register SV *sv, NV num)
+Perl_sv_setnv(pTHX_ register SV *const sv, const NV num)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_SETNV;
+
SV_CHECK_THINKFIRST_COW_DROP(sv);
switch (SvTYPE(sv)) {
case SVt_NULL:
case SVt_IV:
sv_upgrade(sv, SVt_NV);
break;
- case SVt_RV:
case SVt_PV:
case SVt_PVIV:
sv_upgrade(sv, SVt_PVNV);
case SVt_PVIO:
Perl_croak(aTHX_ "Can't coerce %s to number in %s", sv_reftype(sv,0),
OP_NAME(PL_op));
+ default: NOOP;
}
SvNV_set(sv, num);
(void)SvNOK_only(sv); /* validate number */
*/
void
-Perl_sv_setnv_mg(pTHX_ register SV *sv, NV num)
+Perl_sv_setnv_mg(pTHX_ register SV *const sv, const NV num)
{
+ PERL_ARGS_ASSERT_SV_SETNV_MG;
+
sv_setnv(sv,num);
SvSETMAGIC(sv);
}
*/
STATIC void
-S_not_a_number(pTHX_ SV *sv)
+S_not_a_number(pTHX_ SV *const sv)
{
dVAR;
SV *dsv;
char tmpbuf[64];
const char *pv;
+ PERL_ARGS_ASSERT_NOT_A_NUMBER;
+
if (DO_UTF8(sv)) {
- dsv = sv_2mortal(newSVpvs(""));
+ dsv = newSVpvs_flags("", SVs_TEMP);
pv = sv_uni_display(dsv, sv, 10, 0);
} else {
char *d = tmpbuf;
*/
I32
-Perl_looks_like_number(pTHX_ SV *sv)
+Perl_looks_like_number(pTHX_ SV *const sv)
{
register const char *sbegin;
STRLEN len;
+ PERL_ARGS_ASSERT_LOOKS_LIKE_NUMBER;
+
if (SvPOK(sv)) {
sbegin = SvPVX_const(sv);
len = SvCUR(sv);
return grok_number(sbegin, len, NULL);
}
+STATIC bool
+S_glob_2number(pTHX_ GV * const gv)
+{
+ const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
+ SV *const buffer = sv_newmortal();
+
+ PERL_ARGS_ASSERT_GLOB_2NUMBER;
+
+ /* FAKE globs can get coerced, so need to turn this off temporarily if it
+ is on. */
+ SvFAKE_off(gv);
+ gv_efullname3(buffer, gv, "*");
+ SvFLAGS(gv) |= wasfake;
+
+ /* We know that all GVs stringify to something that is not-a-number,
+ so no need to test that. */
+ if (ckWARN(WARN_NUMERIC))
+ not_a_number(buffer);
+ /* We just want something true to return, so that S_sv_2iuv_common
+ can tail call us and return true. */
+ return TRUE;
+}
+
STATIC char *
-S_glob_2inpuv(pTHX_ GV *gv, STRLEN *len, bool want_number)
+S_glob_2pv(pTHX_ GV * const gv, STRLEN * const len)
{
const U32 wasfake = SvFLAGS(gv) & SVf_FAKE;
SV *const buffer = sv_newmortal();
+ PERL_ARGS_ASSERT_GLOB_2PV;
+
/* FAKE globs can get coerced, so need to turn this off temporarily if it
is on. */
SvFAKE_off(gv);
gv_efullname3(buffer, gv, "*");
SvFLAGS(gv) |= wasfake;
- if (want_number) {
- /* We know that all GVs stringify to something that is not-a-number,
- so no need to test that. */
- if (ckWARN(WARN_NUMERIC))
- not_a_number(buffer);
- /* We just want something true to return, so that S_sv_2iuv_common
- can tail call us and return true. */
- return (char *) 1;
- } else {
- assert(SvPOK(buffer));
- if (len) {
- *len = SvCUR(buffer);
- }
- return SvPVX(buffer);
+ assert(SvPOK(buffer));
+ if (len) {
+ *len = SvCUR(buffer);
}
+ return SvPVX(buffer);
}
/* Actually, ISO C leaves conversion of UV to IV undefined, but
/* For sv_2nv these three cases are "SvNOK and don't bother casting" */
STATIC int
-S_sv_2iuv_non_preserve(pTHX_ register SV *sv, I32 numtype)
+S_sv_2iuv_non_preserve(pTHX_ register SV *const sv
+# ifdef DEBUGGING
+ , I32 numtype
+# endif
+ )
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_2IUV_NON_PRESERVE;
+
DEBUG_c(PerlIO_printf(Perl_debug_log,"sv_2iuv_non '%s', IV=0x%"UVxf" NV=%"NVgf" inttype=%"UVXf"\n", SvPVX_const(sv), SvIVX(sv), SvNVX(sv), (UV)numtype));
if (SvNVX(sv) < (NV)IV_MIN) {
(void)SvIOKp_on(sv);
#endif /* !NV_PRESERVES_UV*/
STATIC bool
-S_sv_2iuv_common(pTHX_ SV *sv) {
+S_sv_2iuv_common(pTHX_ SV *const sv)
+{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_2IUV_COMMON;
+
if (SvNOKp(sv)) {
/* erm. not sure. *should* never get NOKp (without NOK) from sv_2nv
* without also getting a cached IV/UV from it at the same time
we're outside the range of NV integer precision */
#endif
) {
- SvIOK_on(sv); /* Can this go wrong with rounding? NWC */
+ if (SvNOK(sv))
+ SvIOK_on(sv); /* Can this go wrong with rounding? NWC */
+ else {
+ /* scalar has trailing garbage, eg "42a" */
+ }
DEBUG_c(PerlIO_printf(Perl_debug_log,
"0x%"UVxf" iv(%"NVgf" => %"IVdf") (precise)\n",
PTR2UV(sv),
came from a (by definition imprecise) NV operation, and
we're outside the range of NV integer precision */
#endif
+ && SvNOK(sv)
)
SvIOK_on(sv);
SvIsUV_on(sv);
if ((NV)(SvIVX(sv)) == SvNVX(sv)) {
SvIOK_on(sv);
} else {
- /*EMPTY*/; /* Integer is imprecise. NOK, IOKp */
+ NOOP; /* Integer is imprecise. NOK, IOKp */
}
/* UV will not work better than IV */
} else {
if ((NV)(SvUVX(sv)) == SvNVX(sv)) {
SvIOK_on(sv);
} else {
- /*EMPTY*/; /* Integer is imprecise. NOK, IOKp, is UV */
+ NOOP; /* Integer is imprecise. NOK, IOKp, is UV */
}
}
SvIsUV_on(sv);
1 1 already read UV.
so there's no point in sv_2iuv_non_preserve() attempting
to use atol, strtol, strtoul etc. */
+# ifdef DEBUGGING
sv_2iuv_non_preserve (sv, numtype);
+# else
+ sv_2iuv_non_preserve (sv);
+# endif
}
}
#endif /* NV_PRESERVES_UV */
+ /* It might be more code efficient to go through the entire logic above
+ and conditionally set with SvIOKp_on() rather than SvIOK(), but it
+ gets complex and potentially buggy, so more programmer efficient
+ to do it this way, by turning off the public flags: */
+ if (!numtype)
+ SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK);
}
}
else {
- if (isGV_with_GP(sv)) {
- return (bool)PTR2IV(glob_2inpuv((GV *)sv, NULL, TRUE));
- }
+ if (isGV_with_GP(sv))
+ return glob_2number((GV *)sv);
if (!(SvFLAGS(sv) & SVs_PADTMP)) {
if (!PL_localizing && ckWARN(WARN_UNINITIALIZED))
*/
IV
-Perl_sv_2iv_flags(pTHX_ register SV *sv, I32 flags)
+Perl_sv_2iv_flags(pTHX_ register SV *const sv, const I32 flags)
{
dVAR;
if (!sv)
return 0;
- if (SvGMAGICAL(sv)) {
+ if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
+ /* FBMs use the same flag bit as SVf_IVisUV, so must let them
+ cache IVs just in case. In practice it seems that they never
+ actually anywhere accessible by user Perl code, let alone get used
+ in anything other than a string context. */
if (flags & SV_GMAGIC)
mg_get(sv);
if (SvIOKp(sv))
*/
UV
-Perl_sv_2uv_flags(pTHX_ register SV *sv, I32 flags)
+Perl_sv_2uv_flags(pTHX_ register SV *const sv, const I32 flags)
{
dVAR;
if (!sv)
return 0;
- if (SvGMAGICAL(sv)) {
+ if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
+ /* FBMs use the same flag bit as SVf_IVisUV, so must let them
+ cache IVs just in case. */
if (flags & SV_GMAGIC)
mg_get(sv);
if (SvIOKp(sv))
*/
NV
-Perl_sv_2nv(pTHX_ register SV *sv)
+Perl_sv_2nv(pTHX_ register SV *const sv)
{
dVAR;
if (!sv)
return 0.0;
- if (SvGMAGICAL(sv)) {
+ if (SvGMAGICAL(sv) || (SvTYPE(sv) == SVt_PVGV && SvVALID(sv))) {
+ /* FBMs use the same flag bit as SVf_IVisUV, so must let them
+ cache IVs just in case. */
mg_get(sv);
if (SvNOKp(sv))
return SvNVX(sv);
if (SvIOKp(sv)) {
SvNV_set(sv, SvIsUV(sv) ? (NV)SvUVX(sv) : (NV)SvIVX(sv));
#ifdef NV_PRESERVES_UV
- SvNOK_on(sv);
+ if (SvIOK(sv))
+ SvNOK_on(sv);
+ else
+ SvNOKp_on(sv);
#else
/* Only set the public NV OK flag if this NV preserves the IV */
/* Check it's not 0xFFFFFFFFFFFFFFFF */
- if (SvIsUV(sv) ? ((SvUVX(sv) != UV_MAX)&&(SvUVX(sv) == U_V(SvNVX(sv))))
+ if (SvIOK(sv) &&
+ SvIsUV(sv) ? ((SvUVX(sv) != UV_MAX)&&(SvUVX(sv) == U_V(SvNVX(sv))))
: (SvIVX(sv) == I_V(SvNVX(sv))))
SvNOK_on(sv);
else
SvNV_set(sv, (numtype & IS_NUMBER_NEG) ? -(NV)value : (NV)value);
} else
SvNV_set(sv, Atof(SvPVX_const(sv)));
- SvNOK_on(sv);
+ if (numtype)
+ SvNOK_on(sv);
+ else
+ SvNOKp_on(sv);
#else
SvNV_set(sv, Atof(SvPVX_const(sv)));
/* Only set the public NV OK flag if this NV preserves the value in
}
}
}
+ /* It might be more code efficient to go through the entire logic above
+ and conditionally set with SvNOKp_on() rather than SvNOK(), but it
+ gets complex and potentially buggy, so more programmer efficient
+ to do it this way, by turning off the public flags: */
+ if (!numtype)
+ SvFLAGS(sv) &= ~(SVf_IOK|SVf_NOK);
#endif /* NV_PRESERVES_UV */
}
else {
if (isGV_with_GP(sv)) {
- glob_2inpuv((GV *)sv, NULL, TRUE);
+ glob_2number((GV *)sv);
return 0.0;
}
return SvNVX(sv);
}
+/*
+=for apidoc sv_2num
+
+Return an SV with the numeric value of the source SV, doing any necessary
+reference or overload conversion. You must use the C<SvNUM(sv)> macro to
+access this function.
+
+=cut
+*/
+
+SV *
+Perl_sv_2num(pTHX_ register SV *const sv)
+{
+ PERL_ARGS_ASSERT_SV_2NUM;
+
+ if (!SvROK(sv))
+ return sv;
+ if (SvAMAGIC(sv)) {
+ SV * const tmpsv = AMG_CALLun(sv,numer);
+ if (tmpsv && (!SvROK(tmpsv) || (SvRV(tmpsv) != SvRV(sv))))
+ return sv_2num(tmpsv);
+ }
+ return sv_2mortal(newSVuv(PTR2UV(SvRV(sv))));
+}
+
/* uiv_2buf(): private routine for use by sv_2pv_flags(): print an IV or
* UV as a string towards the end of buf, and return pointers to start and
* end of it.
*/
static char *
-S_uiv_2buf(char *buf, IV iv, UV uv, int is_uv, char **peob)
+S_uiv_2buf(char *const buf, const IV iv, UV uv, const int is_uv, char **const peob)
{
char *ptr = buf + TYPE_CHARS(UV);
char * const ebuf = ptr;
int sign;
+ PERL_ARGS_ASSERT_UIV_2BUF;
+
if (is_uv)
sign = 0;
else if (iv >= 0) {
return ptr;
}
-/* stringify_regexp(): private routine for use by sv_2pv_flags(): converts
- * a regexp to its stringified form.
- */
-
-static char *
-S_stringify_regexp(pTHX_ SV *sv, MAGIC *mg, STRLEN *lp) {
- dVAR;
- const regexp * const re = (regexp *)mg->mg_obj;
-
- if (!mg->mg_ptr) {
- const char *fptr = "msix";
- char reflags[6];
- char ch;
- int left = 0;
- int right = 4;
- bool need_newline = 0;
- U16 reganch = (U16)((re->reganch & PMf_COMPILETIME) >> 12);
-
- while((ch = *fptr++)) {
- if(reganch & 1) {
- reflags[left++] = ch;
- }
- else {
- reflags[right--] = ch;
- }
- reganch >>= 1;
- }
- if(left != 4) {
- reflags[left] = '-';
- left = 5;
- }
-
- mg->mg_len = re->prelen + 4 + left;
- /*
- * If /x was used, we have to worry about a regex ending with a
- * comment later being embedded within another regex. If so, we don't
- * want this regex's "commentization" to leak out to the right part of
- * the enclosing regex, we must cap it with a newline.
- *
- * So, if /x was used, we scan backwards from the end of the regex. If
- * we find a '#' before we find a newline, we need to add a newline
- * ourself. If we find a '\n' first (or if we don't find '#' or '\n'),
- * we don't need to add anything. -jfriedl
- */
- if (PMf_EXTENDED & re->reganch) {
- const char *endptr = re->precomp + re->prelen;
- while (endptr >= re->precomp) {
- const char c = *(endptr--);
- if (c == '\n')
- break; /* don't need another */
- if (c == '#') {
- /* we end while in a comment, so we need a newline */
- mg->mg_len++; /* save space for it */
- need_newline = 1; /* note to add it */
- break;
- }
- }
- }
-
- Newx(mg->mg_ptr, mg->mg_len + 1 + left, char);
- mg->mg_ptr[0] = '(';
- mg->mg_ptr[1] = '?';
- Copy(reflags, mg->mg_ptr+2, left, char);
- *(mg->mg_ptr+left+2) = ':';
- Copy(re->precomp, mg->mg_ptr+3+left, re->prelen, char);
- if (need_newline)
- mg->mg_ptr[mg->mg_len - 2] = '\n';
- mg->mg_ptr[mg->mg_len - 1] = ')';
- mg->mg_ptr[mg->mg_len] = 0;
- }
- PL_reginterp_cnt += re->program[0].next_off;
-
- if (re->reganch & ROPT_UTF8)
- SvUTF8_on(sv);
- else
- SvUTF8_off(sv);
- if (lp)
- *lp = mg->mg_len;
- return mg->mg_ptr;
-}
-
/*
=for apidoc sv_2pv_flags
*/
char *
-Perl_sv_2pv_flags(pTHX_ register SV *sv, STRLEN *lp, I32 flags)
+Perl_sv_2pv_flags(pTHX_ register SV *const sv, STRLEN *const lp, const I32 flags)
{
dVAR;
register char *s;
STRLEN len;
if (SvIOKp(sv)) {
- len = SvIsUV(sv) ? my_sprintf(tbuf,"%"UVuf, (UV)SvUVX(sv))
- : my_sprintf(tbuf,"%"IVdf, (IV)SvIVX(sv));
+ len = SvIsUV(sv)
+ ? my_snprintf(tbuf, sizeof(tbuf), "%"UVuf, (UV)SvUVX(sv))
+ : my_snprintf(tbuf, sizeof(tbuf), "%"IVdf, (IV)SvIVX(sv));
} else {
Gconvert(SvNVX(sv), NV_DIG, 0, tbuf);
len = strlen(tbuf);
s = SvGROW_mutable(sv, len + 1);
SvCUR_set(sv, len);
SvPOKp_on(sv);
- return memcpy(s, tbuf, len + 1);
+ return (char*)memcpy(s, tbuf, len + 1);
}
}
if (SvROK(sv)) {
}
}
{
- SV *tsv;
- MAGIC *mg;
+ STRLEN len;
+ char *retval;
+ char *buffer;
const SV *const referent = (SV*)SvRV(sv);
if (!referent) {
- tsv = sv_2mortal(newSVpvs("NULLREF"));
- } else if (SvTYPE(referent) == SVt_PVMG
- && ((SvFLAGS(referent) &
- (SVs_OBJECT|SVf_OK|SVs_GMG|SVs_SMG|SVs_RMG))
- == (SVs_OBJECT|SVs_SMG))
- && (mg = mg_find(referent, PERL_MAGIC_qr))) {
- return stringify_regexp(sv, mg, lp);
+ len = 7;
+ retval = buffer = savepvn("NULLREF", len);
+ } else if (SvTYPE(referent) == SVt_REGEXP) {
+ const REGEXP * const re = (REGEXP *)referent;
+ I32 seen_evals = 0;
+
+ assert(re);
+
+ /* If the regex is UTF-8 we want the containing scalar to
+ have an UTF-8 flag too */
+ if (RX_UTF8(re))
+ SvUTF8_on(sv);
+ else
+ SvUTF8_off(sv);
+
+ if ((seen_evals = RX_SEEN_EVALS(re)))
+ PL_reginterp_cnt += seen_evals;
+
+ if (lp)
+ *lp = RX_WRAPLEN(re);
+
+ return RX_WRAPPED(re);
} else {
const char *const typestr = sv_reftype(referent, 0);
+ const STRLEN typelen = strlen(typestr);
+ UV addr = PTR2UV(referent);
+ const char *stashname = NULL;
+ STRLEN stashnamelen = 0; /* hush, gcc */
+ const char *buffer_end;
- tsv = sv_newmortal();
if (SvOBJECT(referent)) {
- const char *const name = HvNAME_get(SvSTASH(referent));
- Perl_sv_setpvf(aTHX_ tsv, "%s=%s(0x%"UVxf")",
- name ? name : "__ANON__" , typestr,
- PTR2UV(referent));
+ const HEK *const name = HvNAME_HEK(SvSTASH(referent));
+
+ if (name) {
+ stashname = HEK_KEY(name);
+ stashnamelen = HEK_LEN(name);
+
+ if (HEK_UTF8(name)) {
+ SvUTF8_on(sv);
+ } else {
+ SvUTF8_off(sv);
+ }
+ } else {
+ stashname = "__ANON__";
+ stashnamelen = 8;
+ }
+ len = stashnamelen + 1 /* = */ + typelen + 3 /* (0x */
+ + 2 * sizeof(UV) + 2 /* )\0 */;
+ } else {
+ len = typelen + 3 /* (0x */
+ + 2 * sizeof(UV) + 2 /* )\0 */;
}
- else
- Perl_sv_setpvf(aTHX_ tsv, "%s(0x%"UVxf")", typestr,
- PTR2UV(referent));
+
+ Newx(buffer, len, char);
+ buffer_end = retval = buffer + len;
+
+ /* Working backwards */
+ *--retval = '\0';
+ *--retval = ')';
+ do {
+ *--retval = PL_hexdigit[addr & 15];
+ } while (addr >>= 4);
+ *--retval = 'x';
+ *--retval = '0';
+ *--retval = '(';
+
+ retval -= typelen;
+ memcpy(retval, typestr, typelen);
+
+ if (stashname) {
+ *--retval = '=';
+ retval -= stashnamelen;
+ memcpy(retval, stashname, stashnamelen);
+ }
+ /* retval may not neccesarily have reached the start of the
+ buffer here. */
+ assert (retval >= buffer);
+
+ len = buffer_end - retval - 1; /* -1 for that \0 */
}
if (lp)
- *lp = SvCUR(tsv);
- return SvPVX(tsv);
+ *lp = len;
+ SAVEFREEPV(buffer);
+ return retval;
}
}
if (SvREADONLY(sv) && !SvOK(sv)) {
- if (ckWARN(WARN_UNINITIALIZED))
- report_uninit(sv);
if (lp)
*lp = 0;
+ if (flags & SV_UNDEF_RETURNS_NULL)
+ return NULL;
+ if (ckWARN(WARN_UNINITIALIZED))
+ report_uninit(sv);
return (char *)"";
}
}
if (SvIOK(sv) || ((SvIOKp(sv) && !SvNOKp(sv)))) {
/* I'm assuming that if both IV and NV are equally valid then
converting the IV is going to be more efficient */
- const U32 isIOK = SvIOK(sv);
const U32 isUIOK = SvIsUV(sv);
char buf[TYPE_CHARS(UV)];
char *ebuf, *ptr;
+ STRLEN len;
if (SvTYPE(sv) < SVt_PVIV)
sv_upgrade(sv, SVt_PVIV);
ptr = uiv_2buf(buf, SvIVX(sv), SvUVX(sv), isUIOK, &ebuf);
+ len = ebuf - ptr;
/* inlined from sv_setpvn */
- SvGROW_mutable(sv, (STRLEN)(ebuf - ptr + 1));
- Move(ptr,SvPVX_mutable(sv),ebuf - ptr,char);
- SvCUR_set(sv, ebuf - ptr);
- s = SvEND(sv);
+ s = SvGROW_mutable(sv, len + 1);
+ Move(ptr, s, len, char);
+ s += len;
*s = '\0';
- if (isIOK)
- SvIOK_on(sv);
- else
- SvIOKp_on(sv);
- if (isUIOK)
- SvIsUV_on(sv);
}
else if (SvNOKp(sv)) {
const int olderrno = errno;
/* some Xenix systems wipe out errno here */
#ifdef apollo
if (SvNVX(sv) == 0.0)
- (void)strcpy(s,"0");
+ my_strlcpy(s, "0", SvLEN(sv));
else
#endif /*apollo*/
{
}
errno = olderrno;
#ifdef FIXNEGATIVEZERO
- if (*s == '-' && s[1] == '0' && !s[2])
- strcpy(s,"0");
+ if (*s == '-' && s[1] == '0' && !s[2]) {
+ s[0] = '0';
+ s[1] = 0;
+ }
#endif
while (*s) s++;
#ifdef hcx
#endif
}
else {
- if (isGV_with_GP(sv)) {
- return glob_2inpuv((GV *)sv, lp, FALSE);
- }
+ if (isGV_with_GP(sv))
+ return glob_2pv((GV *)sv, lp);
- if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
- report_uninit(sv);
if (lp)
*lp = 0;
+ if (flags & SV_UNDEF_RETURNS_NULL)
+ return NULL;
+ if (!PL_localizing && !(SvFLAGS(sv) & SVs_PADTMP) && ckWARN(WARN_UNINITIALIZED))
+ report_uninit(sv);
if (SvTYPE(sv) < SVt_PV)
/* Typically the caller expects that sv_any is not NULL now. */
sv_upgrade(sv, SVt_PV);
Copies a stringified representation of the source SV into the
destination SV. Automatically performs any necessary mg_get and
coercion of numeric values into strings. Guaranteed to preserve
-UTF-8 flag even from overloaded objects. Similar in nature to
+UTF8 flag even from overloaded objects. Similar in nature to
sv_2pv[_flags] but operates directly on an SV instead of just the
string. Mostly uses sv_2pv_flags to do its work, except when that
would lose the UTF-8'ness of the PV.
*/
void
-Perl_sv_copypv(pTHX_ SV *dsv, register SV *ssv)
+Perl_sv_copypv(pTHX_ SV *const dsv, register SV *const ssv)
{
STRLEN len;
const char * const s = SvPV_const(ssv,len);
+
+ PERL_ARGS_ASSERT_SV_COPYPV;
+
sv_setpvn(dsv,s,len);
if (SvUTF8(ssv))
SvUTF8_on(dsv);
*/
char *
-Perl_sv_2pvbyte(pTHX_ register SV *sv, STRLEN *lp)
+Perl_sv_2pvbyte(pTHX_ register SV *const sv, STRLEN *const lp)
{
+ PERL_ARGS_ASSERT_SV_2PVBYTE;
+
sv_utf8_downgrade(sv,0);
return lp ? SvPV(sv,*lp) : SvPV_nolen(sv);
}
char *
Perl_sv_2pvutf8(pTHX_ register SV *sv, STRLEN *lp)
{
+ PERL_ARGS_ASSERT_SV_2PVUTF8;
+
sv_utf8_upgrade(sv);
return lp ? SvPV(sv,*lp) : SvPV_nolen(sv);
}
Perl_sv_2bool(pTHX_ register SV *sv)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_2BOOL;
+
SvGETMAGIC(sv);
if (!SvOK(sv))
Perl_sv_utf8_upgrade_flags(pTHX_ register SV *sv, I32 flags)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_UTF8_UPGRADE_FLAGS;
+
if (sv == &PL_sv_undef)
return 0;
if (!SvPOK(sv)) {
Perl_sv_utf8_downgrade(pTHX_ register SV* sv, bool fail_ok)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_UTF8_DOWNGRADE;
+
if (SvPOKp(sv) && SvUTF8(sv)) {
if (SvCUR(sv)) {
U8 *s;
void
Perl_sv_utf8_encode(pTHX_ register SV *sv)
{
- (void) sv_utf8_upgrade(sv);
+ PERL_ARGS_ASSERT_SV_UTF8_ENCODE;
+
if (SvIsCOW(sv)) {
sv_force_normal_flags(sv, 0);
}
if (SvREADONLY(sv)) {
Perl_croak(aTHX_ PL_no_modify);
}
+ (void) sv_utf8_upgrade(sv);
SvUTF8_off(sv);
}
bool
Perl_sv_utf8_decode(pTHX_ register SV *sv)
{
+ PERL_ARGS_ASSERT_SV_UTF8_DECODE;
+
if (SvPOKp(sv)) {
const U8 *c;
const U8 *e;
static void
S_glob_assign_glob(pTHX_ SV *dstr, SV *sstr, const int dtype)
{
+ I32 mro_changes = 0; /* 1 = method, 2 = isa */
+
+ PERL_ARGS_ASSERT_GLOB_ASSIGN_GLOB;
+
if (dtype != SVt_PVGV) {
const char * const name = GvNAME(sstr);
const STRLEN len = GvNAMELEN(sstr);
- /* don't upgrade SVt_PVLV: it can hold a glob */
- if (dtype != SVt_PVLV) {
+ {
if (dtype >= SVt_PV) {
SvPV_free(dstr);
SvPV_set(dstr, 0);
SvLEN_set(dstr, 0);
SvCUR_set(dstr, 0);
}
- sv_upgrade(dstr, SVt_PVGV);
+ SvUPGRADE(dstr, SVt_PVGV);
(void)SvOK_off(dstr);
- SvSCREAM_on(dstr);
+ /* FIXME - why are we doing this, then turning it off and on again
+ below? */
+ isGV_with_GP_on(dstr);
}
GvSTASH(dstr) = GvSTASH(sstr);
if (GvSTASH(dstr))
}
#endif
+ if(GvGP((GV*)sstr)) {
+ /* If source has method cache entry, clear it */
+ if(GvCVGEN(sstr)) {
+ SvREFCNT_dec(GvCV(sstr));
+ GvCV(sstr) = NULL;
+ GvCVGEN(sstr) = 0;
+ }
+ /* If source has a real method, then a method is
+ going to change */
+ else if(GvCV((GV*)sstr)) {
+ mro_changes = 1;
+ }
+ }
+
+ /* If dest already had a real method, that's a change as well */
+ if(!mro_changes && GvGP((GV*)dstr) && GvCVu((GV*)dstr)) {
+ mro_changes = 1;
+ }
+
+ if(strEQ(GvNAME((GV*)dstr),"ISA"))
+ mro_changes = 2;
+
gp_free((GV*)dstr);
- SvSCREAM_off(dstr);
+ isGV_with_GP_off(dstr);
(void)SvOK_off(dstr);
- SvSCREAM_on(dstr);
+ isGV_with_GP_on(dstr);
GvINTRO_off(dstr); /* one-shot flag */
GvGP(dstr) = gp_ref(GvGP(sstr));
if (SvTAINTED(sstr))
GvIMPORTED_on(dstr);
}
GvMULTI_on(dstr);
+ if(mro_changes == 2) mro_isa_changed_in(GvSTASH(dstr));
+ else if(mro_changes) mro_method_changed_in(GvSTASH(dstr));
return;
}
static void
-S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr) {
+S_glob_assign_ref(pTHX_ SV *dstr, SV *sstr)
+{
SV * const sref = SvREFCNT_inc(SvRV(sstr));
SV *dref = NULL;
const int intro = GvINTRO(dstr);
U8 import_flag = 0;
const U32 stype = SvTYPE(sref);
+ PERL_ARGS_ASSERT_GLOB_ASSIGN_REF;
#ifdef GV_UNIQUE_CHECK
if (GvUNIQUE((GV*)dstr)) {
common:
if (intro) {
if (stype == SVt_PVCV) {
- if (GvCVGEN(dstr) && GvCV(dstr) != (CV*)sref) {
+ /*if (GvCVGEN(dstr) && (GvCV(dstr) != (CV*)sref || GvCVGEN(dstr))) {*/
+ if (GvCVGEN(dstr)) {
SvREFCNT_dec(GvCV(dstr));
GvCV(dstr) = NULL;
GvCVGEN(dstr) = 0; /* Switch off cacheness. */
- PL_sub_generation++;
}
}
SAVEGENERICSV(*location);
}
else
dref = *location;
- if (stype == SVt_PVCV && *location != sref) {
+ if (stype == SVt_PVCV && (*location != sref || GvCVGEN(dstr))) {
CV* const cv = (CV*)*location;
if (cv) {
if (!GvCVGEN((GV*)dstr) &&
it was a const and its value changed. */
if (CvCONST(cv) && CvCONST((CV*)sref)
&& cv_const_sv(cv) == cv_const_sv((CV*)sref)) {
- /*EMPTY*/
+ NOOP;
/* They are 2 constant subroutines generated from
the same constant. This probably means that
they are really the "same" proxy subroutine
|| sv_cmp(cv_const_sv(cv),
cv_const_sv((CV*)sref))))) {
Perl_warner(aTHX_ packWARN(WARN_REDEFINE),
- CvCONST(cv)
- ? "Constant subroutine %s::%s redefined"
- : "Subroutine %s::%s redefined",
+ (const char *)
+ (CvCONST(cv)
+ ? "Constant subroutine %s::%s redefined"
+ : "Subroutine %s::%s redefined"),
HvNAME_get(GvSTASH((GV*)dstr)),
GvENAME((GV*)dstr));
}
}
if (!intro)
- cv_ckproto(cv, (GV*)dstr,
- SvPOK(sref) ? SvPVX_const(sref) : NULL);
+ cv_ckproto_len(cv, (GV*)dstr,
+ SvPOK(sref) ? SvPVX_const(sref) : NULL,
+ SvPOK(sref) ? SvCUR(sref) : 0);
}
GvCVGEN(dstr) = 0; /* Switch off cacheness. */
GvASSUMECV_on(dstr);
- PL_sub_generation++;
+ if(GvSTASH(dstr)) mro_method_changed_in(GvSTASH(dstr)); /* sub foo { 1 } sub bar { 2 } *bar = \&foo */
}
*location = sref;
if (import_flag && !(GvFLAGS(dstr) & import_flag)
dVAR;
register U32 sflags;
register int dtype;
- register int stype;
+ register svtype stype;
+
+ PERL_ARGS_ASSERT_SV_SETSV_FLAGS;
if (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 (!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);
- SvAMAGIC_off(dstr);
+ (void)SvAMAGIC_off(dstr);
if ( SvVOK(dstr) )
{
/* need to nuke the magic */
sv_upgrade(dstr, SVt_IV);
break;
case SVt_NV:
- case SVt_RV:
case SVt_PV:
sv_upgrade(dstr, SVt_PVIV);
break;
+ case SVt_PVGV:
+ goto end_of_first_switch;
}
(void)SvIOK_only(dstr);
SvIV_set(dstr, SvIVX(sstr));
assert(!SvTAINTED(sstr));
return;
}
- goto undef_sstr;
+ if (!SvROK(sstr))
+ goto undef_sstr;
+ if (dtype < SVt_PV && dtype != SVt_IV)
+ sv_upgrade(dstr, SVt_IV);
+ break;
case SVt_NV:
if (SvNOK(sstr)) {
case SVt_IV:
sv_upgrade(dstr, SVt_NV);
break;
- case SVt_RV:
case SVt_PV:
case SVt_PVIV:
sv_upgrade(dstr, SVt_PVNV);
break;
+ case SVt_PVGV:
+ goto end_of_first_switch;
}
SvNV_set(dstr, SvNVX(sstr));
(void)SvNOK_only(dstr);
}
goto undef_sstr;
- case SVt_RV:
- if (dtype < SVt_RV)
- sv_upgrade(dstr, SVt_RV);
- break;
case SVt_PVFM:
#ifdef PERL_OLD_COPY_ON_WRITE
if ((SvFLAGS(sstr) & CAN_COW_MASK) == CAN_COW_FLAGS) {
}
/* Fall through */
#endif
+ case SVt_REGEXP:
case SVt_PV:
if (dtype < SVt_PV)
sv_upgrade(dstr, SVt_PV);
}
break;
+ /* case SVt_BIND: */
+ case SVt_PVLV:
case SVt_PVGV:
- if (dtype <= SVt_PVGV) {
+ if (isGV_with_GP(sstr) && dtype <= SVt_PVGV) {
glob_assign_glob(dstr, sstr, dtype);
return;
}
+ /* SvVALID means that this PVGV is playing at being an FBM. */
/*FALLTHROUGH*/
case SVt_PVMG:
- case SVt_PVLV:
- case SVt_PVBM:
if (SvGMAGICAL(sstr) && (flags & SV_GMAGIC)) {
mg_get(sstr);
- if ((int)SvTYPE(sstr) != stype) {
+ if (SvTYPE(sstr) != stype) {
stype = SvTYPE(sstr);
- if (stype == SVt_PVGV && dtype <= SVt_PVGV) {
+ if (isGV_with_GP(sstr) && stype == SVt_PVGV && dtype <= SVt_PVGV) {
glob_assign_glob(dstr, sstr, dtype);
return;
}
if (stype == SVt_PVLV)
SvUPGRADE(dstr, SVt_PVNV);
else
- SvUPGRADE(dstr, (U32)stype);
+ SvUPGRADE(dstr, (svtype)stype);
}
+ end_of_first_switch:
/* dstr may have been upgraded. */
dtype = SvTYPE(dstr);
sflags = SvFLAGS(sstr);
- if (sflags & SVf_ROK) {
- if (dtype == SVt_PVGV &&
- SvROK(sstr) && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
+ if (dtype == SVt_PVCV || dtype == SVt_PVFM) {
+ /* Assigning to a subroutine sets the prototype. */
+ if (SvOK(sstr)) {
+ STRLEN len;
+ const char *const ptr = SvPV_const(sstr, len);
+
+ SvGROW(dstr, len + 1);
+ Copy(ptr, SvPVX(dstr), len + 1, char);
+ SvCUR_set(dstr, len);
+ SvPOK_only(dstr);
+ SvFLAGS(dstr) |= sflags & SVf_UTF8;
+ } else {
+ SvOK_off(dstr);
+ }
+ } else if (dtype == SVt_PVAV || dtype == SVt_PVHV) {
+ const char * const type = sv_reftype(dstr,0);
+ if (PL_op)
+ Perl_croak(aTHX_ "Cannot copy to %s in %s", type, OP_NAME(PL_op));
+ else
+ Perl_croak(aTHX_ "Cannot copy to %s", type);
+ } else if (sflags & SVf_ROK) {
+ if (isGV_with_GP(dstr) && dtype == SVt_PVGV
+ && SvTYPE(SvRV(sstr)) == SVt_PVGV) {
sstr = SvRV(sstr);
if (sstr == dstr) {
if (GvIMPORTED(dstr) != GVf_IMPORTED
}
if (dtype >= SVt_PV) {
- if (dtype == SVt_PVGV) {
+ if (dtype == SVt_PVGV && isGV_with_GP(dstr)) {
glob_assign_ref(dstr, sstr);
return;
}
}
(void)SvOK_off(dstr);
SvRV_set(dstr, SvREFCNT_inc(SvRV(sstr)));
- SvFLAGS(dstr) |= sflags & (SVf_ROK|SVf_AMAGIC);
+ SvFLAGS(dstr) |= sflags & SVf_ROK;
assert(!(sflags & SVp_NOK));
assert(!(sflags & SVp_IOK));
assert(!(sflags & SVf_NOK));
assert(!(sflags & SVf_IOK));
}
- else if (dtype == SVt_PVGV) {
+ else if (dtype == SVt_PVGV && isGV_with_GP(dstr)) {
if (!(sflags & SVf_OK)) {
if (ckWARN(WARN_MISC))
Perl_warner(aTHX_ packWARN(WARN_MISC),
* possible small lose on short strings, but a big win on long ones.
* It might even be a win on short strings if SvPVX_const(dstr)
* has to be allocated and SvPVX_const(sstr) has to be freed.
+ * Likewise if we can set up COW rather than doing an actual copy, we
+ * drop to the else clause, as the swipe code and the COW setup code
+ * have much in common.
*/
/* Whichever path we take through the next code, we want this true,
(void)SvPOK_only(dstr);
if (
- /* We're not already COW */
- ((sflags & (SVf_FAKE | SVf_READONLY)) != (SVf_FAKE | SVf_READONLY)
+ /* If we're already COW then this clause is not true, and if COW
+ is allowed then we drop down to the else and make dest COW
+ with us. If caller hasn't said that we're allowed to COW
+ shared hash keys then we don't do the COW setup, even if the
+ source scalar is a shared hash key scalar. */
+ (((flags & SV_COW_SHARED_HASH_KEYS)
+ ? (sflags & (SVf_FAKE|SVf_READONLY)) != (SVf_FAKE|SVf_READONLY)
+ : 1 /* If making a COW copy is forbidden then the behaviour we
+ desire is as if the source SV isn't actually already
+ COW, even if it is. So we act as if the source flags
+ are not COW, rather than actually testing them. */
+ )
#ifndef PERL_OLD_COPY_ON_WRITE
- /* or we are, but dstr isn't a suitable target. */
+ /* The change that added SV_COW_SHARED_HASH_KEYS makes the logic
+ when PERL_OLD_COPY_ON_WRITE is defined a little wrong.
+ Conceptually PERL_OLD_COPY_ON_WRITE being defined should
+ override SV_COW_SHARED_HASH_KEYS, because it means "always COW"
+ but in turn, it's somewhat dead code, never expected to go
+ live, but more kept as a placeholder on how to do it better
+ in a newer implementation. */
+ /* If we are COW and dstr is a suitable target then we drop down
+ into the else and make dest a COW of us. */
|| (SvFLAGS(dstr) & CAN_COW_MASK) != CAN_COW_FLAGS
#endif
)
/* and won't be needed again, potentially */
!(PL_op && PL_op->op_type == OP_AASSIGN))
#ifdef PERL_OLD_COPY_ON_WRITE
- && !((sflags & CAN_COW_MASK) == CAN_COW_FLAGS
- && (SvFLAGS(dstr) & CAN_COW_MASK) == CAN_COW_FLAGS
- && SvTYPE(sstr) >= SVt_PVIV)
+ && ((flags & SV_COW_SHARED_HASH_KEYS)
+ ? (!((sflags & CAN_COW_MASK) == CAN_COW_FLAGS
+ && (SvFLAGS(dstr) & CAN_COW_MASK) == CAN_COW_FLAGS
+ && SvTYPE(sstr) >= SVt_PVIV))
+ : 1)
#endif
) {
/* Failed the swipe test, and it's not a shared hash key either.
SvNV_set(dstr, SvNVX(sstr));
}
if (sflags & SVp_IOK) {
- SvRELEASE_IVX(dstr);
SvIV_set(dstr, SvIVX(sstr));
/* Must do this otherwise some other overloaded use of 0x80000000
gets confused. I guess SVpbm_VALID */
if (sflags & SVf_IVisUV)
SvIsUV_on(dstr);
}
- SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8
- |SVf_AMAGIC);
+ SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_NOK|SVp_NOK|SVf_UTF8);
{
- const MAGIC * const smg = SvVOK(sstr);
+ const MAGIC * const smg = SvVSTRING_mg(sstr);
if (smg) {
sv_magic(dstr, NULL, PERL_MAGIC_vstring,
smg->mg_ptr, smg->mg_len);
}
else if (sflags & (SVp_IOK|SVp_NOK)) {
(void)SvOK_off(dstr);
- SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK
- |SVf_AMAGIC);
+ SvFLAGS(dstr) |= sflags & (SVf_IOK|SVp_IOK|SVf_IVisUV|SVf_NOK|SVp_NOK);
if (sflags & SVp_IOK) {
/* XXXX Do we want to set IsUV for IV(ROK)? Be extra safe... */
SvIV_set(dstr, SvIVX(sstr));
SvFAKE_off(sstr);
gv_efullname3(dstr, (GV *)sstr, "*");
SvFLAGS(sstr) |= wasfake;
- SvFLAGS(dstr) |= sflags & SVf_AMAGIC;
}
else
(void)SvOK_off(dstr);
void
Perl_sv_setsv_mg(pTHX_ SV *dstr, register SV *sstr)
{
+ PERL_ARGS_ASSERT_SV_SETSV_MG;
+
sv_setsv(dstr,sstr);
SvSETMAGIC(dstr);
}
STRLEN len = SvLEN(sstr);
register char *new_pv;
+ PERL_ARGS_ASSERT_SV_SETSV_COW;
+
if (DEBUG_C_TEST) {
PerlIO_printf(Perl_debug_log, "Fast copy on write: %p -> %p\n",
- sstr, dstr);
+ (void*)sstr, (void*)dstr);
sv_dump(sstr);
if (dstr)
sv_dump(dstr);
dVAR;
register char *dptr;
+ PERL_ARGS_ASSERT_SV_SETPVN;
+
SV_CHECK_THINKFIRST_COW_DROP(sv);
if (!ptr) {
(void)SvOK_off(sv);
void
Perl_sv_setpvn_mg(pTHX_ register SV *sv, register const char *ptr, register STRLEN len)
{
+ PERL_ARGS_ASSERT_SV_SETPVN_MG;
+
sv_setpvn(sv,ptr,len);
SvSETMAGIC(sv);
}
dVAR;
register STRLEN len;
+ PERL_ARGS_ASSERT_SV_SETPV;
+
SV_CHECK_THINKFIRST_COW_DROP(sv);
if (!ptr) {
(void)SvOK_off(sv);
void
Perl_sv_setpv_mg(pTHX_ register SV *sv, register const char *ptr)
{
+ PERL_ARGS_ASSERT_SV_SETPV_MG;
+
sv_setpv(sv,ptr);
SvSETMAGIC(sv);
}
Tells an SV to use C<ptr> to find its string value. Normally the
string is stored inside the SV but sv_usepvn allows the SV to use an
outside string. The C<ptr> should point to memory that was allocated
-by C<malloc>. The string length, C<len>, must be supplied. This
-function will realloc (i.e. move) the memory pointed to by C<ptr>,
+by C<malloc>. The string length, C<len>, must be supplied. By default
+this function will realloc (i.e. move) the memory pointed to by C<ptr>,
so that pointer should not be freed or used by the programmer after
giving it to sv_usepvn, and neither should any pointers from "behind"
-that pointer (e.g. ptr + 1) be used. If C<flags> & SV_SMAGIC is true, will
-call SvSETMAGIC.
+that pointer (e.g. ptr + 1) be used.
+
+If C<flags> & SV_SMAGIC is true, will call SvSETMAGIC. If C<flags> &
+SV_HAS_TRAILING_NUL is true, then C<ptr[len]> must be NUL, and the realloc
+will be skipped. (i.e. the buffer is actually at least 1 byte longer than
+C<len>, and already meets the requirements for storing in C<SvPVX>)
=cut
*/
{
dVAR;
STRLEN allocate;
+
+ PERL_ARGS_ASSERT_SV_USEPVN_FLAGS;
+
SV_CHECK_THINKFIRST_COW_DROP(sv);
SvUPGRADE(sv, SVt_PV);
if (!ptr) {
if (SvPVX_const(sv))
SvPV_free(sv);
- allocate = PERL_STRLEN_ROUNDUP(len + 1);
#ifdef DEBUGGING
- {
+ if (flags & SV_HAS_TRAILING_NUL)
+ assert(ptr[len] == '\0');
+#endif
+
+ allocate = (flags & SV_HAS_TRAILING_NUL)
+ ? len + 1: PERL_STRLEN_ROUNDUP(len + 1);
+ if (flags & SV_HAS_TRAILING_NUL) {
+ /* It's long enough - do nothing.
+ Specfically Perl_newCONSTSUB is relying on this. */
+ } else {
+#ifdef DEBUGGING
/* Force a move to shake out bugs in callers. */
- char *new_ptr = safemalloc(allocate);
+ char *new_ptr = (char*)safemalloc(allocate);
Copy(ptr, new_ptr, len, char);
PoisonFree(ptr,len,char);
Safefree(ptr);
ptr = new_ptr;
- }
#else
- ptr = saferealloc (ptr, allocate);
+ ptr = (char*) saferealloc (ptr, allocate);
#endif
+ }
SvPV_set(sv, ptr);
SvCUR_set(sv, len);
SvLEN_set(sv, allocate);
- *SvEND(sv) = '\0';
+ if (!(flags & SV_HAS_TRAILING_NUL)) {
+ ptr[len] = '\0';
+ }
(void)SvPOK_only_UTF8(sv); /* validate pointer */
SvTAINT(sv);
if (flags & SV_SMAGIC)
(which it can do by means other than releasing copy-on-write Svs)
or by changing the other copy-on-write SVs in the loop. */
STATIC void
-S_sv_release_COW(pTHX_ register SV *sv, const char *pvx, STRLEN len, SV *after)
+S_sv_release_COW(pTHX_ register SV *sv, const char *pvx, SV *after)
{
- if (len) { /* this SV was SvIsCOW_normal(sv) */
+ PERL_ARGS_ASSERT_SV_RELEASE_COW;
+
+ { /* this SV was SvIsCOW_normal(sv) */
/* we need to find the SV pointing to us. */
SV *current = SV_COW_NEXT_SV(after);
/* Make the SV before us point to the SV after us. */
SV_COW_NEXT_SV_SET(current, after);
}
- } else {
- unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
}
}
-
-int
-Perl_sv_release_IVX(pTHX_ register SV *sv)
-{
- if (SvIsCOW(sv))
- sv_force_normal_flags(sv, 0);
- SvOOK_off(sv);
- return 0;
-}
#endif
/*
=for apidoc sv_force_normal_flags
Perl_sv_force_normal_flags(pTHX_ register SV *sv, U32 flags)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_FORCE_NORMAL_FLAGS;
+
#ifdef PERL_OLD_COPY_ON_WRITE
if (SvREADONLY(sv)) {
/* At this point I believe I should acquire a global SV mutex. */
const char * const pvx = SvPVX_const(sv);
const STRLEN len = SvLEN(sv);
const STRLEN cur = SvCUR(sv);
- SV * const next = SV_COW_NEXT_SV(sv); /* next COW sv in the loop. */
+ /* next COW sv in the loop. If len is 0 then this is a shared-hash
+ key scalar, so we mustn't attempt to call SV_COW_NEXT_SV(), as
+ we'll fail an assertion. */
+ SV * const next = len ? SV_COW_NEXT_SV(sv) : 0;
+
if (DEBUG_C_TEST) {
PerlIO_printf(Perl_debug_log,
"Copy on write: Force normal %ld\n",
SvCUR_set(sv, cur);
*SvEND(sv) = '\0';
}
- sv_release_COW(sv, pvx, len, next);
+ if (len) {
+ sv_release_COW(sv, pvx, next);
+ } else {
+ unshare_hek(SvSHARED_HEK_FROM_PV(pvx));
+ }
if (DEBUG_C_TEST) {
sv_dump(sv);
}
void
Perl_sv_chop(pTHX_ register SV *sv, register const char *ptr)
{
- register STRLEN delta;
+ STRLEN delta;
+ STRLEN old_delta;
+ U8 *p;
+#ifdef DEBUGGING
+ const U8 *real_start;
+#endif
+
+ PERL_ARGS_ASSERT_SV_CHOP;
+
if (!ptr || !SvPOKp(sv))
return;
delta = ptr - SvPVX_const(sv);
+ if (!delta) {
+ /* Nothing to do. */
+ return;
+ }
+ assert(ptr > SvPVX_const(sv));
SV_CHECK_THINKFIRST(sv);
- if (SvTYPE(sv) < SVt_PVIV)
- sv_upgrade(sv,SVt_PVIV);
if (!SvOOK(sv)) {
if (!SvLEN(sv)) { /* make copy of shared string */
Move(pvx,SvPVX(sv),len,char);
*SvEND(sv) = '\0';
}
- SvIV_set(sv, 0);
- /* Same SvOOK_on but SvOOK_on does a SvIOK_off
- and we do that anyway inside the SvNIOK_off
- */
SvFLAGS(sv) |= SVf_OOK;
+ old_delta = 0;
+ } else {
+ SvOOK_offset(sv, old_delta);
}
- SvNIOK_off(sv);
SvLEN_set(sv, SvLEN(sv) - delta);
SvCUR_set(sv, SvCUR(sv) - delta);
SvPV_set(sv, SvPVX(sv) + delta);
- SvIV_set(sv, SvIVX(sv) + delta);
+
+ p = (U8 *)SvPVX_const(sv);
+
+ delta += old_delta;
+
+#ifdef DEBUGGING
+ real_start = p - delta;
+#endif
+
+ assert(delta);
+ if (delta < 0x100) {
+ *--p = (U8) delta;
+ } else {
+ *--p = 0;
+ p -= sizeof(STRLEN);
+ Copy((U8*)&delta, p, sizeof(STRLEN), U8);
+ }
+
+#ifdef DEBUGGING
+ /* Fill the preceding buffer with sentinals to verify that no-one is
+ using it. */
+ while (p > real_start) {
+ --p;
+ *p = (U8)PTR2UV(p);
+ }
+#endif
}
/*
STRLEN dlen;
const char * const dstr = SvPV_force_flags(dsv, dlen, flags);
+ PERL_ARGS_ASSERT_SV_CATPVN_FLAGS;
+
SvGROW(dsv, dlen + slen + 1);
if (sstr == dstr)
sstr = SvPVX_const(dsv);
Perl_sv_catsv_flags(pTHX_ SV *dsv, register SV *ssv, I32 flags)
{
dVAR;
- if (ssv) {
+
+ PERL_ARGS_ASSERT_SV_CATSV_FLAGS;
+
+ if (ssv) {
STRLEN slen;
const char *spv = SvPV_const(ssv, slen);
if (spv) {
if (dutf8 != sutf8) {
if (dutf8) {
/* Not modifying source SV, so taking a temporary copy. */
- SV* const csv = sv_2mortal(newSVpvn(spv, slen));
+ SV* const csv = newSVpvn_flags(spv, slen, SVs_TEMP);
sv_utf8_upgrade(csv);
spv = SvPV_const(csv, slen);
STRLEN tlen;
char *junk;
+ PERL_ARGS_ASSERT_SV_CATPV;
+
if (!ptr)
return;
junk = SvPV_force(sv, tlen);
void
Perl_sv_catpv_mg(pTHX_ register SV *sv, register const char *ptr)
{
+ PERL_ARGS_ASSERT_SV_CATPV_MG;
+
sv_catpv(sv,ptr);
SvSETMAGIC(sv);
}
=cut
*/
MAGIC *
-Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, MGVTBL *vtable,
+Perl_sv_magicext(pTHX_ SV* sv, SV* obj, int how, const MGVTBL *vtable,
const char* name, I32 namlen)
{
dVAR;
MAGIC* mg;
- if (SvTYPE(sv) < SVt_PVMG) {
- SvUPGRADE(sv, SVt_PVMG);
- }
+ PERL_ARGS_ASSERT_SV_MAGICEXT;
+
+ SvUPGRADE(sv, SVt_PVMG);
Newxz(mg, 1, MAGIC);
mg->mg_moremagic = SvMAGIC(sv);
SvMAGIC_set(sv, mg);
*/
if (!obj || obj == sv ||
how == PERL_MAGIC_arylen ||
- how == PERL_MAGIC_qr ||
how == PERL_MAGIC_symtab ||
(SvTYPE(obj) == SVt_PVGV &&
(GvSV(obj) == sv || GvHV(obj) == (HV*)sv || GvAV(obj) == (AV*)sv ||
else
mg->mg_ptr = (char *) name;
}
- mg->mg_virtual = vtable;
+ mg->mg_virtual = (MGVTBL *) vtable;
mg_magical(sv);
if (SvGMAGICAL(sv))
Perl_sv_magic(pTHX_ register SV *sv, SV *obj, int how, const char *name, I32 namlen)
{
dVAR;
- MGVTBL *vtable;
+ const MGVTBL *vtable;
MAGIC* mg;
+ PERL_ARGS_ASSERT_SV_MAGIC;
+
#ifdef PERL_OLD_COPY_ON_WRITE
if (SvIsCOW(sv))
sv_force_normal_flags(sv, 0);
{
MAGIC* mg;
MAGIC** mgp;
+
+ PERL_ARGS_ASSERT_SV_UNMAGIC;
+
if (SvTYPE(sv) < SVt_PVMG || !SvMAGIC(sv))
return 0;
mgp = &(((XPVMG*) SvANY(sv))->xmg_u.xmg_magic);
Weaken a reference: set the C<SvWEAKREF> flag on this RV; give the
referred-to SV C<PERL_MAGIC_backref> magic if it hasn't already; and
push a back-reference to this RV onto the array of backreferences
-associated with that magic.
+associated with that magic. If the RV is magical, set magic will be
+called after the RV is cleared.
=cut
*/
Perl_sv_rvweaken(pTHX_ SV *sv)
{
SV *tsv;
+
+ PERL_ARGS_ASSERT_SV_RVWEAKEN;
+
if (!SvOK(sv)) /* let undefs pass */
return sv;
if (!SvROK(sv))
dVAR;
AV *av;
+ PERL_ARGS_ASSERT_SV_ADD_BACKREF;
+
if (SvTYPE(tsv) == SVt_PVHV) {
AV **const avp = Perl_hv_backreferences_p(aTHX_ (HV*)tsv);
SV **svp;
I32 i;
+ PERL_ARGS_ASSERT_SV_DEL_BACKREF;
+
if (SvTYPE(tsv) == SVt_PVHV && SvOOK(tsv)) {
av = *Perl_hv_backreferences_p(aTHX_ (HV*)tsv);
/* We mustn't attempt to "fix up" the hash here by moving the
{
SV **svp = AvARRAY(av);
+ PERL_ARGS_ASSERT_SV_KILL_BACKREFS;
PERL_UNUSED_ARG(sv);
/* Not sure why the av can get freed ahead of its sv, but somehow it does
SvRV_set(referrer, 0);
SvOK_off(referrer);
SvWEAKREF_off(referrer);
+ SvSETMAGIC(referrer);
} else if (SvTYPE(referrer) == SVt_PVGV ||
SvTYPE(referrer) == SVt_PVLV) {
/* You lookin' at me? */
register I32 i;
STRLEN curlen;
+ PERL_ARGS_ASSERT_SV_INSERT;
if (!bigstr)
Perl_croak(aTHX_ "Can't modify non-existent substring");
else if ((i = mid - big)) { /* faster from front */
midend -= littlelen;
mid = midend;
+ Move(big, midend - i, i, char);
sv_chop(bigstr,midend-i);
- big += i;
- while (i--)
- *--midend = *--big;
if (littlelen)
Move(little, mid, littlelen,char);
}
{
dVAR;
const U32 refcnt = SvREFCNT(sv);
+
+ PERL_ARGS_ASSERT_SV_REPLACE;
+
SV_CHECK_THINKFIRST_COW_DROP(sv);
if (SvREFCNT(nsv) != 1) {
Perl_croak(aTHX_ "panic: reference miscount on nsv in sv_replace() (%"
#else
StructCopy(nsv,sv,SV);
#endif
- /* Currently could join these into one piece of pointer arithmetic, but
- it would be unclear. */
- if(SvTYPE(sv) == SVt_IV)
+ if(SvTYPE(sv) == SVt_IV) {
SvANY(sv)
= (XPVIV*)((char*)&(sv->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
- else if (SvTYPE(sv) == SVt_RV) {
- SvANY(sv) = &sv->sv_u.svu_rv;
}
const U32 type = SvTYPE(sv);
const struct body_details *const sv_type_details
= bodies_by_type + type;
+ HV *stash;
- assert(sv);
+ PERL_ARGS_ASSERT_SV_CLEAR;
assert(SvREFCNT(sv) == 0);
+ assert(SvTYPE(sv) != SVTYPEMASK);
if (type <= SVt_IV) {
/* See the comment in sv.h about the collusion between this early
return and the overloading of the NULL and IV slots in the size
table. */
+ if (SvROK(sv)) {
+ SV * const target = SvRV(sv);
+ if (SvWEAKREF(sv))
+ sv_del_backref(target, sv);
+ else
+ SvREFCNT_dec(target);
+ }
+ SvFLAGS(sv) &= SVf_BREAK;
+ SvFLAGS(sv) |= SVTYPEMASK;
return;
}
if (SvOBJECT(sv)) {
- if (PL_defstash) { /* Still have a symbol table? */
+ if (PL_defstash && /* Still have a symbol table? */
+ SvDESTROYABLE(sv))
+ {
dSP;
HV* stash;
do {
}
}
if (type >= SVt_PVMG) {
- HV *ourstash;
- if ((type == SVt_PVMG || type == SVt_PVGV) &&
- (ourstash = OURSTASH(sv))) {
- SvREFCNT_dec(ourstash);
+ if (type == SVt_PVMG && SvPAD_OUR(sv)) {
+ SvREFCNT_dec(SvOURSTASH(sv));
} else if (SvMAGIC(sv))
mg_free(sv);
if (type == SVt_PVMG && SvPAD_TYPED(sv))
SvREFCNT_dec(SvSTASH(sv));
}
switch (type) {
+ /* case SVt_BIND: */
case SVt_PVIO:
if (IoIFP(sv) &&
IoIFP(sv) != PerlIO_stdin() &&
Safefree(IoFMT_NAME(sv));
Safefree(IoBOTTOM_NAME(sv));
goto freescalar;
- case SVt_PVBM:
+ case SVt_REGEXP:
+ /* FIXME for plugins */
+ pregfree2((REGEXP*) sv);
goto freescalar;
case SVt_PVCV:
case SVt_PVFM:
hv_undef((HV*)sv);
break;
case SVt_PVAV:
+ if (PL_comppad == (AV*)sv) {
+ PL_comppad = NULL;
+ PL_curpad = NULL;
+ }
av_undef((AV*)sv);
break;
case SVt_PVLV:
}
else if (LvTYPE(sv) != 't') /* unless tie: unrefcnted fake SV** */
SvREFCNT_dec(LvTARG(sv));
- goto freescalar;
case SVt_PVGV:
- gp_free((GV*)sv);
- if (GvNAME_HEK(sv)) {
- unshare_hek(GvNAME_HEK(sv));
- }
- /* If we're in a stash, we don't own a reference to it. However it does
- have a back reference to us, which needs to be cleared. */
- if (GvSTASH(sv))
- sv_del_backref((SV*)GvSTASH(sv), sv);
+ if (isGV_with_GP(sv)) {
+ if(GvCVu((GV*)sv) && (stash = GvSTASH((GV*)sv)) && HvNAME_get(stash))
+ mro_method_changed_in(stash);
+ gp_free((GV*)sv);
+ if (GvNAME_HEK(sv))
+ unshare_hek(GvNAME_HEK(sv));
+ /* If we're in a stash, we don't own a reference to it. However it does
+ have a back reference to us, which needs to be cleared. */
+ if (!SvVALID(sv) && (stash = GvSTASH(sv)))
+ sv_del_backref((SV*)stash, sv);
+ }
+ /* FIXME. There are probably more unreferenced pointers to SVs in the
+ interpreter struct that we should check and tidy in a similar
+ fashion to this: */
+ if ((GV*)sv == PL_last_in_gv)
+ PL_last_in_gv = NULL;
case SVt_PVMG:
case SVt_PVNV:
case SVt_PVIV:
+ case SVt_PV:
freescalar:
/* Don't bother with SvOOK_off(sv); as we're only going to free it. */
if (SvOOK(sv)) {
- SvPV_set(sv, SvPVX_mutable(sv) - SvIVX(sv));
+ STRLEN offset;
+ SvOOK_offset(sv, offset);
+ SvPV_set(sv, SvPVX_mutable(sv) - offset);
/* Don't even bother with turning off the OOK flag. */
}
- case SVt_PV:
- case SVt_RV:
if (SvROK(sv)) {
SV * const target = SvRV(sv);
if (SvWEAKREF(sv))
PerlIO_printf(Perl_debug_log, "Copy on write: clear\n");
sv_dump(sv);
}
- sv_release_COW(sv, SvPVX_const(sv), SvLEN(sv),
- SV_COW_NEXT_SV(sv));
+ if (SvLEN(sv)) {
+ sv_release_COW(sv, SvPVX_const(sv), SV_COW_NEXT_SV(sv));
+ } else {
+ unshare_hek(SvSHARED_HEK_FROM_PV(SvPVX_const(sv)));
+ }
+
/* And drop it here. */
SvFAKE_off(sv);
} else if (SvLEN(sv)) {
return;
}
if (ckWARN_d(WARN_INTERNAL)) {
+#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
+ Perl_dump_sv_child(aTHX_ sv);
+#else
+ #ifdef DEBUG_LEAKING_SCALARS
+ sv_dump(sv);
+ #endif
+#ifdef DEBUG_LEAKING_SCALARS_ABORT
+ if (PL_warnhook == PERL_WARNHOOK_FATAL
+ || ckDEAD(packWARN(WARN_INTERNAL))) {
+ /* Don't let Perl_warner cause us to escape our fate: */
+ abort();
+ }
+#endif
+ /* This may not return: */
Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
"Attempt to free unreferenced scalar: SV 0x%"UVxf
pTHX__FORMAT, PTR2UV(sv) pTHX__VALUE);
-#ifdef DEBUG_LEAKING_SCALARS_FORK_DUMP
- Perl_dump_sv_child(aTHX_ sv);
#endif
}
+#ifdef DEBUG_LEAKING_SCALARS_ABORT
+ abort();
+#endif
return;
}
if (--(SvREFCNT(sv)) > 0)
Perl_sv_free2(pTHX_ SV *sv)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_FREE2;
+
#ifdef DEBUGGING
if (SvTEMP(sv)) {
if (ckWARN_d(WARN_DEBUGGING))
if (PL_utf8cache) {
STRLEN ulen;
- MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : 0;
+ MAGIC *mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_utf8) : NULL;
if (mg && mg->mg_len != -1) {
ulen = mg->mg_len;
*/
SAVEI8(PL_utf8cache);
PL_utf8cache = 0;
- Perl_croak(aTHX_ "panic: sv_len_utf8 cache %"UVf
- " real %"UVf" for %"SVf,
- (UV) ulen, (UV) real, sv);
+ Perl_croak(aTHX_ "panic: sv_len_utf8 cache %"UVuf
+ " real %"UVuf" for %"SVf,
+ (UV) ulen, (UV) real, SVfARG(sv));
}
}
}
/* Walk forwards to find the byte corresponding to the passed in UTF-8
offset. */
static STRLEN
-S_sv_pos_u2b_forwards(pTHX_ const U8 *const start, const U8 *const send,
+S_sv_pos_u2b_forwards(const U8 *const start, const U8 *const send,
STRLEN uoffset)
{
const U8 *s = start;
- PERL_UNUSED_CONTEXT;
+ PERL_ARGS_ASSERT_SV_POS_U2B_FORWARDS;
while (s < send && uoffset--)
s += UTF8SKIP(s);
whether to walk forwards or backwards to find the byte corresponding to
the passed in UTF-8 offset. */
static STRLEN
-S_sv_pos_u2b_midway(pTHX_ const U8 *const start, const U8 *send,
+S_sv_pos_u2b_midway(const U8 *const start, const U8 *send,
STRLEN uoffset, STRLEN uend)
{
STRLEN backw = uend - uoffset;
+
+ PERL_ARGS_ASSERT_SV_POS_U2B_MIDWAY;
+
if (uoffset < 2 * backw) {
/* The assumption is that going forwards is twice the speed of going
forward (that's where the 2 * backw comes from).
(The real figure of course depends on the UTF-8 data.) */
- return S_sv_pos_u2b_forwards(aTHX_ start, send, uoffset);
+ return sv_pos_u2b_forwards(start, send, uoffset);
}
while (backw--) {
static STRLEN
S_sv_pos_u2b_cached(pTHX_ SV *sv, MAGIC **mgp, const U8 *const start,
const U8 *const send, STRLEN uoffset,
- STRLEN uoffset0, STRLEN boffset0) {
+ STRLEN uoffset0, STRLEN boffset0)
+{
STRLEN boffset = 0; /* Actually always set, but let's keep gcc happy. */
bool found = FALSE;
+ PERL_ARGS_ASSERT_SV_POS_U2B_CACHED;
+
assert (uoffset >= uoffset0);
if (SvMAGICAL(sv) && !SvREADONLY(sv) && PL_utf8cache
if ((*mgp)->mg_len != -1) {
/* And we know the end too. */
boffset = boffset0
- + S_sv_pos_u2b_midway(aTHX_ start + boffset0, send,
+ + sv_pos_u2b_midway(start + boffset0, send,
uoffset - uoffset0,
(*mgp)->mg_len - uoffset0);
} else {
boffset = boffset0
- + S_sv_pos_u2b_forwards(aTHX_ start + boffset0,
+ + sv_pos_u2b_forwards(start + boffset0,
send, uoffset - uoffset0);
}
}
}
boffset = boffset0
- + S_sv_pos_u2b_midway(aTHX_ start + boffset0,
+ + sv_pos_u2b_midway(start + boffset0,
start + cache[1],
uoffset - uoffset0,
cache[0] - uoffset0);
} else {
boffset = boffset0
- + S_sv_pos_u2b_midway(aTHX_ start + boffset0,
+ + sv_pos_u2b_midway(start + boffset0,
start + cache[3],
uoffset - uoffset0,
cache[2] - uoffset0);
/* In fact, offset0 is either 0, or less than offset, so don't
need to worry about the other possibility. */
boffset = boffset0
- + S_sv_pos_u2b_midway(aTHX_ start + boffset0, send,
+ + sv_pos_u2b_midway(start + boffset0, send,
uoffset - uoffset0,
(*mgp)->mg_len - uoffset0);
found = TRUE;
if (!found || PL_utf8cache < 0) {
const STRLEN real_boffset
- = boffset0 + S_sv_pos_u2b_forwards(aTHX_ start + boffset0,
+ = boffset0 + sv_pos_u2b_forwards(start + boffset0,
send, uoffset - uoffset0);
if (found && PL_utf8cache < 0) {
infinitely while printing error messages. */
SAVEI8(PL_utf8cache);
PL_utf8cache = 0;
- Perl_croak(aTHX_ "panic: sv_pos_u2b_cache cache %"UVf
- " real %"UVf" for %"SVf,
- (UV) boffset, (UV) real_boffset, sv);
+ Perl_croak(aTHX_ "panic: sv_pos_u2b_cache cache %"UVuf
+ " real %"UVuf" for %"SVf,
+ (UV) boffset, (UV) real_boffset, SVfARG(sv));
}
}
boffset = real_boffset;
const U8 *start;
STRLEN len;
+ PERL_ARGS_ASSERT_SV_POS_U2B;
+
if (!sv)
return;
STRLEN uoffset = (STRLEN) *offsetp;
const U8 * const send = start + len;
MAGIC *mg = NULL;
- STRLEN boffset = S_sv_pos_u2b_cached(aTHX_ sv, &mg, start, send,
+ const STRLEN boffset = sv_pos_u2b_cached(sv, &mg, start, send,
uoffset, 0, 0);
*offsetp = (I32) boffset;
if (lenp) {
/* Convert the relative offset to absolute. */
- STRLEN uoffset2 = uoffset + (STRLEN) *lenp;
- STRLEN boffset2
- = S_sv_pos_u2b_cached(aTHX_ sv, &mg, start, send, uoffset2,
+ const STRLEN uoffset2 = uoffset + (STRLEN) *lenp;
+ const STRLEN boffset2
+ = sv_pos_u2b_cached(sv, &mg, start, send, uoffset2,
uoffset, boffset) - boffset;
*lenp = boffset2;
STRLEN blen)
{
STRLEN *cache;
+
+ PERL_ARGS_ASSERT_UTF8_MG_POS_CACHE_UPDATE;
+
if (SvREADONLY(sv))
return;
if (PL_utf8cache < 0) {
const U8 *start = (const U8 *) SvPVX_const(sv);
- const U8 *const end = start + byte;
- STRLEN realutf8 = 0;
-
- while (start < end) {
- start += UTF8SKIP(start);
- realutf8++;
- }
-
- /* Can't use S_sv_pos_b2u_forwards as it will scream warnings on
- surrogates. FIXME - is it inconsistent that b2u warns, but u2b
- doesn't? I don't know whether this difference was introduced with
- the caching code in 5.8.1. */
+ const STRLEN realutf8 = utf8_length(start, start + byte);
if (realutf8 != utf8) {
/* Need to turn the assertions off otherwise we may recurse
infinitely while printing error messages. */
SAVEI8(PL_utf8cache);
PL_utf8cache = 0;
- Perl_croak(aTHX_ "panic: utf8_mg_pos_cache_update cache %"UVf
- " real %"UVf" for %"SVf, (UV) utf8, (UV) realutf8, sv);
+ Perl_croak(aTHX_ "panic: utf8_mg_pos_cache_update cache %"UVuf
+ " real %"UVuf" for %"SVf, (UV) utf8, (UV) realutf8, SVfARG(sv));
}
}
ASSERT_UTF8_CACHE(cache);
}
-/* If we don't know the character offset of the end of a region, our only
- option is to walk forwards to the target byte offset. */
-static STRLEN
-S_sv_pos_b2u_forwards(pTHX_ const U8 *s, const U8 *const target)
-{
- STRLEN len = 0;
- while (s < target) {
- STRLEN n = 1;
-
- /* Call utf8n_to_uvchr() to validate the sequence
- * (unless a simple non-UTF character) */
- if (!UTF8_IS_INVARIANT(*s))
- utf8n_to_uvchr(s, UTF8SKIP(s), &n, 0);
- if (n > 0) {
- s += n;
- len++;
- }
- else
- break;
- }
- return len;
-}
-
/* We already know all of the way, now we may be able to walk back. The same
assumption is made as in S_sv_pos_u2b_midway(), namely that walking
backward is half the speed of walking forward. */
const STRLEN forw = target - s;
STRLEN backw = end - target;
+ PERL_ARGS_ASSERT_SV_POS_B2U_MIDWAY;
+
if (forw < 2 * backw) {
- return S_sv_pos_b2u_forwards(aTHX_ s, target);
+ return utf8_length(s, target);
}
while (end > target) {
const U8* send;
bool found = FALSE;
+ PERL_ARGS_ASSERT_SV_POS_B2U;
+
if (!sv)
return;
+ S_sv_pos_b2u_midway(aTHX_ s + cache[1], send,
s + blen, mg->mg_len - cache[0]);
} else {
- len = cache[0]
- + S_sv_pos_b2u_forwards(aTHX_ s + cache[1], send);
+ len = cache[0] + utf8_length(s + cache[1], send);
}
}
else if (cache[3] < byte) {
}
}
if (!found || PL_utf8cache < 0) {
- const STRLEN real_len = S_sv_pos_b2u_forwards(aTHX_ s, send);
+ const STRLEN real_len = utf8_length(s, send);
if (found && PL_utf8cache < 0) {
if (len != real_len) {
infinitely while printing error messages. */
SAVEI8(PL_utf8cache);
PL_utf8cache = 0;
- Perl_croak(aTHX_ "panic: sv_pos_b2u cache %"UVf
- " real %"UVf" for %"SVf,
- (UV) len, (UV) real_len, sv);
+ Perl_croak(aTHX_ "panic: sv_pos_b2u cache %"UVuf
+ " real %"UVuf" for %"SVf,
+ (UV) len, (UV) real_len, SVfARG(sv));
}
}
len = real_len;
pv1 = "";
cur1 = 0;
}
- else
+ else {
+ /* if pv1 and pv2 are the same, second SvPV_const call may
+ * invalidate pv1, so we may need to make a copy */
+ if (sv1 == sv2 && (SvTHINKFIRST(sv1) || SvGMAGICAL(sv1))) {
+ pv1 = SvPV_const(sv1, cur1);
+ sv1 = newSVpvn_flags(pv1, cur1, SVs_TEMP | SvUTF8(sv2));
+ }
pv1 = SvPV_const(sv1, cur1);
+ }
if (!sv2){
pv2 = "";
Compares the strings in two SVs in a locale-aware manner. Is UTF-8 and
'use bytes' aware, handles get magic, and will coerce its args to strings
-if necessary. See also C<sv_cmp_locale>. See also C<sv_cmp>.
+if necessary. See also C<sv_cmp>.
=cut
*/
dVAR;
MAGIC *mg;
+ PERL_ARGS_ASSERT_SV_COLLXFRM;
+
mg = SvMAGICAL(sv) ? mg_find(sv, PERL_MAGIC_collxfrm) : (MAGIC *) NULL;
if (!mg || !mg->mg_ptr || *(U32*)mg->mg_ptr != PL_collation_ix) {
const char *s;
Safefree(mg->mg_ptr);
s = SvPV_const(sv, len);
if ((xf = mem_collxfrm(s, len, &xlen))) {
- if (SvREADONLY(sv)) {
- SAVEFREEPV(xf);
- *nxp = xlen;
- return xf + sizeof(PL_collation_ix);
- }
if (! mg) {
#ifdef PERL_OLD_COPY_ON_WRITE
if (SvIsCOW(sv))
I32 i = 0;
I32 rspara = 0;
+ PERL_ARGS_ASSERT_SV_GETS;
+
if (SvTHINKFIRST(sv))
sv_force_normal_flags(sv, append ? 0 : SV_COW_DROP_PV);
/* XXX. If you make this PVIV, then copy on write can copy scalars read
*
* - jik 9/25/96
*/
- if (!(cnt < sizeof(buf) && PerlIO_eof(fp)))
+ if (!(cnt < (I32)sizeof(buf) && PerlIO_eof(fp)))
goto screamer2;
}
return;
}
if (flags & SVp_NOK) {
+ const NV was = SvNVX(sv);
+ if (NV_OVERFLOWS_INTEGERS_AT &&
+ was >= NV_OVERFLOWS_INTEGERS_AT && ckWARN(WARN_IMPRECISION)) {
+ Perl_warner(aTHX_ packWARN(WARN_IMPRECISION),
+ "Lost precision when incrementing %" NVff " by 1",
+ was);
+ }
(void)SvNOK_only(sv);
- SvNV_set(sv, SvNVX(sv) + 1.0);
+ SvNV_set(sv, was + 1.0);
return;
}
SvUV_set(sv, SvUVX(sv) - 1);
}
} else {
- if (SvIVX(sv) == IV_MIN)
- sv_setnv(sv, (NV)IV_MIN - 1.0);
+ if (SvIVX(sv) == IV_MIN) {
+ sv_setnv(sv, (NV)IV_MIN);
+ goto oops_its_num;
+ }
else {
(void)SvIOK_only(sv);
SvIV_set(sv, SvIVX(sv) - 1);
return;
}
if (flags & SVp_NOK) {
- SvNV_set(sv, SvNVX(sv) - 1.0);
- (void)SvNOK_only(sv);
- return;
+ oops_its_num:
+ {
+ const NV was = SvNVX(sv);
+ if (NV_OVERFLOWS_INTEGERS_AT &&
+ was <= -NV_OVERFLOWS_INTEGERS_AT && ckWARN(WARN_IMPRECISION)) {
+ Perl_warner(aTHX_ packWARN(WARN_IMPRECISION),
+ "Lost precision when decrementing %" NVff " by 1",
+ was);
+ }
+ (void)SvNOK_only(sv);
+ SvNV_set(sv, was - 1.0);
+ return;
+ }
}
if (!(flags & SVp_POK)) {
if ((flags & SVTYPEMASK) < SVt_PVIV)
return sv;
}
+
+/*
+=for apidoc newSVpvn_flags
+
+Creates a new SV and copies a string into it. The reference count for the
+SV is set to 1. Note that if C<len> is zero, Perl will create a zero length
+string. You are responsible for ensuring that the source string is at least
+C<len> bytes long. If the C<s> argument is NULL the new SV will be undefined.
+Currently the only flag bits accepted are C<SVf_UTF8> and C<SVs_TEMP>.
+If C<SVs_TEMP> is set, then C<sv2mortal()> is called on the result before
+returning. If C<SVf_UTF8> is set, then it will be set on the new SV.
+C<newSVpvn_utf8()> is a convenience wrapper for this function, defined as
+
+ #define newSVpvn_utf8(s, len, u) \
+ newSVpvn_flags((s), (len), (u) ? SVf_UTF8 : 0)
+
+=cut
+*/
+
+SV *
+Perl_newSVpvn_flags(pTHX_ const char *s, STRLEN len, U32 flags)
+{
+ dVAR;
+ register SV *sv;
+
+ /* All the flags we don't support must be zero.
+ And we're new code so I'm going to assert this from the start. */
+ assert(!(flags & ~(SVf_UTF8|SVs_TEMP)));
+ new_SV(sv);
+ sv_setpvn(sv,s,len);
+ SvFLAGS(sv) |= (flags & SVf_UTF8);
+ return (flags & SVs_TEMP) ? sv_2mortal(sv) : sv;
+}
+
/*
=for apidoc sv_2mortal
register SV *sv;
new_SV(sv);
- sv_setpvn(sv,s,len ? len : strlen(s));
+ sv_setpvn(sv, s, len || s == NULL ? len : strlen(s));
return sv;
}
return sv;
}
-
/*
=for apidoc newSVhek
SvUTF8_on (sv);
Safefree (as_utf8); /* bytes_to_utf8() allocates a new string */
return sv;
- } else if (flags & HVhek_REHASH) {
+ } else if (flags & (HVhek_REHASH|HVhek_UNSHARED)) {
/* We don't have a pointer to the hv, so we have to replicate the
flag into every HEK. This hv is using custom a hasing
algorithm. Hence we can't return a shared string scalar, as
that would contain the (wrong) hash value, and might get passed
- into an hv routine with a regular hash */
+ into an hv routine with a regular hash.
+ Similarly, a hash that isn't using shared hash keys has to have
+ the flag in every key so that we know not to try to call
+ share_hek_kek on it. */
SV * const sv = newSVpvn (HEK_KEY(hek), HEK_LEN(hek));
if (HEK_UTF8(hek))
Creates a new SV with its SvPVX_const pointing to a shared string in the string
table. If the string does not already exist in the table, it is created
-first. Turns on READONLY and FAKE. The string's hash is stored in the UV
-slot of the SV; if the C<hash> parameter is non-zero, that value is used;
-otherwise the hash is computed. The idea here is that as the string table
-is used for shared hash keys these strings will have SvPVX_const == HeKEY and
-hash lookup will avoid string compare.
+first. Turns on READONLY and FAKE. If the C<hash> parameter is non-zero, that
+value is used; otherwise the hash is computed. The string's hash can be later
+be retrieved from the SV with the C<SvSHARED_HASH()> macro. The idea here is
+that as the string table is used for shared hash keys these strings will have
+SvPVX_const == HeKEY and hash lookup will avoid string compare.
=cut
*/
dTHX;
register SV *sv;
va_list args;
+
+ PERL_ARGS_ASSERT_NEWSVPVF_NOCONTEXT;
+
va_start(args, pat);
sv = vnewSVpvf(pat, &args);
va_end(args);
{
register SV *sv;
va_list args;
+
+ PERL_ARGS_ASSERT_NEWSVPVF;
+
va_start(args, pat);
sv = vnewSVpvf(pat, &args);
va_end(args);
{
dVAR;
register SV *sv;
+
+ PERL_ARGS_ASSERT_VNEWSVPVF;
+
new_SV(sv);
sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
return sv;
}
/*
+=for apidoc newSV_type
+
+Creates a new SV, of the type specified. The reference count for the new SV
+is set to 1.
+
+=cut
+*/
+
+SV *
+Perl_newSV_type(pTHX_ const svtype type)
+{
+ register SV *sv;
+
+ new_SV(sv);
+ sv_upgrade(sv, type);
+ return sv;
+}
+
+/*
=for apidoc newRV_noinc
Creates an RV wrapper for an SV. The reference count for the original
Perl_newRV_noinc(pTHX_ SV *tmpRef)
{
dVAR;
- register SV *sv;
+ register SV *sv = newSV_type(SVt_IV);
+
+ PERL_ARGS_ASSERT_NEWRV_NOINC;
- new_SV(sv);
- sv_upgrade(sv, SVt_RV);
SvTEMP_off(tmpRef);
SvRV_set(sv, tmpRef);
SvROK_on(sv);
Perl_newRV(pTHX_ SV *sv)
{
dVAR;
+
+ PERL_ARGS_ASSERT_NEWRV;
+
return newRV_noinc(SvREFCNT_inc_simple_NN(sv));
}
dVAR;
char todo[PERL_UCHAR_MAX+1];
+ PERL_ARGS_ASSERT_SV_RESET;
+
if (!stash)
return;
if (!*s) { /* reset ?? searches */
MAGIC * const mg = mg_find((SV *)stash, PERL_MAGIC_symtab);
if (mg) {
- PMOP *pm = (PMOP *) mg->mg_obj;
- while (pm) {
- pm->op_pmdynflags &= ~PMdf_USED;
- pm = pm->op_pmnext;
+ const U32 count = mg->mg_len / sizeof(PMOP**);
+ PMOP **pmp = (PMOP**) mg->mg_ptr;
+ PMOP *const *const end = pmp + count;
+
+ while (pmp < end) {
+#ifdef USE_ITHREADS
+ SvREADONLY_off(PL_regex_pad[(*pmp)->op_pmoffset]);
+#else
+ (*pmp)->op_pmflags &= ~PMf_USED;
+#endif
+ ++pmp;
}
}
return;
IO* io;
GV* gv;
+ PERL_ARGS_ASSERT_SV_2IO;
+
switch (SvTYPE(sv)) {
case SVt_PVIO:
io = (IO*)sv;
else
io = 0;
if (!io)
- Perl_croak(aTHX_ "Bad filehandle: %"SVf, sv);
+ Perl_croak(aTHX_ "Bad filehandle: %"SVf, SVfARG(sv));
break;
}
return io;
GV *gv = NULL;
CV *cv = NULL;
+ PERL_ARGS_ASSERT_SV_2CV;
+
if (!sv) {
*st = NULL;
*gvp = NULL;
LEAVE;
if (!GvCVu(gv))
Perl_croak(aTHX_ "Unable to create sub named \"%"SVf"\"",
- sv);
+ SVfARG(sv));
}
return GvCVu(gv);
}
Perl_sv_pvn_force_flags(pTHX_ SV *sv, STRLEN *lp, I32 flags)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_PVN_FORCE_FLAGS;
+
if (SvTHINKFIRST(sv) && !SvROK(sv))
sv_force_normal_flags(sv, 0);
else
Perl_croak(aTHX_ "Can't coerce readonly %s to string", ref);
}
- if (SvTYPE(sv) > SVt_PVLV && SvTYPE(sv) != SVt_PVFM)
+ if ((SvTYPE(sv) > SVt_PVLV && SvTYPE(sv) != SVt_PVFM)
+ || isGV_with_GP(sv))
Perl_croak(aTHX_ "Can't coerce %s to string in %s", sv_reftype(sv,0),
OP_NAME(PL_op));
s = sv_2pv_flags(sv, &len, flags);
SvGROW(sv, len + 1);
Move(s,SvPVX(sv),len,char);
SvCUR_set(sv, len);
- *SvEND(sv) = '\0';
+ SvPVX(sv)[len] = '\0';
}
if (!SvPOK(sv)) {
SvPOK_on(sv); /* validate pointer */
char *
Perl_sv_pvbyten_force(pTHX_ SV *sv, STRLEN *lp)
{
+ PERL_ARGS_ASSERT_SV_PVBYTEN_FORCE;
+
sv_pvn_force(sv,lp);
sv_utf8_downgrade(sv,0);
*lp = SvCUR(sv);
char *
Perl_sv_pvutf8n_force(pTHX_ SV *sv, STRLEN *lp)
{
+ PERL_ARGS_ASSERT_SV_PVUTF8N_FORCE;
+
sv_pvn_force(sv,lp);
sv_utf8_upgrade(sv);
*lp = SvCUR(sv);
=cut
*/
-char *
+const char *
Perl_sv_reftype(pTHX_ const SV *sv, int ob)
{
+ PERL_ARGS_ASSERT_SV_REFTYPE;
+
/* The fact that I don't need to downcast to char * everywhere, only in ?:
inside return suggests a const propagation bug in g++. */
if (ob && SvOBJECT(sv)) {
case SVt_NULL:
case SVt_IV:
case SVt_NV:
- case SVt_RV:
case SVt_PV:
case SVt_PVIV:
case SVt_PVNV:
case SVt_PVMG:
- case SVt_PVBM:
if (SvVOK(sv))
return "VSTRING";
if (SvROK(sv))
case SVt_PVGV: return "GLOB";
case SVt_PVFM: return "FORMAT";
case SVt_PVIO: return "IO";
+ case SVt_BIND: return "BIND";
+ case SVt_REGEXP: return "REGEXP";
default: return "UNKNOWN";
}
}
Perl_sv_isa(pTHX_ SV *sv, const char *name)
{
const char *hvname;
+
+ PERL_ARGS_ASSERT_SV_ISA;
+
if (!sv)
return 0;
SvGETMAGIC(sv);
dVAR;
SV *sv;
+ PERL_ARGS_ASSERT_NEWSVRV;
+
new_SV(sv);
SV_CHECK_THINKFIRST_COW_DROP(rv);
- SvAMAGIC_off(rv);
+ (void)SvAMAGIC_off(rv);
if (SvTYPE(rv) >= SVt_PVMG) {
const U32 refcnt = SvREFCNT(rv);
SvFLAGS(rv) = 0;
SvREFCNT(rv) = refcnt;
- sv_upgrade(rv, SVt_RV);
+ sv_upgrade(rv, SVt_IV);
} else if (SvROK(rv)) {
SvREFCNT_dec(SvRV(rv));
- } else if (SvTYPE(rv) < SVt_RV)
- sv_upgrade(rv, SVt_RV);
- else if (SvTYPE(rv) > SVt_RV) {
- SvPV_free(rv);
- SvCUR_set(rv, 0);
- SvLEN_set(rv, 0);
+ } else {
+ prepare_SV_for_RV(rv);
}
SvOK_off(rv);
SvROK_on(rv);
if (classname) {
- HV* const stash = gv_stashpv(classname, TRUE);
+ HV* const stash = gv_stashpv(classname, GV_ADD);
(void)sv_bless(rv, stash);
}
return sv;
Perl_sv_setref_pv(pTHX_ SV *rv, const char *classname, void *pv)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_SETREF_PV;
+
if (!pv) {
sv_setsv(rv, &PL_sv_undef);
SvSETMAGIC(rv);
SV*
Perl_sv_setref_iv(pTHX_ SV *rv, const char *classname, IV iv)
{
+ PERL_ARGS_ASSERT_SV_SETREF_IV;
+
sv_setiv(newSVrv(rv,classname), iv);
return rv;
}
SV*
Perl_sv_setref_uv(pTHX_ SV *rv, const char *classname, UV uv)
{
+ PERL_ARGS_ASSERT_SV_SETREF_UV;
+
sv_setuv(newSVrv(rv,classname), uv);
return rv;
}
SV*
Perl_sv_setref_nv(pTHX_ SV *rv, const char *classname, NV nv)
{
+ PERL_ARGS_ASSERT_SV_SETREF_NV;
+
sv_setnv(newSVrv(rv,classname), nv);
return rv;
}
SV*
Perl_sv_setref_pvn(pTHX_ SV *rv, const char *classname, const char *pv, STRLEN n)
{
+ PERL_ARGS_ASSERT_SV_SETREF_PVN;
+
sv_setpvn(newSVrv(rv,classname), pv, n);
return rv;
}
{
dVAR;
SV *tmpRef;
+
+ PERL_ARGS_ASSERT_SV_BLESS;
+
if (!SvROK(sv))
Perl_croak(aTHX_ "Can't bless non-reference value");
tmpRef = SvRV(sv);
if (SvFLAGS(tmpRef) & (SVs_OBJECT|SVf_READONLY)) {
+ if (SvIsCOW(tmpRef))
+ sv_force_normal_flags(tmpRef, 0);
if (SvREADONLY(tmpRef))
Perl_croak(aTHX_ PL_no_modify);
if (SvOBJECT(tmpRef)) {
if (Gv_AMG(stash))
SvAMAGIC_on(sv);
else
- SvAMAGIC_off(sv);
+ (void)SvAMAGIC_off(sv);
if(SvSMAGICAL(tmpRef))
if(mg_find(tmpRef, PERL_MAGIC_ext) || mg_find(tmpRef, PERL_MAGIC_uvar))
{
dVAR;
void *xpvmg;
+ HV *stash;
SV * const temp = sv_newmortal();
+ PERL_ARGS_ASSERT_SV_UNGLOB;
+
assert(SvTYPE(sv) == SVt_PVGV);
SvFAKE_off(sv);
gv_efullname3(temp, (GV *) sv, "*");
if (GvGP(sv)) {
+ if(GvCVu((GV*)sv) && (stash = GvSTASH((GV*)sv)) && HvNAME_get(stash))
+ mro_method_changed_in(stash);
gp_free((GV*)sv);
}
if (GvSTASH(sv)) {
if (GvNAME_HEK(sv)) {
unshare_hek(GvNAME_HEK(sv));
}
- SvSCREAM_off(sv);
+ isGV_with_GP_off(sv);
/* need to keep SvANY(sv) in the right arena */
xpvmg = new_XPVMG();
{
SV* const target = SvRV(ref);
+ PERL_ARGS_ASSERT_SV_UNREF_FLAGS;
+
if (SvWEAKREF(ref)) {
sv_del_backref(target, ref);
SvWEAKREF_off(ref);
void
Perl_sv_untaint(pTHX_ SV *sv)
{
+ PERL_ARGS_ASSERT_SV_UNTAINT;
+
if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
if (mg)
bool
Perl_sv_tainted(pTHX_ SV *sv)
{
+ PERL_ARGS_ASSERT_SV_TAINTED;
+
if (SvTYPE(sv) >= SVt_PVMG && SvMAGIC(sv)) {
const MAGIC * const mg = mg_find(sv, PERL_MAGIC_taint);
if (mg && (mg->mg_len & 1) )
char *ebuf;
char * const ptr = uiv_2buf(buf, iv, 0, 0, &ebuf);
+ PERL_ARGS_ASSERT_SV_SETPVIV;
+
sv_setpvn(sv, ptr, ebuf - ptr);
}
void
Perl_sv_setpviv_mg(pTHX_ SV *sv, IV iv)
{
+ PERL_ARGS_ASSERT_SV_SETPVIV_MG;
+
sv_setpviv(sv, iv);
SvSETMAGIC(sv);
}
{
dTHX;
va_list args;
+
+ PERL_ARGS_ASSERT_SV_SETPVF_NOCONTEXT;
+
va_start(args, pat);
sv_vsetpvf(sv, pat, &args);
va_end(args);
{
dTHX;
va_list args;
+
+ PERL_ARGS_ASSERT_SV_SETPVF_MG_NOCONTEXT;
+
va_start(args, pat);
sv_vsetpvf_mg(sv, pat, &args);
va_end(args);
Perl_sv_setpvf(pTHX_ SV *sv, const char* pat, ...)
{
va_list args;
+
+ PERL_ARGS_ASSERT_SV_SETPVF;
+
va_start(args, pat);
sv_vsetpvf(sv, pat, &args);
va_end(args);
void
Perl_sv_vsetpvf(pTHX_ SV *sv, const char* pat, va_list* args)
{
+ PERL_ARGS_ASSERT_SV_VSETPVF;
+
sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
}
Perl_sv_setpvf_mg(pTHX_ SV *sv, const char* pat, ...)
{
va_list args;
+
+ PERL_ARGS_ASSERT_SV_SETPVF_MG;
+
va_start(args, pat);
sv_vsetpvf_mg(sv, pat, &args);
va_end(args);
void
Perl_sv_vsetpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
{
+ PERL_ARGS_ASSERT_SV_VSETPVF_MG;
+
sv_vsetpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
SvSETMAGIC(sv);
}
{
dTHX;
va_list args;
+
+ PERL_ARGS_ASSERT_SV_CATPVF_NOCONTEXT;
+
va_start(args, pat);
sv_vcatpvf(sv, pat, &args);
va_end(args);
{
dTHX;
va_list args;
+
+ PERL_ARGS_ASSERT_SV_CATPVF_MG_NOCONTEXT;
+
va_start(args, pat);
sv_vcatpvf_mg(sv, pat, &args);
va_end(args);
Perl_sv_catpvf(pTHX_ SV *sv, const char* pat, ...)
{
va_list args;
+
+ PERL_ARGS_ASSERT_SV_CATPVF;
+
va_start(args, pat);
sv_vcatpvf(sv, pat, &args);
va_end(args);
void
Perl_sv_vcatpvf(pTHX_ SV *sv, const char* pat, va_list* args)
{
+ PERL_ARGS_ASSERT_SV_VCATPVF;
+
sv_vcatpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
}
Perl_sv_catpvf_mg(pTHX_ SV *sv, const char* pat, ...)
{
va_list args;
+
+ PERL_ARGS_ASSERT_SV_CATPVF_MG;
+
va_start(args, pat);
sv_vcatpvf_mg(sv, pat, &args);
va_end(args);
void
Perl_sv_vcatpvf_mg(pTHX_ SV *sv, const char* pat, va_list* args)
{
+ PERL_ARGS_ASSERT_SV_VCATPVF_MG;
+
sv_vcatpvfn(sv, pat, strlen(pat), args, NULL, 0, NULL);
SvSETMAGIC(sv);
}
void
Perl_sv_vsetpvfn(pTHX_ SV *sv, const char *pat, STRLEN patlen, va_list *args, SV **svargs, I32 svmax, bool *maybe_tainted)
{
+ PERL_ARGS_ASSERT_SV_VSETPVFN;
+
sv_setpvn(sv, "", 0);
sv_vcatpvfn(sv, pat, patlen, args, svargs, svmax, maybe_tainted);
}
{
dVAR;
I32 var = 0;
+
+ PERL_ARGS_ASSERT_EXPECT_NUMBER;
+
switch (**pattern) {
case '1': case '2': case '3':
case '4': case '5': case '6':
const int neg = nv < 0;
UV uv;
+ PERL_ARGS_ASSERT_F0CONVERT;
+
if (neg)
nv = -nv;
if (nv < UV_MAX) {
/* large enough for "%#.#f" --chip */
/* what about long double NVs? --jhi */
+ PERL_ARGS_ASSERT_SV_VCATPVFN;
PERL_UNUSED_ARG(maybe_tainted);
/* no matter what, this is a string now */
}
if (args && patlen == 3 && pat[0] == '%' &&
pat[1] == '-' && pat[2] == 'p') {
- argsv = va_arg(*args, SV*);
+ argsv = (SV*)va_arg(*args, void*);
sv_catsv(sv, argsv);
return;
}
%p include pointer address (standard)
%-p (SVf) include an SV (previously %_)
%-<num>p include an SV with precision <num>
- %1p (VDf) include a v-string (as %vd)
%<num>p reserved for future extensions
Robin Barker 2005-07-14
+
+ %1p (VDf) removed. RMB 2007-10-19
*/
char* r = q;
bool sv = FALSE;
precis = n;
has_precis = TRUE;
}
- argsv = va_arg(*args, SV*);
- eptr = SvPVx_const(argsv, elen);
+ argsv = (SV*)va_arg(*args, void*);
+ eptr = SvPV_const(argsv, elen);
if (DO_UTF8(argsv))
is_utf8 = TRUE;
goto string;
}
-#if vdNUMBER
- else if (n == vdNUMBER) { /* VDf */
- vectorize = TRUE;
- VECTORIZE_ARGS
- goto format_vd;
- }
-#endif
else if (n) {
if (ckWARN_d(WARN_INTERNAL))
Perl_warner(aTHX_ packWARN(WARN_INTERNAL),
switch (*q) {
case ' ':
case '+':
- plus = *q++;
+ if (plus == '+' && *q == ' ') /* '+' over ' ' */
+ q++;
+ else
+ plus = *q++;
continue;
case '-':
goto unknown;
}
vecsv = sv_newmortal();
- /* scan_vstring is expected to be called during
- * tokenization, so we need to fake up the end
- * of the buffer for it
- */
- PL_bufend = version + veclen;
- scan_vstring(version, vecsv);
+ scan_vstring(version, version + veclen, vecsv);
vecstr = (U8*)SvPV_const(vecsv, veclen);
vec_utf8 = DO_UTF8(vecsv);
Safefree(version);
else
i = (ewix ? ewix <= svmax : svix < svmax)
? SvIVx(svargs[ewix ? ewix-1 : svix++]) : 0;
- precis = (i < 0) ? 0 : i;
+ precis = i;
+ has_precis = !(i < 0);
}
else {
precis = 0;
while (isDIGIT(*q))
precis = precis * 10 + (*q++ - '0');
+ has_precis = TRUE;
}
- has_precis = TRUE;
}
/* SIZE */
case 'c':
if (vectorize)
goto unknown;
- uv = (args) ? va_arg(*args, int) : SvIVx(argsv);
+ uv = (args) ? va_arg(*args, int) : SvIV(argsv);
if ((uv > 255 ||
(!UNI_IS_INVARIANT(uv) && SvUTF8(sv)))
&& !IN_BYTES) {
}
}
else {
- eptr = SvPVx_const(argsv, elen);
+ eptr = SvPV_const(argsv, elen);
if (DO_UTF8(argsv)) {
+ I32 old_precis = precis;
if (has_precis && precis < elen) {
I32 p = precis;
sv_pos_u2b(argsv, &p, 0); /* sticks at end */
precis = p;
}
if (width) { /* fudge width (can't fudge elen) */
- width += elen - sv_len_utf8(argsv);
+ if (has_precis && precis < elen)
+ width += precis - old_precis;
+ else
+ width += elen - sv_len_utf8(argsv);
}
is_utf8 = TRUE;
}
}
}
else {
- IV tiv = SvIVx(argsv); /* work around GCC bug #13488 */
+ IV tiv = SvIV(argsv); /* work around GCC bug #13488 */
switch (intsize) {
case 'h': iv = (short)tiv; break;
case 'l': iv = (long)tiv; break;
base = 10;
goto uns_integer;
+ case 'B':
case 'b':
base = 2;
goto uns_integer;
}
}
else {
- UV tuv = SvUVx(argsv); /* work around GCC bug #13488 */
+ UV tuv = SvUV(argsv); /* work around GCC bug #13488 */
switch (intsize) {
case 'h': uv = (unsigned short)tuv; break;
case 'l': uv = (unsigned long)tuv; break;
integer:
{
char *ptr = ebuf + sizeof ebuf;
+ bool tempalt = uv ? alt : FALSE; /* Vectors can't change alt */
+ zeros = 0;
+
switch (base) {
unsigned dig;
case 16:
- if (!uv)
- alt = FALSE;
- p = (char*)((c == 'X')
- ? "0123456789ABCDEF" : "0123456789abcdef");
+ p = (char *)((c == 'X') ? PL_hexdigit + 16 : PL_hexdigit);
do {
dig = uv & 15;
*--ptr = p[dig];
} while (uv >>= 4);
- if (alt) {
+ if (tempalt) {
esignbuf[esignlen++] = '0';
esignbuf[esignlen++] = c; /* 'x' or 'X' */
}
*--ptr = '0';
break;
case 2:
- if (!uv)
- alt = FALSE;
do {
dig = uv & 1;
*--ptr = '0' + dig;
} while (uv >>= 1);
- if (alt) {
+ if (tempalt) {
esignbuf[esignlen++] = '0';
- esignbuf[esignlen++] = 'b';
+ esignbuf[esignlen++] = c;
}
break;
default: /* it had better be ten or less */
if (has_precis) {
if (precis > elen)
zeros = precis - elen;
- else if (precis == 0 && elen == 1 && *eptr == '0')
+ else if (precis == 0 && elen == 1 && *eptr == '0'
+ && !(base == 8 && alt)) /* "%#.0o" prints "0" */
elen = 0;
+
+ /* a precision nullifies the 0 flag. */
+ if (fill == '0')
+ fill = ' ';
}
}
break;
#else
va_arg(*args, double)
#endif
- : SvNVx(argsv);
+ : SvNV(argsv);
need = 0;
- if (c != 'e' && c != 'E') {
+ /* nv * 0 will be NaN for NaN, +Inf and -Inf, and 0 for anything
+ else. frexp() has some unspecified behaviour for those three */
+ if (c != 'e' && c != 'E' && (nv * 0) == 0) {
i = PERL_INT_MIN;
/* FIXME: if HAS_LONG_DOUBLE but not USE_LONG_DOUBLE this
will cast our (long double) to (double) */
* --jhi */
#if defined(HAS_LONG_DOUBLE)
elen = ((intsize == 'q')
- ? my_sprintf(PL_efloatbuf, ptr, nv)
- : my_sprintf(PL_efloatbuf, ptr, (double)nv));
+ ? my_snprintf(PL_efloatbuf, PL_efloatsize, ptr, nv)
+ : my_snprintf(PL_efloatbuf, PL_efloatsize, ptr, (double)nv));
#else
elen = my_sprintf(PL_efloatbuf, ptr, nv);
#endif
(UV)c & 0xFF);
} else
sv_catpvs(msg, "end of string");
- Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%"SVf, msg); /* yes, this is reentrant */
+ Perl_warner(aTHX_ packWARN(WARN_PRINTF), "%"SVf, SVfARG(msg)); /* yes, this is reentrant */
}
/* output mangled stuff ... */
continue; /* not "break" */
}
- /* calculate width before utf8_upgrade changes it */
+ if (is_utf8 != has_utf8) {
+ if (is_utf8) {
+ if (SvCUR(sv))
+ sv_utf8_upgrade(sv);
+ }
+ else {
+ const STRLEN old_elen = elen;
+ SV * const nsv = newSVpvn_flags(eptr, elen, SVs_TEMP);
+ sv_utf8_upgrade(nsv);
+ eptr = SvPVX_const(nsv);
+ elen = SvCUR(nsv);
+
+ if (width) { /* fudge width (can't fudge elen) */
+ width += elen - old_elen;
+ }
+ is_utf8 = TRUE;
+ }
+ }
+
have = esignlen + zeros + elen;
if (have < zeros)
Perl_croak_nocontext(PL_memory_wrap);
- if (is_utf8 != has_utf8) {
- if (is_utf8) {
- if (SvCUR(sv))
- sv_utf8_upgrade(sv);
- }
- else {
- SV * const nsv = sv_2mortal(newSVpvn(eptr, elen));
- sv_utf8_upgrade(nsv);
- eptr = SvPVX_const(nsv);
- elen = SvCUR(nsv);
- }
- SvGROW(sv, SvCUR(sv) + elen + 1);
- p = SvEND(sv);
- *p = '\0';
- }
-
need = (have > width ? have : width);
gap = need - have;
All the macros and functions in this section are for the private use of
the main function, perl_clone().
-The foo_dup() functions make an exact copy of an existing foo thinngy.
+The foo_dup() functions make an exact copy of an existing foo thingy.
During the course of a cloning, a hash table is used to map old addresses
to new addresses. The table is created and manipulated with the
ptr_table_* functions.
/* Certain cases in Perl_ss_dup have been merged, by relying on the fact
- that currently av_dup and hv_dup are the same as sv_dup. If this changes,
- please unmerge ss_dup. */
+ that currently av_dup, gv_dup and hv_dup are the same as sv_dup.
+ If this changes, please unmerge ss_dup. */
#define sv_dup_inc(s,t) SvREFCNT_inc(sv_dup(s,t))
#define sv_dup_inc_NN(s,t) SvREFCNT_inc_NN(sv_dup(s,t))
#define av_dup(s,t) (AV*)sv_dup((SV*)s,t)
#define SAVEPV(p) ((p) ? savepv(p) : NULL)
#define SAVEPVN(p,n) ((p) ? savepvn(p,n) : NULL)
+/* clone a parser */
-/* Duplicate a regexp. Required reading: pregcomp() and pregfree() in
- regcomp.c. AMS 20010712 */
-
-REGEXP *
-Perl_re_dup(pTHX_ const REGEXP *r, CLONE_PARAMS *param)
+yy_parser *
+Perl_parser_dup(pTHX_ const yy_parser *proto, CLONE_PARAMS* param)
{
- dVAR;
- REGEXP *ret;
- int i, len, npar;
- struct reg_substr_datum *s;
+ yy_parser *parser;
- if (!r)
- return (REGEXP *)NULL;
+ PERL_ARGS_ASSERT_PARSER_DUP;
- if ((ret = (REGEXP *)ptr_table_fetch(PL_ptr_table, r)))
- return ret;
-
- len = r->offsets[0];
- npar = r->nparens+1;
-
- Newxc(ret, sizeof(regexp) + (len+1)*sizeof(regnode), char, regexp);
- Copy(r->program, ret->program, len+1, regnode);
+ if (!proto)
+ return NULL;
- Newx(ret->startp, npar, I32);
- Copy(r->startp, ret->startp, npar, I32);
- Newx(ret->endp, npar, I32);
- Copy(r->startp, ret->startp, npar, I32);
+ /* look for it in the table first */
+ parser = (yy_parser *)ptr_table_fetch(PL_ptr_table, proto);
+ if (parser)
+ return parser;
- Newx(ret->substrs, 1, struct reg_substr_data);
- for (s = ret->substrs->data, i = 0; i < 3; i++, s++) {
- s->min_offset = r->substrs->data[i].min_offset;
- s->max_offset = r->substrs->data[i].max_offset;
- s->substr = sv_dup_inc(r->substrs->data[i].substr, param);
- s->utf8_substr = sv_dup_inc(r->substrs->data[i].utf8_substr, param);
- }
+ /* create anew and remember what it is */
+ Newxz(parser, 1, yy_parser);
+ ptr_table_store(PL_ptr_table, proto, parser);
+
+ parser->yyerrstatus = 0;
+ parser->yychar = YYEMPTY; /* Cause a token to be read. */
+
+ /* XXX these not yet duped */
+ parser->old_parser = NULL;
+ parser->stack = NULL;
+ parser->ps = NULL;
+ parser->stack_size = 0;
+ /* XXX parser->stack->state = 0; */
+
+ /* XXX eventually, just Copy() most of the parser struct ? */
+
+ parser->lex_brackets = proto->lex_brackets;
+ parser->lex_casemods = proto->lex_casemods;
+ parser->lex_brackstack = savepvn(proto->lex_brackstack,
+ (proto->lex_brackets < 120 ? 120 : proto->lex_brackets));
+ parser->lex_casestack = savepvn(proto->lex_casestack,
+ (proto->lex_casemods < 12 ? 12 : proto->lex_casemods));
+ parser->lex_defer = proto->lex_defer;
+ parser->lex_dojoin = proto->lex_dojoin;
+ parser->lex_expect = proto->lex_expect;
+ parser->lex_formbrack = proto->lex_formbrack;
+ parser->lex_inpat = proto->lex_inpat;
+ parser->lex_inwhat = proto->lex_inwhat;
+ parser->lex_op = proto->lex_op;
+ parser->lex_repl = sv_dup_inc(proto->lex_repl, param);
+ parser->lex_starts = proto->lex_starts;
+ parser->lex_stuff = sv_dup_inc(proto->lex_stuff, param);
+ parser->multi_close = proto->multi_close;
+ parser->multi_open = proto->multi_open;
+ parser->multi_start = proto->multi_start;
+ parser->multi_end = proto->multi_end;
+ parser->pending_ident = proto->pending_ident;
+ parser->preambled = proto->preambled;
+ parser->sublex_info = proto->sublex_info; /* XXX not quite right */
+ parser->linestr = sv_dup_inc(proto->linestr, param);
+ parser->expect = proto->expect;
+ parser->copline = proto->copline;
+ parser->last_lop_op = proto->last_lop_op;
+ parser->lex_state = proto->lex_state;
+ parser->rsfp = fp_dup(proto->rsfp, '<', param);
+ /* rsfp_filters entries have fake IoDIRP() */
+ parser->rsfp_filters= av_dup_inc(proto->rsfp_filters, param);
+ parser->in_my = proto->in_my;
+ parser->in_my_stash = hv_dup(proto->in_my_stash, param);
+ parser->error_count = proto->error_count;
+
+
+ parser->linestr = sv_dup_inc(proto->linestr, param);
- ret->regstclass = NULL;
- if (r->data) {
- struct reg_data *d;
- const int count = r->data->count;
- int i;
+ {
+ char * const ols = SvPVX(proto->linestr);
+ char * const ls = SvPVX(parser->linestr);
- Newxc(d, sizeof(struct reg_data) + count*sizeof(void *),
- char, struct reg_data);
- Newx(d->what, count, U8);
-
- d->count = count;
- for (i = 0; i < count; i++) {
- d->what[i] = r->data->what[i];
- switch (d->what[i]) {
- /* legal options are one of: sfpont
- see also regcomp.h and pregfree() */
- case 's':
- d->data[i] = sv_dup_inc((SV *)r->data->data[i], param);
- break;
- case 'p':
- d->data[i] = av_dup_inc((AV *)r->data->data[i], param);
- break;
- case 'f':
- /* This is cheating. */
- Newx(d->data[i], 1, struct regnode_charclass_class);
- StructCopy(r->data->data[i], d->data[i],
- struct regnode_charclass_class);
- ret->regstclass = (regnode*)d->data[i];
- break;
- case 'o':
- /* Compiled op trees are readonly, and can thus be
- shared without duplication. */
- OP_REFCNT_LOCK;
- d->data[i] = (void*)OpREFCNT_inc((OP*)r->data->data[i]);
- OP_REFCNT_UNLOCK;
- break;
- case 'n':
- d->data[i] = r->data->data[i];
- break;
- case 't':
- d->data[i] = r->data->data[i];
- OP_REFCNT_LOCK;
- ((reg_trie_data*)d->data[i])->refcount++;
- OP_REFCNT_UNLOCK;
- break;
- default:
- Perl_croak(aTHX_ "panic: re_dup unknown data code '%c'", r->data->what[i]);
- }
- }
+ parser->bufptr = ls + (proto->bufptr >= ols ?
+ proto->bufptr - ols : 0);
+ parser->oldbufptr = ls + (proto->oldbufptr >= ols ?
+ proto->oldbufptr - ols : 0);
+ parser->oldoldbufptr= ls + (proto->oldoldbufptr >= ols ?
+ proto->oldoldbufptr - ols : 0);
+ parser->linestart = ls + (proto->linestart >= ols ?
+ proto->linestart - ols : 0);
+ parser->last_uni = ls + (proto->last_uni >= ols ?
+ proto->last_uni - ols : 0);
+ parser->last_lop = ls + (proto->last_lop >= ols ?
+ proto->last_lop - ols : 0);
- ret->data = d;
+ parser->bufend = ls + SvCUR(parser->linestr);
}
- else
- ret->data = NULL;
- Newx(ret->offsets, 2*len+1, U32);
- Copy(r->offsets, ret->offsets, 2*len+1, U32);
+ Copy(proto->tokenbuf, parser->tokenbuf, 256, char);
- ret->precomp = SAVEPVN(r->precomp, r->prelen);
- ret->refcnt = r->refcnt;
- ret->minlen = r->minlen;
- ret->prelen = r->prelen;
- ret->nparens = r->nparens;
- ret->lastparen = r->lastparen;
- ret->lastcloseparen = r->lastcloseparen;
- ret->reganch = r->reganch;
- ret->sublen = r->sublen;
-
- if (RX_MATCH_COPIED(ret))
- ret->subbeg = SAVEPVN(r->subbeg, r->sublen);
- else
- ret->subbeg = NULL;
-#ifdef PERL_OLD_COPY_ON_WRITE
- ret->saved_copy = NULL;
+#ifdef PERL_MAD
+ parser->endwhite = proto->endwhite;
+ parser->faketokens = proto->faketokens;
+ parser->lasttoke = proto->lasttoke;
+ parser->nextwhite = proto->nextwhite;
+ parser->realtokenstart = proto->realtokenstart;
+ parser->skipwhite = proto->skipwhite;
+ parser->thisclose = proto->thisclose;
+ parser->thismad = proto->thismad;
+ parser->thisopen = proto->thisopen;
+ parser->thisstuff = proto->thisstuff;
+ parser->thistoken = proto->thistoken;
+ parser->thiswhite = proto->thiswhite;
+
+ Copy(proto->nexttoke, parser->nexttoke, 5, NEXTTOKE);
+ parser->curforce = proto->curforce;
+#else
+ Copy(proto->nextval, parser->nextval, 5, YYSTYPE);
+ Copy(proto->nexttype, parser->nexttype, 5, I32);
+ parser->nexttoke = proto->nexttoke;
#endif
-
- ptr_table_store(PL_ptr_table, r, ret);
- return ret;
+ return parser;
}
+
/* duplicate a file handle */
PerlIO *
{
PerlIO *ret;
+ PERL_ARGS_ASSERT_FP_DUP;
PERL_UNUSED_ARG(type);
if (!fp)
{
GP *ret;
+ PERL_ARGS_ASSERT_GP_DUP;
+
if (!gp)
return (GP*)NULL;
/* look for it in the table first */
ret->gp_cv = cv_dup_inc(gp->gp_cv, param);
ret->gp_cvgen = gp->gp_cvgen;
ret->gp_line = gp->gp_line;
- ret->gp_file = gp->gp_file; /* points to COP.cop_file */
+ ret->gp_file_hek = hek_dup(gp->gp_file_hek, param);
return ret;
}
{
MAGIC *mgprev = (MAGIC*)NULL;
MAGIC *mgret;
+
+ PERL_ARGS_ASSERT_MG_DUP;
+
if (!mg)
return (MAGIC*)NULL;
/* look for it in the table first */
nmg->mg_private = mg->mg_private;
nmg->mg_type = mg->mg_type;
nmg->mg_flags = mg->mg_flags;
+ /* FIXME for plugins
if (mg->mg_type == PERL_MAGIC_qr) {
- nmg->mg_obj = (SV*)re_dup((REGEXP*)mg->mg_obj, param);
+ nmg->mg_obj = (SV*)CALLREGDUPE((REGEXP*)mg->mg_obj, param);
}
- else if(mg->mg_type == PERL_MAGIC_backref) {
+ else
+ */
+ if(mg->mg_type == PERL_MAGIC_backref) {
/* The backref AV has its reference count deliberately bumped by
1. */
nmg->mg_obj = SvREFCNT_inc(av_dup_inc((AV*) mg->mg_obj, param));
}
- else if (mg->mg_type == PERL_MAGIC_symtab) {
- nmg->mg_obj = mg->mg_obj;
- }
else {
nmg->mg_obj = (mg->mg_flags & MGf_REFCOUNTED)
? sv_dup_inc(mg->mg_obj, param)
return mgret;
}
+#endif /* USE_ITHREADS */
+
/* create a new pointer-mapping table */
PTR_TBL_t *
/* map an existing pointer using a table */
STATIC PTR_TBL_ENT_t *
-S_ptr_table_find(PTR_TBL_t *tbl, const void *sv) {
+S_ptr_table_find(PTR_TBL_t *tbl, const void *sv)
+{
PTR_TBL_ENT_t *tblent;
const UV hash = PTR_TABLE_HASH(sv);
- assert(tbl);
+
+ PERL_ARGS_ASSERT_PTR_TABLE_FIND;
+
tblent = tbl->tbl_ary[hash & tbl->tbl_max];
for (; tblent; tblent = tblent->next) {
if (tblent->oldval == sv)
Perl_ptr_table_fetch(pTHX_ PTR_TBL_t *tbl, const void *sv)
{
PTR_TBL_ENT_t const *const tblent = ptr_table_find(tbl, sv);
+
+ PERL_ARGS_ASSERT_PTR_TABLE_FETCH;
PERL_UNUSED_CONTEXT;
+
return tblent ? tblent->newval : NULL;
}
Perl_ptr_table_store(pTHX_ PTR_TBL_t *tbl, const void *oldsv, void *newsv)
{
PTR_TBL_ENT_t *tblent = ptr_table_find(tbl, oldsv);
+
+ PERL_ARGS_ASSERT_PTR_TABLE_STORE;
PERL_UNUSED_CONTEXT;
if (tblent) {
const UV oldsize = tbl->tbl_max + 1;
UV newsize = oldsize * 2;
UV i;
+
+ PERL_ARGS_ASSERT_PTR_TABLE_SPLIT;
PERL_UNUSED_CONTEXT;
Renew(ary, newsize, PTR_TBL_ENT_t*);
Safefree(tbl);
}
+#if defined(USE_ITHREADS)
void
Perl_rvpv_dup(pTHX_ SV *dstr, const SV *sstr, CLONE_PARAMS* param)
{
+ PERL_ARGS_ASSERT_RVPV_DUP;
+
if (SvROK(sstr)) {
SvRV_set(dstr, SvWEAKREF(sstr)
? sv_dup(SvRV(sstr), param)
}
else {
/* Copy the NULL */
- if (SvTYPE(dstr) == SVt_RV)
- SvRV_set(dstr, NULL);
- else
- SvPV_set(dstr, NULL);
+ SvPV_set(dstr, NULL);
}
}
dVAR;
SV *dstr;
- if (!sstr || SvTYPE(sstr) == SVTYPEMASK)
+ PERL_ARGS_ASSERT_SV_DUP;
+
+ if (!sstr)
+ return NULL;
+ if (SvTYPE(sstr) == SVTYPEMASK) {
+#ifdef DEBUG_LEAKING_SCALARS_ABORT
+ abort();
+#endif
return NULL;
+ }
/* look for it in the table first */
dstr = (SV*)ptr_table_fetch(PL_ptr_table, sstr);
if (dstr)
/** We are joining here so we don't want do clone
something that is bad **/
if (SvTYPE(sstr) == SVt_PVHV) {
- const char * const hvname = HvNAME_get(sstr);
+ const HEK * const hvname = HvNAME_HEK(sstr);
if (hvname)
/** don't clone stashes if they already exist **/
- return (SV*)gv_stashpv(hvname,0);
+ return (SV*)gv_stashpvn(HEK_KEY(hvname), HEK_LEN(hvname), 0);
}
}
#ifdef DEBUGGING
if (SvANY(sstr) && PL_watch_pvx && SvPVX_const(sstr) == PL_watch_pvx)
PerlIO_printf(Perl_debug_log, "watch at %p hit, found string \"%s\"\n",
- PL_watch_pvx, SvPVX_const(sstr));
+ (void*)PL_watch_pvx, SvPVX_const(sstr));
#endif
/* don't clone objects whose class has asked us not to */
if (SvOBJECT(sstr) && ! (SvFLAGS(SvSTASH(sstr)) & SVphv_CLONEABLE)) {
- SvFLAGS(dstr) &= ~SVTYPEMASK;
- SvOBJECT_off(dstr);
+ SvFLAGS(dstr) = 0;
return dstr;
}
break;
case SVt_IV:
SvANY(dstr) = (XPVIV*)((char*)&(dstr->sv_u.svu_iv) - STRUCT_OFFSET(XPVIV, xiv_iv));
- SvIV_set(dstr, SvIVX(sstr));
+ if(SvROK(sstr)) {
+ Perl_rvpv_dup(aTHX_ dstr, sstr, param);
+ } else {
+ SvIV_set(dstr, SvIVX(sstr));
+ }
break;
case SVt_NV:
SvANY(dstr) = new_XNV();
SvNV_set(dstr, SvNVX(sstr));
break;
- case SVt_RV:
- SvANY(dstr) = &(dstr->sv_u.svu_rv);
- Perl_rvpv_dup(aTHX_ dstr, sstr, param);
- break;
+ /* case SVt_BIND: */
default:
{
/* These are all the types that need complex bodies allocating. */
case SVt_PVGV:
if (GvUNIQUE((GV*)sstr)) {
- /*EMPTY*/; /* Do sharing here, and fall through */
+ NOOP; /* Do sharing here, and fall through */
}
case SVt_PVIO:
case SVt_PVFM:
case SVt_PVHV:
case SVt_PVAV:
- case SVt_PVBM:
case SVt_PVCV:
case SVt_PVLV:
+ case SVt_REGEXP:
case SVt_PVMG:
case SVt_PVNV:
case SVt_PVIV:
missing by always going for the destination.
FIXME - instrument and check that assumption */
if (sv_type >= SVt_PVMG) {
- HV *ourstash;
- if ((sv_type == SVt_PVMG) && (ourstash = OURSTASH(dstr))) {
- OURSTASH_set(dstr, hv_dup_inc(ourstash, param));
+ if ((sv_type == SVt_PVMG) && SvPAD_OUR(dstr)) {
+ SvOURSTASH_set(dstr, hv_dup_inc(SvOURSTASH(dstr), param));
} else if (SvMAGIC(dstr))
SvMAGIC_set(dstr, mg_dup(SvMAGIC(dstr), param));
if (SvSTASH(dstr))
break;
case SVt_PVMG:
break;
- case SVt_PVBM:
+ case SVt_REGEXP:
+ /* FIXME for plugins */
+ re_dup_guts((REGEXP*) sstr, (REGEXP*) dstr, param);
break;
case SVt_PVLV:
/* XXX LvTARGOFF sometimes holds PMOP* when DEBUGGING */
LvTARG(dstr) = (SV*)he_dup((HE*)LvTARG(dstr), 0, param);
else
LvTARG(dstr) = sv_dup_inc(LvTARG(dstr), param);
- break;
case SVt_PVGV:
- if (GvNAME_HEK(dstr))
- GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
-
- /* Don't call sv_add_backref here as it's going to be created
- as part of the magic cloning of the symbol table. */
- GvSTASH(dstr) = hv_dup(GvSTASH(dstr), param);
if(isGV_with_GP(sstr)) {
+ if (GvNAME_HEK(dstr))
+ GvNAME_HEK(dstr) = hek_dup(GvNAME_HEK(dstr), param);
+ /* Don't call sv_add_backref here as it's going to be
+ created as part of the magic cloning of the symbol
+ table. */
/* Danger Will Robinson - GvGP(dstr) isn't initialised
at the point of this comment. */
+ GvSTASH(dstr) = hv_dup(GvSTASH(dstr), param);
GvGP(dstr) = gp_dup(GvGP(sstr), param);
(void)GpREFCNT_inc(GvGP(dstr));
} else
IoOFP(dstr) = IoIFP(dstr);
else
IoOFP(dstr) = fp_dup(IoOFP(dstr), IoTYPE(dstr), param);
- /* PL_rsfp_filters entries have fake IoDIRP() */
+ /* PL_parser->rsfp_filters entries have fake IoDIRP() */
if(IoFLAGS(dstr) & IOf_FAKE_DIRP) {
/* I have no idea why fake dirp (rsfps)
should be treated differently but otherwise
if (IoDIRP(dstr)) {
IoDIRP(dstr) = dirp_dup(IoDIRP(dstr));
} else {
- /*EMPTY*/;
+ NOOP;
/* IoDIRP(dstr) is already a copy of IoDIRP(sstr) */
}
}
src_ary = AvARRAY((AV*)sstr);
Newxz(dst_ary, AvMAX((AV*)sstr)+1, SV*);
ptr_table_store(PL_ptr_table, src_ary, dst_ary);
- SvPV_set(dstr, (char*)dst_ary);
+ AvARRAY((AV*)dstr) = dst_ary;
AvALLOC((AV*)dstr) = dst_ary;
if (AvREAL((AV*)sstr)) {
while (items-- > 0)
}
}
else {
- SvPV_set(dstr, NULL);
+ AvARRAY((AV*)dstr) = NULL;
AvALLOC((AV*)dstr) = (SV**)NULL;
}
break;
case SVt_PVHV:
- {
- HEK *hvname = NULL;
-
- if (HvARRAY((HV*)sstr)) {
- STRLEN i = 0;
- const bool sharekeys = !!HvSHAREKEYS(sstr);
- XPVHV * const dxhv = (XPVHV*)SvANY(dstr);
- XPVHV * const sxhv = (XPVHV*)SvANY(sstr);
- char *darray;
- Newx(darray, PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1)
- + (SvOOK(sstr) ? sizeof(struct xpvhv_aux) : 0),
- char);
- HvARRAY(dstr) = (HE**)darray;
- while (i <= sxhv->xhv_max) {
- const HE *source = HvARRAY(sstr)[i];
- HvARRAY(dstr)[i] = source
- ? he_dup(source, sharekeys, param) : 0;
- ++i;
- }
- if (SvOOK(sstr)) {
- struct xpvhv_aux * const saux = HvAUX(sstr);
- struct xpvhv_aux * const daux = HvAUX(dstr);
- /* This flag isn't copied. */
- /* SvOOK_on(hv) attacks the IV flags. */
- SvFLAGS(dstr) |= SVf_OOK;
-
- hvname = saux->xhv_name;
- daux->xhv_name
- = hvname ? hek_dup(hvname, param) : hvname;
-
- daux->xhv_riter = saux->xhv_riter;
- daux->xhv_eiter = saux->xhv_eiter
- ? he_dup(saux->xhv_eiter,
- (bool)!!HvSHAREKEYS(sstr), param) : 0;
- daux->xhv_backreferences = saux->xhv_backreferences
+ if (HvARRAY((HV*)sstr)) {
+ STRLEN i = 0;
+ const bool sharekeys = !!HvSHAREKEYS(sstr);
+ XPVHV * const dxhv = (XPVHV*)SvANY(dstr);
+ XPVHV * const sxhv = (XPVHV*)SvANY(sstr);
+ char *darray;
+ Newx(darray, PERL_HV_ARRAY_ALLOC_BYTES(dxhv->xhv_max+1)
+ + (SvOOK(sstr) ? sizeof(struct xpvhv_aux) : 0),
+ char);
+ HvARRAY(dstr) = (HE**)darray;
+ while (i <= sxhv->xhv_max) {
+ const HE * const source = HvARRAY(sstr)[i];
+ HvARRAY(dstr)[i] = source
+ ? he_dup(source, sharekeys, param) : 0;
+ ++i;
+ }
+ if (SvOOK(sstr)) {
+ HEK *hvname;
+ const struct xpvhv_aux * const saux = HvAUX(sstr);
+ struct xpvhv_aux * const daux = HvAUX(dstr);
+ /* This flag isn't copied. */
+ /* SvOOK_on(hv) attacks the IV flags. */
+ SvFLAGS(dstr) |= SVf_OOK;
+
+ hvname = saux->xhv_name;
+ daux->xhv_name = hvname ? hek_dup(hvname, param) : hvname;
+
+ daux->xhv_riter = saux->xhv_riter;
+ daux->xhv_eiter = saux->xhv_eiter
+ ? he_dup(saux->xhv_eiter,
+ (bool)!!HvSHAREKEYS(sstr), param) : 0;
+ daux->xhv_backreferences =
+ saux->xhv_backreferences
? (AV*) SvREFCNT_inc(
- sv_dup((SV*)saux->
- xhv_backreferences,
- param))
+ sv_dup((SV*)saux->xhv_backreferences, param))
: 0;
- }
- }
- else {
- SvPV_set(dstr, NULL);
+
+ daux->xhv_mro_meta = saux->xhv_mro_meta
+ ? mro_meta_dup(saux->xhv_mro_meta, param)
+ : 0;
+
+ /* Record stashes for possible cloning in Perl_clone(). */
+ if (hvname)
+ av_push(param->stashes, dstr);
}
- /* Record stashes for possible cloning in Perl_clone(). */
- if(hvname)
- av_push(param->stashes, dstr);
}
+ else
+ HvARRAY((HV*)dstr) = NULL;
break;
case SVt_PVCV:
if (!(param->flags & CLONEf_COPY_STACKS)) {
{
PERL_CONTEXT *ncxs;
+ PERL_ARGS_ASSERT_CX_DUP;
+
if (!cxs)
return (PERL_CONTEXT*)NULL;
return ncxs;
/* create anew and remember what it is */
- Newxz(ncxs, max + 1, PERL_CONTEXT);
+ Newx(ncxs, max + 1, PERL_CONTEXT);
ptr_table_store(PL_ptr_table, cxs, ncxs);
+ Copy(cxs, ncxs, max + 1, PERL_CONTEXT);
while (ix >= 0) {
- PERL_CONTEXT * const cx = &cxs[ix];
PERL_CONTEXT * const ncx = &ncxs[ix];
- ncx->cx_type = cx->cx_type;
- if (CxTYPE(cx) == CXt_SUBST) {
+ if (CxTYPE(ncx) == CXt_SUBST) {
Perl_croak(aTHX_ "Cloning substitution context is unimplemented");
}
else {
- ncx->blk_oldsp = cx->blk_oldsp;
- ncx->blk_oldcop = cx->blk_oldcop;
- ncx->blk_oldmarksp = cx->blk_oldmarksp;
- ncx->blk_oldscopesp = cx->blk_oldscopesp;
- ncx->blk_oldpm = cx->blk_oldpm;
- ncx->blk_gimme = cx->blk_gimme;
- switch (CxTYPE(cx)) {
+ switch (CxTYPE(ncx)) {
case CXt_SUB:
- ncx->blk_sub.cv = (cx->blk_sub.olddepth == 0
- ? cv_dup_inc(cx->blk_sub.cv, param)
- : cv_dup(cx->blk_sub.cv,param));
- ncx->blk_sub.argarray = (cx->blk_sub.hasargs
- ? av_dup_inc(cx->blk_sub.argarray, param)
+ 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.argarray = (CxHASARGS(ncx)
+ ? av_dup_inc(ncx->blk_sub.argarray,
+ param)
: NULL);
- ncx->blk_sub.savearray = av_dup_inc(cx->blk_sub.savearray, param);
- ncx->blk_sub.olddepth = cx->blk_sub.olddepth;
- ncx->blk_sub.hasargs = cx->blk_sub.hasargs;
- ncx->blk_sub.lval = cx->blk_sub.lval;
- ncx->blk_sub.retop = cx->blk_sub.retop;
+ ncx->blk_sub.savearray = av_dup_inc(ncx->blk_sub.savearray,
+ param);
+ ncx->blk_sub.oldcomppad = (PAD*)ptr_table_fetch(PL_ptr_table,
+ ncx->blk_sub.oldcomppad);
break;
case CXt_EVAL:
- ncx->blk_eval.old_in_eval = cx->blk_eval.old_in_eval;
- ncx->blk_eval.old_op_type = cx->blk_eval.old_op_type;
- ncx->blk_eval.old_namesv = sv_dup_inc(cx->blk_eval.old_namesv, param);
- ncx->blk_eval.old_eval_root = cx->blk_eval.old_eval_root;
- ncx->blk_eval.cur_text = sv_dup(cx->blk_eval.cur_text, param);
- ncx->blk_eval.retop = cx->blk_eval.retop;
+ ncx->blk_eval.old_namesv = sv_dup_inc(ncx->blk_eval.old_namesv,
+ param);
+ ncx->blk_eval.cur_text = sv_dup(ncx->blk_eval.cur_text, param);
break;
- case CXt_LOOP:
- ncx->blk_loop.label = cx->blk_loop.label;
- ncx->blk_loop.resetsp = cx->blk_loop.resetsp;
- ncx->blk_loop.redo_op = cx->blk_loop.redo_op;
- ncx->blk_loop.next_op = cx->blk_loop.next_op;
- ncx->blk_loop.last_op = cx->blk_loop.last_op;
- ncx->blk_loop.iterdata = (CxPADLOOP(cx)
- ? cx->blk_loop.iterdata
- : gv_dup((GV*)cx->blk_loop.iterdata, param));
- ncx->blk_loop.oldcomppad
- = (PAD*)ptr_table_fetch(PL_ptr_table,
- cx->blk_loop.oldcomppad);
- ncx->blk_loop.itersave = sv_dup_inc(cx->blk_loop.itersave, param);
- ncx->blk_loop.iterlval = sv_dup_inc(cx->blk_loop.iterlval, param);
- ncx->blk_loop.iterary = av_dup_inc(cx->blk_loop.iterary, param);
- ncx->blk_loop.iterix = cx->blk_loop.iterix;
- ncx->blk_loop.itermax = cx->blk_loop.itermax;
+ case CXt_LOOP_LAZYSV:
+ ncx->blk_loop.state_u.lazysv.end
+ = sv_dup_inc(ncx->blk_loop.state_u.lazysv.end, param);
+ /* We are taking advantage of av_dup_inc and sv_dup_inc
+ actually being the same function, and order equivalance of
+ the two unions.
+ We can assert the later [but only at run time :-(] */
+ assert ((void *) &ncx->blk_loop.state_u.ary.ary ==
+ (void *) &ncx->blk_loop.state_u.lazysv.cur);
+ case CXt_LOOP_FOR:
+ ncx->blk_loop.state_u.ary.ary
+ = av_dup_inc(ncx->blk_loop.state_u.ary.ary, param);
+ case CXt_LOOP_LAZYIV:
+ case CXt_LOOP_PLAIN:
+ if (CxPADLOOP(ncx)) {
+ ncx->blk_loop.oldcomppad
+ = (PAD*)ptr_table_fetch(PL_ptr_table,
+ ncx->blk_loop.oldcomppad);
+ } else {
+ ncx->blk_loop.oldcomppad
+ = (PAD*)gv_dup((GV*)ncx->blk_loop.oldcomppad, param);
+ }
break;
case CXt_FORMAT:
- ncx->blk_sub.cv = cv_dup(cx->blk_sub.cv, param);
- ncx->blk_sub.gv = gv_dup(cx->blk_sub.gv, param);
- ncx->blk_sub.dfoutgv = gv_dup_inc(cx->blk_sub.dfoutgv, param);
- ncx->blk_sub.hasargs = cx->blk_sub.hasargs;
- ncx->blk_sub.retop = cx->blk_sub.retop;
+ ncx->blk_format.cv = cv_dup(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_BLOCK:
case CXt_NULL:
{
PERL_SI *nsi;
+ PERL_ARGS_ASSERT_SI_DUP;
+
if (!si)
return (PERL_SI*)NULL;
{
void *ret;
+ PERL_ARGS_ASSERT_ANY_DUP;
+
if (!v)
return (void*)NULL;
ANY *
Perl_ss_dup(pTHX_ PerlInterpreter *proto_perl, CLONE_PARAMS* param)
{
- ANY * const ss = proto_perl->Tsavestack;
- const I32 max = proto_perl->Tsavestack_max;
- I32 ix = proto_perl->Tsavestack_ix;
+ dVAR;
+ ANY * const ss = proto_perl->Isavestack;
+ const I32 max = proto_perl->Isavestack_max;
+ I32 ix = proto_perl->Isavestack_ix;
ANY *nss;
SV *sv;
GV *gv;
long longval;
GP *gp;
IV iv;
+ I32 i;
char *c = NULL;
void (*dptr) (void*);
void (*dxptr) (pTHX_ void*);
+ PERL_ARGS_ASSERT_SS_DUP;
+
Newxz(nss, max, ANY);
while (ix > 0) {
- I32 i = POPINT(ss,ix);
- TOPINT(nss,ix) = i;
- switch (i) {
+ const I32 type = POPINT(ss,ix);
+ TOPINT(nss,ix) = type;
+ switch (type) {
+ case SAVEt_HELEM: /* hash element */
+ sv = (SV*)POPPTR(ss,ix);
+ TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+ /* fall through */
case SAVEt_ITEM: /* normal string */
case SAVEt_SV: /* scalar reference */
sv = (SV*)POPPTR(ss,ix);
TOPPTR(nss,ix) = sv_dup_inc(sv, param);
+ /* fall through */
+ case SAVEt_FREESV:
+ case SAVEt_MORTALIZESV:
sv = (SV*)POPPTR(ss,ix);
TOPPTR(nss,ix) = sv_dup_inc(sv, param);
break;
break;
case SAVEt_HV: /* hash reference */
case SAVEt_AV: /* array reference */
- sv = POPPTR(ss,ix);
+ sv = (SV*) POPPTR(ss,ix);
TOPPTR(nss,ix) = sv_dup_inc(sv, param);
- gv = (GV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = gv_dup(gv, param);
+ /* fall through */
+ case SAVEt_COMPPAD:
+ case SAVEt_NSTAB:
+ sv = (SV*) POPPTR(ss,ix);
+ TOPPTR(nss,ix) = sv_dup(sv, param);
break;
case SAVEt_INT: /* int reference */
ptr = POPPTR(ss,ix);
case SAVEt_LONG: /* long reference */
ptr = POPPTR(ss,ix);
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
+ /* fall through */
+ case SAVEt_CLEARSV:
longval = (long)POPLONG(ss,ix);
TOPLONG(nss,ix) = longval;
break;
c = (char*)POPPTR(ss,ix);
TOPPTR(nss,ix) = pv_dup(c);
break;
- case SAVEt_NSTAB:
- gv = (GV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = gv_dup(gv, param);
- break;
case SAVEt_GP: /* scalar reference */
gp = (GP*)POPPTR(ss,ix);
TOPPTR(nss,ix) = gp = gp_dup(gp, param);
(void)GpREFCNT_inc(gp);
gv = (GV*)POPPTR(ss,ix);
TOPPTR(nss,ix) = gv_dup_inc(gv, param);
- c = (char*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = pv_dup(c);
- iv = POPIV(ss,ix);
- TOPIV(nss,ix) = iv;
- iv = POPIV(ss,ix);
- TOPIV(nss,ix) = iv;
break;
- case SAVEt_FREESV:
- case SAVEt_MORTALIZESV:
- sv = (SV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = sv_dup_inc(sv, param);
- break;
case SAVEt_FREEOP:
ptr = POPPTR(ss,ix);
if (ptr && (((OP*)ptr)->op_private & OPpREFCOUNTED)) {
case OP_LEAVEWRITE:
TOPPTR(nss,ix) = ptr;
o = (OP*)ptr;
- OpREFCNT_inc(o);
+ OP_REFCNT_LOCK;
+ (void) OpREFCNT_inc(o);
+ OP_REFCNT_UNLOCK;
break;
default:
TOPPTR(nss,ix) = NULL;
c = (char*)POPPTR(ss,ix);
TOPPTR(nss,ix) = pv_dup_inc(c);
break;
- case SAVEt_CLEARSV:
- longval = POPLONG(ss,ix);
- TOPLONG(nss,ix) = longval;
- break;
case SAVEt_DELETE:
hv = (HV*)POPPTR(ss,ix);
TOPPTR(nss,ix) = hv_dup_inc(hv, param);
c = (char*)POPPTR(ss,ix);
TOPPTR(nss,ix) = pv_dup_inc(c);
+ /* fall through */
+ case SAVEt_STACK_POS: /* Position on Perl stack */
i = POPINT(ss,ix);
TOPINT(nss,ix) = i;
break;
TOPINT(nss,ix) = i;
ix -= i;
break;
- case SAVEt_STACK_POS: /* Position on Perl stack */
- i = POPINT(ss,ix);
- TOPINT(nss,ix) = i;
- break;
case SAVEt_AELEM: /* array element */
sv = (SV*)POPPTR(ss,ix);
TOPPTR(nss,ix) = sv_dup_inc(sv, param);
av = (AV*)POPPTR(ss,ix);
TOPPTR(nss,ix) = av_dup_inc(av, param);
break;
- case SAVEt_HELEM: /* hash element */
- sv = (SV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = sv_dup_inc(sv, param);
- sv = (SV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = sv_dup_inc(sv, param);
- hv = (HV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = hv_dup_inc(hv, param);
- break;
case SAVEt_OP:
ptr = POPPTR(ss,ix);
TOPPTR(nss,ix) = ptr;
TOPPTR(nss,ix) = hv_dup_inc(hv, param);
}
break;
- case SAVEt_COMPPAD:
- av = (AV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = av_dup(av, param);
- break;
- case SAVEt_PADSV:
+ case SAVEt_PADSV_AND_MORTALIZE:
longval = (long)POPLONG(ss,ix);
TOPLONG(nss,ix) = longval;
ptr = POPPTR(ss,ix);
TOPPTR(nss,ix) = any_dup(ptr, proto_perl);
sv = (SV*)POPPTR(ss,ix);
- TOPPTR(nss,ix) = sv_dup(sv, param);
+ TOPPTR(nss,ix) = sv_dup_inc(sv, param);
break;
case SAVEt_BOOL:
ptr = POPPTR(ss,ix);
= pv_dup(old_state->re_state_reginput);
new_state->re_state_regeol
= pv_dup(old_state->re_state_regeol);
- new_state->re_state_regstartp
- = any_dup(old_state->re_state_regstartp, proto_perl);
- new_state->re_state_regendp
- = any_dup(old_state->re_state_regendp, proto_perl);
+ new_state->re_state_regoffs
+ = (regexp_paren_pair*)
+ any_dup(old_state->re_state_regoffs, proto_perl);
new_state->re_state_reglastparen
- = any_dup(old_state->re_state_reglastparen, proto_perl);
+ = (U32*) any_dup(old_state->re_state_reglastparen,
+ proto_perl);
new_state->re_state_reglastcloseparen
- = any_dup(old_state->re_state_reglastcloseparen,
+ = (U32*)any_dup(old_state->re_state_reglastcloseparen,
proto_perl);
/* XXX This just has to be broken. The old save_re_context
code did SAVEGENERICPV(PL_reg_start_tmp);
= sv_dup(old_state->re_state_nrs, param);
#endif
new_state->re_state_reg_magic
- = any_dup(old_state->re_state_reg_magic, proto_perl);
+ = (MAGIC*) any_dup(old_state->re_state_reg_magic,
+ proto_perl);
new_state->re_state_reg_oldcurpm
- = any_dup(old_state->re_state_reg_oldcurpm, proto_perl);
+ = (PMOP*) any_dup(old_state->re_state_reg_oldcurpm,
+ proto_perl);
new_state->re_state_reg_curpm
- = any_dup(old_state->re_state_reg_curpm, proto_perl);
+ = (PMOP*) any_dup(old_state->re_state_reg_curpm,
+ proto_perl);
new_state->re_state_reg_oldsaved
= pv_dup(old_state->re_state_reg_oldsaved);
new_state->re_state_reg_poscache
= pv_dup(old_state->re_state_reg_poscache);
-#ifdef DEBUGGING
new_state->re_state_reg_starttry
= pv_dup(old_state->re_state_reg_starttry);
-#endif
break;
}
case SAVEt_COMPILE_WARNINGS:
ptr = POPPTR(ss,ix);
TOPPTR(nss,ix) = DUP_WARNINGS((STRLEN*)ptr);
break;
+ case SAVEt_PARSER:
+ ptr = POPPTR(ss,ix);
+ TOPPTR(nss,ix) = parser_dup((const yy_parser*)ptr, param);
+ break;
default:
- Perl_croak(aTHX_ "panic: ss_dup inconsistency (%"IVdf")", (IV) i);
+ Perl_croak(aTHX_
+ "panic: ss_dup inconsistency (%"IVdf")", (IV) type);
}
}
* so we know which stashes want their objects cloned */
static void
-do_mark_cloneable_stash(pTHX_ SV *sv)
+do_mark_cloneable_stash(pTHX_ SV *const sv)
{
const HEK * const hvname = HvNAME_HEK((HV*)sv);
if (hvname) {
ENTER;
SAVETMPS;
PUSHMARK(SP);
- XPUSHs(sv_2mortal(newSVhek(hvname)));
+ mXPUSHs(newSVhek(hvname));
PUTBACK;
call_sv((SV*)GvCV(cloner), G_SCALAR);
SPAGAIN;
with it we copy the stacks and the new perl interpreter is
ready to run at the exact same point as the previous one.
The pseudo-fork code uses COPY_STACKS while the
-threads->new doesn't.
+threads->create doesn't.
CLONEf_KEEP_PTR_TABLE
perl_clone keeps a ptr_table with the pointer of the old
dVAR;
#ifdef PERL_IMPLICIT_SYS
+ PERL_ARGS_ASSERT_PERL_CLONE;
+
/* perlhost.h so we need to call into it
to clone the host, CPerlHost should have a c interface, sky */
CLONE_PARAMS* const param = &clone_params;
PerlInterpreter * const my_perl = (PerlInterpreter*)(*ipM->pMalloc)(ipM, sizeof(PerlInterpreter));
+
+ PERL_ARGS_ASSERT_PERL_CLONE_USING;
+
/* for each stash, determine whether its objects should be cloned */
S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
PERL_SET_THX(my_perl);
PL_savestack_ix = 0;
PL_savestack_max = -1;
PL_sig_pending = 0;
+ PL_parser = NULL;
Zero(&PL_debug_pad, 1, struct perl_debug_pad);
# else /* !DEBUGGING */
Zero(my_perl, 1, PerlInterpreter);
CLONE_PARAMS clone_params;
CLONE_PARAMS* param = &clone_params;
PerlInterpreter * const my_perl = (PerlInterpreter*)PerlMem_malloc(sizeof(PerlInterpreter));
+
+ PERL_ARGS_ASSERT_PERL_CLONE;
+
/* for each stash, determine whether its objects should be cloned */
S_visit(proto_perl, do_mark_cloneable_stash, SVt_PVHV, SVTYPEMASK);
PERL_SET_THX(my_perl);
PL_savestack_ix = 0;
PL_savestack_max = -1;
PL_sig_pending = 0;
+ PL_parser = NULL;
Zero(&PL_debug_pad, 1, struct perl_debug_pad);
# else /* !DEBUGGING */
Zero(my_perl, 1, PerlInterpreter);
SvREFCNT(&PL_sv_no) = (~(U32)0)/2;
SvFLAGS(&PL_sv_no) = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
|SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
- SvPV_set(&PL_sv_no, SAVEPVN(PL_No, 0));
+ SvPV_set(&PL_sv_no, savepvn(PL_No, 0));
SvCUR_set(&PL_sv_no, 0);
SvLEN_set(&PL_sv_no, 1);
SvIV_set(&PL_sv_no, 0);
SvREFCNT(&PL_sv_yes) = (~(U32)0)/2;
SvFLAGS(&PL_sv_yes) = SVp_IOK|SVf_IOK|SVp_NOK|SVf_NOK
|SVp_POK|SVf_POK|SVf_READONLY|SVt_PVNV;
- SvPV_set(&PL_sv_yes, SAVEPVN(PL_Yes, 1));
+ SvPV_set(&PL_sv_yes, savepvn(PL_Yes, 1));
SvCUR_set(&PL_sv_yes, 1);
SvLEN_set(&PL_sv_yes, 2);
SvIV_set(&PL_sv_yes, 1);
ptr_table_store(PL_ptr_table, &proto_perl->Icompiling, &PL_compiling);
PL_compiling.cop_warnings = DUP_WARNINGS(PL_compiling.cop_warnings);
- if (!specialCopIO(PL_compiling.cop_io))
- PL_compiling.cop_io = sv_dup_inc(PL_compiling.cop_io, param);
- if (PL_compiling.cop_hints) {
+ if (PL_compiling.cop_hints_hash) {
HINTS_REFCNT_LOCK;
- PL_compiling.cop_hints->refcounted_he_refcnt++;
+ PL_compiling.cop_hints_hash->refcounted_he_refcnt++;
HINTS_REFCNT_UNLOCK;
}
- PL_curcop = (COP*)any_dup(proto_perl->Tcurcop, proto_perl);
+ PL_curcop = (COP*)any_dup(proto_perl->Icurcop, proto_perl);
+#ifdef PERL_DEBUG_READONLY_OPS
+ PL_slabs = NULL;
+ PL_slab_count = 0;
+#endif
/* pseudo environmental stuff */
PL_origargc = proto_perl->Iorigargc;
PL_patchlevel = sv_dup_inc(proto_perl->Ipatchlevel, param);
PL_localpatches = proto_perl->Ilocalpatches;
PL_splitstr = proto_perl->Isplitstr;
- PL_preprocess = proto_perl->Ipreprocess;
PL_minus_n = proto_perl->Iminus_n;
PL_minus_p = proto_perl->Iminus_p;
PL_minus_l = proto_perl->Iminus_l;
sv_setpvn(PERL_DEBUG_PAD(1), "", 0); /* ext/re needs these */
sv_setpvn(PERL_DEBUG_PAD(2), "", 0); /* even without DEBUGGING. */
+
+ /* RE engine related */
+ Zero(&PL_reg_state, 1, struct re_save_state);
+ PL_reginterp_cnt = 0;
+ PL_regmatch_slab = NULL;
+
/* Clone the regex array */
- PL_regex_padav = newAV();
- {
- const I32 len = av_len((AV*)proto_perl->Iregex_padav);
- SV* const * const regexen = AvARRAY((AV*)proto_perl->Iregex_padav);
- IV i;
- av_push(PL_regex_padav, sv_dup_inc_NN(regexen[0],param));
- for(i = 1; i <= len; i++) {
- const SV * const regex = regexen[i];
- SV * const sv =
- SvREPADTMP(regex)
- ? sv_dup_inc(regex, param)
- : SvREFCNT_inc(
- newSViv(PTR2IV(re_dup(
- INT2PTR(REGEXP *, SvIVX(regex)), param))))
- ;
- av_push(PL_regex_padav, sv);
- }
- }
+ /* ORANGE FIXME for plugins, probably in the SV dup code.
+ newSViv(PTR2IV(CALLREGDUPE(
+ INT2PTR(REGEXP *, SvIVX(regex)), param))))
+ */
+ PL_regex_padav = av_dup_inc(proto_perl->Iregex_padav, param);
PL_regex_pad = AvARRAY(PL_regex_padav);
/* shortcuts to various I/O objects */
PL_DBsingle = sv_dup(proto_perl->IDBsingle, param);
PL_DBtrace = sv_dup(proto_perl->IDBtrace, param);
PL_DBsignal = sv_dup(proto_perl->IDBsignal, param);
- PL_DBassertion = sv_dup(proto_perl->IDBassertion, param);
- PL_lineary = av_dup(proto_perl->Ilineary, param);
PL_dbargs = av_dup(proto_perl->Idbargs, param);
/* symbol tables */
- PL_defstash = hv_dup_inc(proto_perl->Tdefstash, param);
- PL_curstash = hv_dup(proto_perl->Tcurstash, param);
+ PL_defstash = hv_dup_inc(proto_perl->Idefstash, param);
+ PL_curstash = hv_dup(proto_perl->Icurstash, param);
PL_debstash = hv_dup(proto_perl->Idebstash, param);
PL_globalstash = hv_dup(proto_perl->Iglobalstash, param);
PL_curstname = sv_dup_inc(proto_perl->Icurstname, param);
PL_beginav = av_dup_inc(proto_perl->Ibeginav, param);
PL_beginav_save = av_dup_inc(proto_perl->Ibeginav_save, param);
PL_checkav_save = av_dup_inc(proto_perl->Icheckav_save, param);
+ PL_unitcheckav = av_dup_inc(proto_perl->Iunitcheckav, param);
+ PL_unitcheckav_save = av_dup_inc(proto_perl->Iunitcheckav_save, param);
PL_endav = av_dup_inc(proto_perl->Iendav, param);
PL_checkav = av_dup_inc(proto_perl->Icheckav, param);
PL_initav = av_dup_inc(proto_perl->Iinitav, param);
PL_sub_generation = proto_perl->Isub_generation;
+ PL_isarev = hv_dup_inc(proto_perl->Iisarev, param);
/* funky return mechanisms */
PL_forkprocess = proto_perl->Iforkprocess;
/* current interpreter roots */
PL_main_cv = cv_dup_inc(proto_perl->Imain_cv, param);
+ OP_REFCNT_LOCK;
PL_main_root = OpREFCNT_inc(proto_perl->Imain_root);
+ OP_REFCNT_UNLOCK;
PL_main_start = proto_perl->Imain_start;
PL_eval_root = proto_perl->Ieval_root;
PL_eval_start = proto_perl->Ieval_start;
/* runtime control stuff */
PL_curcopdb = (COP*)any_dup(proto_perl->Icurcopdb, proto_perl);
- PL_copline = proto_perl->Icopline;
PL_filemode = proto_perl->Ifilemode;
PL_lastfd = proto_perl->Ilastfd;
PL_Argv = NULL;
PL_Cmd = NULL;
PL_gensym = proto_perl->Igensym;
- PL_preambled = proto_perl->Ipreambled;
PL_preambleav = av_dup_inc(proto_perl->Ipreambleav, param);
PL_laststatval = proto_perl->Ilaststatval;
PL_laststype = proto_perl->Ilaststype;
if (PL_my_cxt_size) {
Newx(PL_my_cxt_list, PL_my_cxt_size, void *);
Copy(proto_perl->Imy_cxt_list, PL_my_cxt_list, PL_my_cxt_size, void *);
+#ifdef PERL_GLOBAL_STRUCT_PRIVATE
+ Newx(PL_my_cxt_keys, PL_my_cxt_size, const char *);
+ Copy(proto_perl->Imy_cxt_keys, PL_my_cxt_keys, PL_my_cxt_size, char *);
+#endif
}
- else
+ else {
PL_my_cxt_list = (void**)NULL;
+#ifdef PERL_GLOBAL_STRUCT_PRIVATE
+ PL_my_cxt_keys = (const char**)NULL;
+#endif
+ }
PL_modglobal = hv_dup_inc(proto_perl->Imodglobal, param);
PL_custom_op_names = hv_dup_inc(proto_perl->Icustom_op_names,param);
PL_custom_op_descs = hv_dup_inc(proto_perl->Icustom_op_descs,param);
PL_profiledata = NULL;
- PL_rsfp = fp_dup(proto_perl->Irsfp, '<', param);
- /* PL_rsfp_filters entries have fake IoDIRP() */
- PL_rsfp_filters = av_dup_inc(proto_perl->Irsfp_filters, param);
PL_compcv = cv_dup(proto_perl->Icompcv, param);
PL_runops = proto_perl->Irunops;
- Copy(proto_perl->Itokenbuf, PL_tokenbuf, 256, char);
-
-#ifdef CSH
- PL_cshlen = proto_perl->Icshlen;
- PL_cshname = proto_perl->Icshname; /* XXX never deallocated */
-#endif
-
- PL_lex_state = proto_perl->Ilex_state;
- PL_lex_defer = proto_perl->Ilex_defer;
- PL_lex_expect = proto_perl->Ilex_expect;
- PL_lex_formbrack = proto_perl->Ilex_formbrack;
- PL_lex_dojoin = proto_perl->Ilex_dojoin;
- PL_lex_starts = proto_perl->Ilex_starts;
- PL_lex_stuff = sv_dup_inc(proto_perl->Ilex_stuff, param);
- PL_lex_repl = sv_dup_inc(proto_perl->Ilex_repl, param);
- PL_lex_op = proto_perl->Ilex_op;
- PL_lex_inpat = proto_perl->Ilex_inpat;
- PL_lex_inwhat = proto_perl->Ilex_inwhat;
- PL_lex_brackets = proto_perl->Ilex_brackets;
- i = (PL_lex_brackets < 120 ? 120 : PL_lex_brackets);
- PL_lex_brackstack = SAVEPVN(proto_perl->Ilex_brackstack,i);
- PL_lex_casemods = proto_perl->Ilex_casemods;
- i = (PL_lex_casemods < 12 ? 12 : PL_lex_casemods);
- PL_lex_casestack = SAVEPVN(proto_perl->Ilex_casestack,i);
-
-#ifdef PERL_MAD
- Copy(proto_perl->Inexttoke, PL_nexttoke, 5, NEXTTOKE);
- PL_lasttoke = proto_perl->Ilasttoke;
- PL_realtokenstart = proto_perl->Irealtokenstart;
- PL_faketokens = proto_perl->Ifaketokens;
- PL_thismad = proto_perl->Ithismad;
- PL_thistoken = proto_perl->Ithistoken;
- PL_thisopen = proto_perl->Ithisopen;
- PL_thisstuff = proto_perl->Ithisstuff;
- PL_thisclose = proto_perl->Ithisclose;
- PL_thiswhite = proto_perl->Ithiswhite;
- PL_nextwhite = proto_perl->Inextwhite;
- PL_skipwhite = proto_perl->Iskipwhite;
- PL_endwhite = proto_perl->Iendwhite;
- PL_curforce = proto_perl->Icurforce;
-#else
- Copy(proto_perl->Inextval, PL_nextval, 5, YYSTYPE);
- Copy(proto_perl->Inexttype, PL_nexttype, 5, I32);
- PL_nexttoke = proto_perl->Inexttoke;
-#endif
-
- /* XXX This is probably masking the deeper issue of why
- * SvANY(proto_perl->Ilinestr) can be NULL at this point. For test case:
- * http://archive.develooper.com/perl5-porters%40perl.org/msg83298.html
- * (A little debugging with a watchpoint on it may help.)
- */
- if (SvANY(proto_perl->Ilinestr)) {
- PL_linestr = sv_dup_inc(proto_perl->Ilinestr, param);
- i = proto_perl->Ibufptr - SvPVX_const(proto_perl->Ilinestr);
- PL_bufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
- i = proto_perl->Ioldbufptr - SvPVX_const(proto_perl->Ilinestr);
- PL_oldbufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
- i = proto_perl->Ioldoldbufptr - SvPVX_const(proto_perl->Ilinestr);
- PL_oldoldbufptr = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
- i = proto_perl->Ilinestart - SvPVX_const(proto_perl->Ilinestr);
- PL_linestart = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
- }
- else {
- PL_linestr = newSV(79);
- sv_upgrade(PL_linestr,SVt_PVIV);
- sv_setpvn(PL_linestr,"",0);
- PL_bufptr = PL_oldbufptr = PL_oldoldbufptr = PL_linestart = SvPVX(PL_linestr);
- }
- PL_bufend = SvPVX(PL_linestr) + SvCUR(PL_linestr);
- PL_pending_ident = proto_perl->Ipending_ident;
- PL_sublex_info = proto_perl->Isublex_info; /* XXX not quite right */
-
- PL_expect = proto_perl->Iexpect;
+ PL_parser = parser_dup(proto_perl->Iparser, param);
- PL_multi_start = proto_perl->Imulti_start;
- PL_multi_end = proto_perl->Imulti_end;
- PL_multi_open = proto_perl->Imulti_open;
- PL_multi_close = proto_perl->Imulti_close;
-
- PL_error_count = proto_perl->Ierror_count;
PL_subline = proto_perl->Isubline;
PL_subname = sv_dup_inc(proto_perl->Isubname, param);
- /* XXX See comment on SvANY(proto_perl->Ilinestr) above */
- if (SvANY(proto_perl->Ilinestr)) {
- i = proto_perl->Ilast_uni - SvPVX_const(proto_perl->Ilinestr);
- PL_last_uni = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
- i = proto_perl->Ilast_lop - SvPVX_const(proto_perl->Ilinestr);
- PL_last_lop = SvPVX(PL_linestr) + (i < 0 ? 0 : i);
- PL_last_lop_op = proto_perl->Ilast_lop_op;
- }
- else {
- PL_last_uni = SvPVX(PL_linestr);
- PL_last_lop = SvPVX(PL_linestr);
- PL_last_lop_op = 0;
- }
- PL_in_my = proto_perl->Iin_my;
- PL_in_my_stash = hv_dup(proto_perl->Iin_my_stash, param);
#ifdef FCRYPT
PL_cryptseen = proto_perl->Icryptseen;
#endif
PL_lockhook = proto_perl->Ilockhook;
PL_unlockhook = proto_perl->Iunlockhook;
PL_threadhook = proto_perl->Ithreadhook;
-
- PL_runops_std = proto_perl->Irunops_std;
- PL_runops_dbg = proto_perl->Irunops_dbg;
+ PL_destroyhook = proto_perl->Idestroyhook;
#ifdef THREADS_HAVE_PIDS
PL_ppid = proto_perl->Ippid;
PL_glob_index = proto_perl->Iglob_index;
PL_srand_called = proto_perl->Isrand_called;
- PL_uudmap['M'] = 0; /* reinits on demand */
PL_bitcount = NULL; /* reinits on demand */
if (proto_perl->Ipsig_pend) {
PL_psig_name = (SV**)NULL;
}
- /* thrdvar.h stuff */
+ /* intrpvar.h stuff */
if (flags & CLONEf_COPY_STACKS) {
/* next allocation will be PL_tmps_stack[PL_tmps_ix+1] */
- PL_tmps_ix = proto_perl->Ttmps_ix;
- PL_tmps_max = proto_perl->Ttmps_max;
- PL_tmps_floor = proto_perl->Ttmps_floor;
+ PL_tmps_ix = proto_perl->Itmps_ix;
+ PL_tmps_max = proto_perl->Itmps_max;
+ PL_tmps_floor = proto_perl->Itmps_floor;
Newxz(PL_tmps_stack, PL_tmps_max, SV*);
i = 0;
while (i <= PL_tmps_ix) {
- PL_tmps_stack[i] = sv_dup_inc(proto_perl->Ttmps_stack[i], param);
+ PL_tmps_stack[i] = sv_dup_inc(proto_perl->Itmps_stack[i], param);
++i;
}
/* next PUSHMARK() sets *(PL_markstack_ptr+1) */
- i = proto_perl->Tmarkstack_max - proto_perl->Tmarkstack;
+ i = proto_perl->Imarkstack_max - proto_perl->Imarkstack;
Newxz(PL_markstack, i, I32);
- PL_markstack_max = PL_markstack + (proto_perl->Tmarkstack_max
- - proto_perl->Tmarkstack);
- PL_markstack_ptr = PL_markstack + (proto_perl->Tmarkstack_ptr
- - proto_perl->Tmarkstack);
- Copy(proto_perl->Tmarkstack, PL_markstack,
+ PL_markstack_max = PL_markstack + (proto_perl->Imarkstack_max
+ - proto_perl->Imarkstack);
+ PL_markstack_ptr = PL_markstack + (proto_perl->Imarkstack_ptr
+ - proto_perl->Imarkstack);
+ Copy(proto_perl->Imarkstack, PL_markstack,
PL_markstack_ptr - PL_markstack + 1, I32);
/* next push_scope()/ENTER sets PL_scopestack[PL_scopestack_ix]
* NOTE: unlike the others! */
- PL_scopestack_ix = proto_perl->Tscopestack_ix;
- PL_scopestack_max = proto_perl->Tscopestack_max;
+ PL_scopestack_ix = proto_perl->Iscopestack_ix;
+ PL_scopestack_max = proto_perl->Iscopestack_max;
Newxz(PL_scopestack, PL_scopestack_max, I32);
- Copy(proto_perl->Tscopestack, PL_scopestack, PL_scopestack_ix, I32);
+ Copy(proto_perl->Iscopestack, PL_scopestack, PL_scopestack_ix, I32);
/* NOTE: si_dup() looks at PL_markstack */
- PL_curstackinfo = si_dup(proto_perl->Tcurstackinfo, param);
+ PL_curstackinfo = si_dup(proto_perl->Icurstackinfo, param);
/* PL_curstack = PL_curstackinfo->si_stack; */
- PL_curstack = av_dup(proto_perl->Tcurstack, param);
- PL_mainstack = av_dup(proto_perl->Tmainstack, param);
+ PL_curstack = av_dup(proto_perl->Icurstack, param);
+ PL_mainstack = av_dup(proto_perl->Imainstack, param);
/* next PUSHs() etc. set *(PL_stack_sp+1) */
PL_stack_base = AvARRAY(PL_curstack);
- PL_stack_sp = PL_stack_base + (proto_perl->Tstack_sp
- - proto_perl->Tstack_base);
+ PL_stack_sp = PL_stack_base + (proto_perl->Istack_sp
+ - proto_perl->Istack_base);
PL_stack_max = PL_stack_base + AvMAX(PL_curstack);
/* next SSPUSHFOO() sets PL_savestack[PL_savestack_ix]
* NOTE: unlike the others! */
- PL_savestack_ix = proto_perl->Tsavestack_ix;
- PL_savestack_max = proto_perl->Tsavestack_max;
+ PL_savestack_ix = proto_perl->Isavestack_ix;
+ PL_savestack_max = proto_perl->Isavestack_max;
/*Newxz(PL_savestack, PL_savestack_max, ANY);*/
PL_savestack = ss_dup(proto_perl, param);
}
* non-refcount means (eg a temp in @_); otherwise they will be
* orphaned
*/
- for (i = 0; i<= proto_perl->Ttmps_ix; i++) {
+ for (i = 0; i<= proto_perl->Itmps_ix; i++) {
SV * const nsv = (SV*)ptr_table_fetch(PL_ptr_table,
- proto_perl->Ttmps_stack[i]);
+ proto_perl->Itmps_stack[i]);
if (nsv && !SvREFCNT(nsv)) {
EXTEND_MORTAL(1);
PL_tmps_stack[++PL_tmps_ix] = SvREFCNT_inc_simple(nsv);
}
}
- PL_start_env = proto_perl->Tstart_env; /* XXXXXX */
+ PL_start_env = proto_perl->Istart_env; /* XXXXXX */
PL_top_env = &PL_start_env;
- PL_op = proto_perl->Top;
+ PL_op = proto_perl->Iop;
PL_Sv = NULL;
PL_Xpv = (XPV*)NULL;
- PL_na = proto_perl->Tna;
+ my_perl->Ina = proto_perl->Ina;
- PL_statbuf = proto_perl->Tstatbuf;
- PL_statcache = proto_perl->Tstatcache;
- PL_statgv = gv_dup(proto_perl->Tstatgv, param);
- PL_statname = sv_dup_inc(proto_perl->Tstatname, param);
+ PL_statbuf = proto_perl->Istatbuf;
+ PL_statcache = proto_perl->Istatcache;
+ PL_statgv = gv_dup(proto_perl->Istatgv, param);
+ PL_statname = sv_dup_inc(proto_perl->Istatname, param);
#ifdef HAS_TIMES
- PL_timesbuf = proto_perl->Ttimesbuf;
+ PL_timesbuf = proto_perl->Itimesbuf;
#endif
- PL_tainted = proto_perl->Ttainted;
- PL_curpm = proto_perl->Tcurpm; /* XXX No PMOP ref count */
- PL_rs = sv_dup_inc(proto_perl->Trs, param);
- PL_last_in_gv = gv_dup(proto_perl->Tlast_in_gv, param);
- PL_ofs_sv = sv_dup_inc(proto_perl->Tofs_sv, param);
- PL_defoutgv = gv_dup_inc(proto_perl->Tdefoutgv, param);
- PL_chopset = proto_perl->Tchopset; /* XXX never deallocated */
- PL_toptarget = sv_dup_inc(proto_perl->Ttoptarget, param);
- PL_bodytarget = sv_dup_inc(proto_perl->Tbodytarget, param);
- PL_formtarget = sv_dup(proto_perl->Tformtarget, param);
-
- PL_restartop = proto_perl->Trestartop;
- PL_in_eval = proto_perl->Tin_eval;
- PL_delaymagic = proto_perl->Tdelaymagic;
- PL_dirty = proto_perl->Tdirty;
- PL_localizing = proto_perl->Tlocalizing;
-
- PL_errors = sv_dup_inc(proto_perl->Terrors, param);
+ PL_tainted = proto_perl->Itainted;
+ PL_curpm = proto_perl->Icurpm; /* XXX No PMOP ref count */
+ PL_rs = sv_dup_inc(proto_perl->Irs, param);
+ PL_last_in_gv = gv_dup(proto_perl->Ilast_in_gv, param);
+ PL_ofs_sv = sv_dup_inc(proto_perl->Iofs_sv, param);
+ PL_defoutgv = gv_dup_inc(proto_perl->Idefoutgv, param);
+ PL_chopset = proto_perl->Ichopset; /* XXX never deallocated */
+ PL_toptarget = sv_dup_inc(proto_perl->Itoptarget, param);
+ PL_bodytarget = sv_dup_inc(proto_perl->Ibodytarget, param);
+ PL_formtarget = sv_dup(proto_perl->Iformtarget, param);
+
+ PL_restartop = proto_perl->Irestartop;
+ PL_in_eval = proto_perl->Iin_eval;
+ PL_delaymagic = proto_perl->Idelaymagic;
+ PL_dirty = proto_perl->Idirty;
+ PL_localizing = proto_perl->Ilocalizing;
+
+ PL_errors = sv_dup_inc(proto_perl->Ierrors, param);
PL_hv_fetch_ent_mh = NULL;
- PL_modcount = proto_perl->Tmodcount;
+ PL_modcount = proto_perl->Imodcount;
PL_lastgotoprobe = NULL;
- PL_dumpindent = proto_perl->Tdumpindent;
+ PL_dumpindent = proto_perl->Idumpindent;
- PL_sortcop = (OP*)any_dup(proto_perl->Tsortcop, proto_perl);
- PL_sortstash = hv_dup(proto_perl->Tsortstash, param);
- PL_firstgv = gv_dup(proto_perl->Tfirstgv, param);
- PL_secondgv = gv_dup(proto_perl->Tsecondgv, param);
+ PL_sortcop = (OP*)any_dup(proto_perl->Isortcop, proto_perl);
+ PL_sortstash = hv_dup(proto_perl->Isortstash, param);
+ PL_firstgv = gv_dup(proto_perl->Ifirstgv, param);
+ PL_secondgv = gv_dup(proto_perl->Isecondgv, param);
PL_efloatbuf = NULL; /* reinits on demand */
PL_efloatsize = 0; /* reinits on demand */
PL_maxscream = -1; /* reinits on demand */
PL_lastscream = NULL;
- PL_watchaddr = NULL;
- PL_watchok = NULL;
- PL_regdummy = proto_perl->Tregdummy;
+ PL_regdummy = proto_perl->Iregdummy;
PL_colorset = 0; /* reinits PL_colors[] */
/*PL_colors[6] = {0,0,0,0,0,0};*/
- /* RE engine - function pointers */
- PL_regcompp = proto_perl->Tregcompp;
- PL_regexecp = proto_perl->Tregexecp;
- PL_regint_start = proto_perl->Tregint_start;
- PL_regint_string = proto_perl->Tregint_string;
- PL_regfree = proto_perl->Tregfree;
- Zero(&PL_reg_state, 1, struct re_save_state);
- PL_reginterp_cnt = 0;
- PL_regmatch_slab = NULL;
+
/* Pluggable optimizer */
- PL_peepp = proto_perl->Tpeepp;
+ PL_peepp = proto_perl->Ipeepp;
PL_stashcache = newHV();
+ PL_watchaddr = (char **) ptr_table_fetch(PL_ptr_table,
+ proto_perl->Iwatchaddr);
+ PL_watchok = PL_watchaddr ? * PL_watchaddr : NULL;
+ if (PL_debug && PL_watchaddr) {
+ PerlIO_printf(Perl_debug_log,
+ "WATCHING: %"UVxf" cloned as %"UVxf" with value %"UVxf"\n",
+ PTR2UV(proto_perl->Iwatchaddr), PTR2UV(PL_watchaddr),
+ PTR2UV(PL_watchok));
+ }
+
if (!(flags & CLONEf_KEEP_PTR_TABLE)) {
ptr_table_free(PL_ptr_table);
PL_ptr_table = NULL;
ENTER;
SAVETMPS;
PUSHMARK(SP);
- XPUSHs(sv_2mortal(newSVhek(HvNAME_HEK(stash))));
+ mXPUSHs(newSVhek(HvNAME_HEK(stash)));
PUTBACK;
call_sv((SV*)GvCV(cloner), G_DISCARD);
FREETMPS;
Perl_sv_recode_to_utf8(pTHX_ SV *sv, SV *encoding)
{
dVAR;
+
+ PERL_ARGS_ASSERT_SV_RECODE_TO_UTF8;
+
if (SvPOK(sv) && !SvUTF8(sv) && !IN_BYTES && SvROK(encoding)) {
SV *uni;
STRLEN len;
{
dVAR;
bool ret = FALSE;
+
+ PERL_ARGS_ASSERT_SV_CAT_DECODE;
+
if (SvPOK(ssv) && SvPOK(dsv) && SvROK(encoding) && offset) {
SV *offsv;
dSP;
XPUSHs(encoding);
XPUSHs(dsv);
XPUSHs(ssv);
- XPUSHs(offsv = sv_2mortal(newSViv(*offset)));
- XPUSHs(sv_2mortal(newSVpvn(tstr, tlen)));
+ offsv = newSViv(*offset);
+ mXPUSHs(offsv);
+ mXPUSHp(tstr, tlen);
PUTBACK;
call_method("cat_decode", G_SCALAR);
SPAGAIN;
register HE **array;
I32 i;
+ PERL_ARGS_ASSERT_FIND_HASH_SUBSCRIPT;
+
if (!hv || SvMAGICAL(hv) || !HvARRAY(hv) ||
(HvTOTALKEYS(hv) > FUV_MAX_SEARCH_SIZE))
return NULL;
return NULL;
if (HeKLEN(entry) == HEf_SVKEY)
return sv_mortalcopy(HeKEY_sv(entry));
- return sv_2mortal(newSVpvn(HeKEY(entry), HeKLEN(entry)));
+ return sv_2mortal(newSVhek(HeKEY_hek(entry)));
}
}
return NULL;
S_find_array_subscript(pTHX_ AV *av, SV* val)
{
dVAR;
- SV** svp;
- I32 i;
+
+ PERL_ARGS_ASSERT_FIND_ARRAY_SUBSCRIPT;
+
if (!av || SvMAGICAL(av) || !AvARRAY(av) ||
(AvFILLp(av) > FUV_MAX_SEARCH_SIZE))
return -1;
- svp = AvARRAY(av);
- for (i=AvFILLp(av); i>=0; i--) {
- if (svp[i] == val && svp[i] != &PL_sv_undef)
- return i;
+ if (val != &PL_sv_undef) {
+ SV ** const svp = AvARRAY(av);
+ I32 i;
+
+ for (i=AvFILLp(av); i>=0; i--)
+ if (svp[i] == val)
+ return i;
}
return -1;
}
}
}
else {
- U32 unused;
- CV * const cv = find_runcv(&unused);
+ CV * const cv = find_runcv(NULL);
SV *sv;
AV *av;
return NULL;
av = (AV*)(*av_fetch(CvPADLIST(cv), 0, FALSE));
sv = *av_fetch(av, targ, FALSE);
- /* SvLEN in a pad name is not to be trusted */
- sv_setpv(name, SvPV_nolen_const(sv));
+ sv_setpvn(name, SvPV_nolen_const(sv), SvCUR(sv));
}
if (subscript_type == FUV_SUBSCRIPT_HASH) {
subscript_type = FUV_SUBSCRIPT_HASH;
}
else {
- index = S_find_array_subscript(aTHX_ (AV*)sv, uninit_sv);
+ index = find_array_subscript((AV*)sv, uninit_sv);
if (index >= 0)
subscript_type = FUV_SUBSCRIPT_ARRAY;
}
case OP_PRTF:
case OP_PRINT:
+ case OP_SAY:
/* skip filehandle as it can't produce 'undef' warning */
o = cUNOPx(obase)->op_first;
if ((obase->op_flags & OPf_STACKED) && o->op_type == OP_PUSHMARK)
goto do_op2;
+ case OP_ENTEREVAL: /* could be eval $undef or $x='$undef'; eval $x */
case OP_RV2SV:
case OP_CUSTOM:
- case OP_ENTERSUB:
match = 1; /* XS or custom code could trigger random warnings */
goto do_op;
+ case OP_ENTERSUB:
+ case OP_GOTO:
+ /* XXX tmp hack: these two may call an XS sub, and currently
+ XS subs don't have a SUB entry on the context stack, so CV and
+ pad determination goes wrong, and BAD things happen. So, just
+ don't try to determine the value under those circumstances.
+ Need a better fix at dome point. DAPM 11/2007 */
+ break;
+
+ case OP_POS:
+ /* def-ness of rval pos() is independent of the def-ness of its arg */
+ if ( !(obase->op_flags & OPf_MOD))
+ break;
+
case OP_SCHOMP:
case OP_CHOMP:
if (SvROK(PL_rs) && uninit_sv == SvRV(PL_rs))
- return sv_2mortal(newSVpvs("${$/}"));
+ return newSVpvs_flags("${$/}", SVs_TEMP);
/*FALLTHROUGH*/
default:
* or are optimized away, then it's unambiguous */
o2 = NULL;
for (kid=o; kid; kid = kid->op_sibling) {
- SV *sv;
- if (kid &&
- ( (kid->op_type == OP_CONST && (sv = cSVOPx_sv(kid))
- && SvOK(sv))
- || (kid->op_type == OP_NULL && ! (kid->op_flags & OPf_KIDS))
- || (kid->op_type == OP_PUSHMARK)
+ if (kid) {
+ const OPCODE type = kid->op_type;
+ if ( (type == OP_CONST && SvOK(cSVOPx_sv(kid)))
+ || (type == OP_NULL && ! (kid->op_flags & OPf_KIDS))
+ || (type == OP_PUSHMARK)
)
- )
continue;
+ }
if (o2) { /* more than one found */
o2 = NULL;
break;