}
STATIC void
-S_forget_pmop(pTHX_ PMOP *const o
- )
+S_forget_pmop(pTHX_ PMOP *const o)
{
HV * const pmstash = PmopSTASH(o);
}
else if ( topop->op_type == OP_CONCAT
&& (topop->op_flags & OPf_STACKED)
- && (cUNOPo->op_first->op_flags & OPf_MOD)
&& (!(topop->op_private & OPpCONCAT_NESTED))
)
{
OP *prev;
/* set prev to the sibling *before* the arg to be cut out,
- * e.g.:
+ * e.g. when cutting EXPR:
*
* |
- * kid= CONST
+ * kid= CONCAT
* |
- * prev= CONST -- EXPR
+ * prev= CONCAT -- EXPR
* |
*/
if (argp == args && kid->op_type != OP_CONCAT) {
- /* in e.g. '$x . = f(1)' there's no RHS concat tree
+ /* in e.g. '$x .= f(1)' there's no RHS concat tree
* so the expression to be cut isn't kid->op_last but
* kid itself */
OP *o1, *o2;
case OP_RV2HV:
if (type == OP_REFGEN && o->op_flags & OPf_PARENS) {
PL_modcount = RETURN_UNLIMITED_NUMBER;
- return o; /* Treat \(@foo) like ordinary list. */
+ /* Treat \(@foo) like ordinary list, but still mark it as modi-
+ fiable since some contexts need to know. */
+ o->op_flags |= OPf_MOD;
+ return o;
}
/* FALLTHROUGH */
case OP_RV2GV:
case OP_PADHV:
PL_modcount = RETURN_UNLIMITED_NUMBER;
if (type == OP_REFGEN && o->op_flags & OPf_PARENS)
- return o; /* Treat \(@foo) like ordinary list. */
+ {
+ /* Treat \(@foo) like ordinary list, but still mark it as modi-
+ fiable since some contexts need to know. */
+ o->op_flags |= OPf_MOD;
+ return o;
+ }
if (scalar_mod_type(o, type))
goto nomod;
if ((o->op_flags & OPf_WANT) != OPf_WANT_SCALAR
STRLEN rlen;
const U8 *t = (U8*)SvPV_const(tstr, tlen);
const U8 *r = (U8*)SvPV_const(rstr, rlen);
- I32 i;
- I32 j;
- I32 grows = 0;
- short *tbl;
-
- const I32 complement = o->op_private & OPpTRANS_COMPLEMENT;
- const I32 squash = o->op_private & OPpTRANS_SQUASH;
- I32 del = o->op_private & OPpTRANS_DELETE;
+ Size_t i, j;
+ bool grows = FALSE;
+ OPtrans_map *tbl;
+ SSize_t struct_size; /* malloced size of table struct */
+
+ const bool complement = cBOOL(o->op_private & OPpTRANS_COMPLEMENT);
+ const bool squash = cBOOL(o->op_private & OPpTRANS_SQUASH);
+ const bool del = cBOOL(o->op_private & OPpTRANS_DELETE);
SV* swash;
PERL_ARGS_ASSERT_PMTRANS;
none = ++max;
if (del)
- del = ++max;
+ ++max;
if (max > 0xffff)
bits = 32;
goto warnins;
}
- /* Non-utf8 case: set o->op_pv to point to a simple 256-entry lookup
+ /* Non-utf8 case: set o->op_pv to point to a simple 256+ entry lookup
* table. Entries with the value -1 indicate chars not to be
* translated, while -2 indicates a search char without a
* corresponding replacement char under /d.
*
- * With /c, an extra length arg is stored at the end of the table to
- * indicate the number of chars in the replacement string, plus any
- * excess replacement chars not paired with search chars. The extra
- * chars are needed for utf8 strings. For example,
- * tr/\x00-\xfd/abcd/c is logically equivalent to
- * tr/\xfe\xff\x{100}\x{101}.../abcdddd.../, so the c,d chars need to
- * be kept even though they aren't paired with any chars in the table
- * (which represents chars \x00-\xff). Even without excess chars, the
- * last replacement char needs to be kept.
+ * Normally, the table has 256 slots. However, in the presence of
+ * /c, the search charlist has an implicit \x{100}-\x{7fffffff}
+ * added, and if there are enough replacement chars to start pairing
+ * with the \x{100},... search chars, then a larger (> 256) table
+ * is allocated.
+ *
+ * In addition, regardless of whether under /c, an extra slot at the
+ * end is used to store the final repeating char, or -3 under an empty
+ * replacement list, or -2 under /d; which makes the runtime code
+ * easier.
*
* The toker will have already expanded char ranges in t and r.
*/
- tbl = (short*)PerlMemShared_calloc(
- /* one slot for 'extra len' count and one slot
- * for possible storing of last replacement char */
- (complement && !del) ? 258 : 256,
- sizeof(short));
+ /* Initially allocate 257-slot table: 256 for basic (non /c) usage,
+ * plus final slot for repeat/-2/-3. Later we realloc if excess > * 0.
+ * The OPtrans_map struct already contains one slot; hence the -1.
+ */
+ struct_size = sizeof(OPtrans_map) + (256 - 1 + 1)*sizeof(short);
+ tbl = (OPtrans_map*)PerlMemShared_calloc(struct_size, 1);
+ tbl->size = 256;
cPVOPo->op_pv = (char*)tbl;
if (complement) {
+ Size_t excess;
+
/* in this branch, j is a count of 'consumed' (i.e. paired off
* with a search char) replacement chars (so j <= rlen always)
*/
- for (i = 0; i < (I32)tlen; i++)
- tbl[t[i]] = -1;
+ for (i = 0; i < tlen; i++)
+ tbl->map[t[i]] = -1;
+
for (i = 0, j = 0; i < 256; i++) {
- if (!tbl[i]) {
- if (j == (I32)rlen) {
+ if (!tbl->map[i]) {
+ if (j == rlen) {
if (del)
- tbl[i] = -2;
+ tbl->map[i] = -2;
else if (rlen)
- tbl[i] = r[j-1];
+ tbl->map[i] = r[j-1];
else
- tbl[i] = (short)i;
+ tbl->map[i] = (short)i;
}
else {
- if (UVCHR_IS_INVARIANT(i) && ! UVCHR_IS_INVARIANT(r[j]))
- grows = 1;
- tbl[i] = r[j++];
+ tbl->map[i] = r[j++];
}
+ if ( tbl->map[i] >= 0
+ && UVCHR_IS_INVARIANT((UV)i)
+ && !UVCHR_IS_INVARIANT((UV)(tbl->map[i]))
+ )
+ grows = TRUE;
}
}
- assert(j <= (I32)rlen);
- if (!del) {
- if (!rlen) {
- /* empty replacement list */
- j = rlen;
- if (!squash)
- o->op_private |= OPpTRANS_IDENTICAL;
- }
- else if (j == (I32)rlen)
- /* no more replacement chars than search chars */
- j = rlen - 1;
- else {
- /* more replacement chars than search chars */
- tbl =
- (short *)
- PerlMemShared_realloc(tbl,
- (0x101+rlen-j) * sizeof(short));
- cPVOPo->op_pv = (char*)tbl;
- }
- tbl[0x100] = (short)(rlen - j);
- /* store any excess replacement chars at end of main table */
- for (i=0; i < (I32)rlen - j; i++)
- tbl[0x101+i] = r[j+i];
- }
+ ASSUME(j <= rlen);
+ excess = rlen - j;
+
+ if (excess) {
+ /* More replacement chars than search chars:
+ * store excess replacement chars at end of main table.
+ */
+
+ struct_size += excess;
+ tbl = (OPtrans_map*)PerlMemShared_realloc(tbl,
+ struct_size + excess * sizeof(short));
+ tbl->size += excess;
+ cPVOPo->op_pv = (char*)tbl;
+
+ for (i = 0; i < excess; i++)
+ tbl->map[i + 256] = r[j+i];
+ }
+ else {
+ /* no more replacement chars than search chars */
+ if (!rlen && !del && !squash)
+ o->op_private |= OPpTRANS_IDENTICAL;
+ }
+
+ tbl->map[tbl->size] = del ? -2 : rlen ? r[rlen - 1] : -3;
}
else {
if (!rlen && !del) {
else if (!squash && rlen == tlen && memEQ((char*)t, (char*)r, tlen)) {
o->op_private |= OPpTRANS_IDENTICAL;
}
+
for (i = 0; i < 256; i++)
- tbl[i] = -1;
- for (i = 0, j = 0; i < (I32)tlen; i++,j++) {
- if (j >= (I32)rlen) {
+ tbl->map[i] = -1;
+ for (i = 0, j = 0; i < tlen; i++,j++) {
+ if (j >= rlen) {
if (del) {
- if (tbl[t[i]] == -1)
- tbl[t[i]] = -2;
+ if (tbl->map[t[i]] == -1)
+ tbl->map[t[i]] = -2;
continue;
}
--j;
}
- if (tbl[t[i]] == -1) {
+ if (tbl->map[t[i]] == -1) {
if ( UVCHR_IS_INVARIANT(t[i])
&& ! UVCHR_IS_INVARIANT(r[j]))
- grows = 1;
- tbl[t[i]] = r[j];
+ grows = TRUE;
+ tbl->map[t[i]] = r[j];
}
}
+ tbl->map[tbl->size] = del ? -1 : rlen ? -1 : -3;
}
/* both non-utf8 and utf8 code paths end up here */
op_null(scope);
}
- if (is_compiletime)
- /* runtime finalizes as part of finalizing whole tree */
- optimize_optree(o);
+ /* XXX optimize_optree() must be called on o before
+ * CALL_PEEP(), as currently S_maybe_multiconcat() can't
+ * currently cope with a peephole-optimised optree.
+ * Calling optimize_optree() here ensures that condition
+ * is met, but may mean optimize_optree() is applied
+ * to the same optree later (where hopefully it won't do any
+ * harm as it can't convert an op to multiconcat if it's
+ * already been converted */
+ optimize_optree(o);
/* have to peep the DOs individually as we've removed it from
* the op_next chain */
&& o2->op_private & OPpLVAL_INTRO
&& !(o2->op_private & OPpPAD_STATE))
{
- Perl_ck_warner_d(aTHX_ packWARN(WARN_DEPRECATED),
- "Deprecated use of my() in false conditional. "
- "This will be a fatal error in Perl 5.30");
+ Perl_croak(aTHX_ "This use of my() in false conditional is "
+ "no longer allowed");
}
*otherp = NULL;
case OP_FLOP:
return TRUE;
+
+ case OP_INDEX:
+ case OP_RINDEX:
+ /* optimised-away (index() != -1) or similar comparison */
+ if (o->op_private & OPpTRUEBOOL)
+ return TRUE;
+ return FALSE;
case OP_CONST:
/* Detect comparisons that have been optimized away */
return TRUE;
else
return FALSE;
-
/* FALLTHROUGH */
default:
return FALSE;
Also, we may be called from load_module at run time, so
PL_curstash (which sets CvSTASH) may not point to the stash the
sub is stored in. */
+ /* XXX This optimization is currently disabled for packages other
+ than main, since there was too much CPAN breakage. */
const I32 flags =
ec ? GV_NOADD_NOINIT
: (IN_PERL_RUNTIME && PL_curstash != CopSTASH(PL_curcop))
+ || PL_curstash != PL_defstash
|| memchr(name, ':', namlen) || memchr(name, '\'', namlen)
? gv_fetch_flags
: GV_ADDMULTI | GV_NOINIT | GV_NOTQUAL;
/* at this point we're looking for an OP_AELEM, OP_HELEM,
* OP_EXISTS or OP_DELETE */
- /* if something like arybase (a.k.a $[ ) is in scope,
+ /* if a custom array/hash access checker is in scope,
* abandon optimisation attempt */
if ( (o->op_type == OP_AELEM || o->op_type == OP_HELEM)
&& PL_check[o->op_type] != Perl_ck_null)