static const char array_passed_to_stat[] = "Array passed to stat will be coerced to a scalar";
-/* Used to avoid recursion through the op tree in scalarvoid() and
- op_free()
-*/
-
-#define DEFERRED_OP_STEP 100
-#define DEFER_OP(o) \
- STMT_START { \
- if (UNLIKELY(defer_ix == (defer_stack_alloc-1))) { \
- defer_stack_alloc += DEFERRED_OP_STEP; \
- assert(defer_stack_alloc > 0); \
- Renew(defer_stack, defer_stack_alloc, OP *); \
- } \
- defer_stack[++defer_ix] = o; \
- } STMT_END
-
-#define POP_DEFERRED_OP() (defer_ix >= 0 ? defer_stack[defer_ix--] : (OP *)NULL)
-
/* remove any leading "empty" ops from the op_next chain whose first
* node's address is stored in op_p. Store the updated address of the
* first node in op_p.
#define SIZE_TO_PSIZE(x) (((x) + sizeof(I32 *) - 1)/sizeof(I32 *))
#define DIFF(o,p) ((size_t)((I32 **)(p) - (I32**)(o)))
+/* malloc a new op slab (suitable for attaching to PL_compcv) */
+
static OPSLAB *
S_new_slab(pTHX_ size_t sz)
{
PerlIO_printf(Perl_debug_log, "%s", SvPVx_nolen(Perl_mess args)) \
)
+/* Returns a sz-sized block of memory (suitable for holding an op) from
+ * a free slot in the chain of op slabs attached to PL_compcv.
+ * Allocates a new slab if necessary.
+ * if PL_compcv isn't compiling, malloc() instead.
+ */
+
void *
Perl_Slab_Alloc(pTHX_ size_t sz)
{
DEBUG_S_warn((aTHX_ "allocating op at %p, slab %p", (void*)o, (void*)slab));
gotit:
-#ifdef PERL_OP_PARENT
/* moresib == 0, op_sibling == 0 implies a solitary unattached op */
assert(!o->op_moresib);
assert(!o->op_sibparent);
-#endif
return (void *)o;
}
}
#endif
+
+/* Return the block of memory used by an op to the free list of
+ * the OP slab associated with that op.
+ */
+
void
Perl_Slab_Free(pTHX_ void *op)
{
if (havepad) LEAVE;
}
+/* Free a chain of OP slabs. Should only be called after all ops contained
+ * in it have been freed. At this point, its reference count should be 1,
+ * because OpslabREFCNT_dec() skips doing rc-- when it detects that rc == 1,
+ * and just directly calls opslab_free().
+ * (Note that the reference count which PL_compcv held on the slab should
+ * have been removed once compilation of the sub was complete).
+ *
+ *
+ */
+
void
Perl_opslab_free(pTHX_ OPSLAB *slab)
{
} while (slab);
}
+/* like opslab_free(), but first calls op_free() on any ops in the slab
+ * not marked as OP_FREED
+ */
+
void
Perl_opslab_force_free(pTHX_ OPSLAB *slab)
{
/* Destructor */
/*
-=for apidoc Am|void|op_free|OP *o
+=for apidoc op_free
-Free an op. Only use this when an op is no longer linked to from any
-optree.
+Free an op and its children. Only use this when an op is no longer linked
+to from any optree.
=cut
*/
{
dVAR;
OPCODE type;
- SSize_t defer_ix = -1;
- SSize_t defer_stack_alloc = 0;
- OP **defer_stack = NULL;
+ OP *top_op = o;
+ OP *next_op = o;
+ bool went_up = FALSE; /* whether we reached the current node by
+ following the parent pointer from a child, and
+ so have already seen this node */
- do {
+ if (!o || o->op_type == OP_FREED)
+ return;
+
+ if (o->op_private & OPpREFCOUNTED) {
+ /* if base of tree is refcounted, just decrement */
+ switch (o->op_type) {
+ case OP_LEAVESUB:
+ case OP_LEAVESUBLV:
+ case OP_LEAVEEVAL:
+ case OP_LEAVE:
+ case OP_SCOPE:
+ case OP_LEAVEWRITE:
+ {
+ PADOFFSET refcnt;
+ OP_REFCNT_LOCK;
+ refcnt = OpREFCNT_dec(o);
+ OP_REFCNT_UNLOCK;
+ if (refcnt) {
+ /* Need to find and remove any pattern match ops from
+ * the list we maintain for reset(). */
+ find_and_forget_pmops(o);
+ return;
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ while (next_op) {
+ o = next_op;
+
+ /* free child ops before ourself, (then free ourself "on the
+ * way back up") */
+
+ if (!went_up && o->op_flags & OPf_KIDS) {
+ next_op = cUNOPo->op_first;
+ continue;
+ }
+
+ /* find the next node to visit, *then* free the current node
+ * (can't rely on o->op_* fields being valid after o has been
+ * freed) */
+
+ /* The next node to visit will be either the sibling, or the
+ * parent if no siblings left, or NULL if we've worked our way
+ * back up to the top node in the tree */
+ next_op = (o == top_op) ? NULL : o->op_sibparent;
+ went_up = cBOOL(!OpHAS_SIBLING(o)); /* parents are already visited */
+
+ /* Now process the current node */
/* Though ops may be freed twice, freeing the op after its slab is a
big no-no. */
- assert(!o || !o->op_slabbed || OpSLAB(o)->opslab_refcnt != ~(size_t)0);
+ assert(!o->op_slabbed || OpSLAB(o)->opslab_refcnt != ~(size_t)0);
/* During the forced freeing of ops after compilation failure, kidops
may be freed before their parents. */
if (!o || o->op_type == OP_FREED)
* we can't spot faults in the main code, only
* evaled/required code */
#ifdef DEBUGGING
- if ( o->op_ppaddr == PL_ppaddr[o->op_type]
+ if ( o->op_ppaddr == PL_ppaddr[type]
&& PL_parser
&& !PL_parser->error_count)
{
}
#endif
- if (o->op_private & OPpREFCOUNTED) {
- switch (type) {
- case OP_LEAVESUB:
- case OP_LEAVESUBLV:
- case OP_LEAVEEVAL:
- case OP_LEAVE:
- case OP_SCOPE:
- case OP_LEAVEWRITE:
- {
- PADOFFSET refcnt;
- OP_REFCNT_LOCK;
- refcnt = OpREFCNT_dec(o);
- OP_REFCNT_UNLOCK;
- if (refcnt) {
- /* Need to find and remove any pattern match ops from the list
- we maintain for reset(). */
- find_and_forget_pmops(o);
- continue;
- }
- }
- break;
- default:
- break;
- }
- }
/* Call the op_free hook if it has been set. Do it now so that it's called
* at the right time for refcounted ops, but still before all of the kids
* are freed. */
CALL_OPFREEHOOK(o);
- if (o->op_flags & OPf_KIDS) {
- OP *kid, *nextkid;
- for (kid = cUNOPo->op_first; kid; kid = nextkid) {
- nextkid = OpSIBLING(kid); /* Get before next freeing kid */
- if (!kid || kid->op_type == OP_FREED)
- /* During the forced freeing of ops after
- compilation failure, kidops may be freed before
- their parents. */
- continue;
- if (!(kid->op_flags & OPf_KIDS))
- /* If it has no kids, just free it now */
- op_free(kid);
- else
- DEFER_OP(kid);
- }
- }
if (type == OP_NULL)
type = (OPCODE)o->op_targ;
FreeOp(o);
if (PL_op == o)
PL_op = NULL;
- } while ( (o = POP_DEFERRED_OP()) );
-
- Safefree(defer_stack);
+ }
}
+
/* S_op_clear_gv(): free a GV attached to an OP */
STATIC
o->op_targ = 0;
break;
default:
- if (!(o->op_flags & OPf_REF)
- || (PL_check[o->op_type] != Perl_ck_ftst))
+ if (!(o->op_flags & OPf_REF) || !OP_IS_STAT(o->op_type))
break;
/* FALLTHROUGH */
case OP_GVSV:
}
STATIC void
-S_forget_pmop(pTHX_ PMOP *const o
- )
+S_forget_pmop(pTHX_ PMOP *const o)
{
HV * const pmstash = PmopSTASH(o);
}
/*
-=for apidoc Am|void|op_null|OP *o
+=for apidoc op_null
Neutralizes an op when it is no longer needed, but is still linked to from
other ops.
OpMAYBESIB_set(start, insert, NULL);
}
else {
- if (!parent)
- goto no_parent;
+ assert(parent);
cLISTOPx(parent)->op_first = insert;
if (insert)
parent->op_flags |= OPf_KIDS;
Perl_croak_nocontext("panic: op_sibling_splice(): NULL parent");
}
-
-#ifdef PERL_OP_PARENT
-
/*
=for apidoc op_parent
Returns the parent OP of C<o>, if it has a parent. Returns C<NULL> otherwise.
-This function is only available on perls built with C<-DPERL_OP_PARENT>.
=cut
*/
return o->op_sibparent;
}
-#endif
-
-
/* replace the sibling following start with a new UNOP, which becomes
* the parent of the original sibling; e.g.
*
OpTYPE_set(logop, type);
logop->op_first = first;
logop->op_other = other;
- logop->op_flags = OPf_KIDS;
+ if (first)
+ logop->op_flags = OPf_KIDS;
while (kid && OpHAS_SIBLING(kid))
kid = OpSIBLING(kid);
if (kid)
/* Contextualizers */
/*
-=for apidoc Am|OP *|op_contextualize|OP *o|I32 context
+=for apidoc op_contextualize
Applies a syntactic context to an op tree representing an expression.
C<o> is the op tree, and C<context> must be C<G_SCALAR>, C<G_ARRAY>,
/*
-=for apidoc Am|OP*|op_linklist|OP *o
+=for apidoc op_linklist
This function is the implementation of the L</LINKLIST> macro. It should
not be called directly.
SVfARG(name), lbrack, SVfARG(keysv), rbrack);
}
+
+
+/* apply scalar context to the o subtree */
+
OP *
Perl_scalar(pTHX_ OP *o)
{
- OP *kid;
+ OP * top_op = o;
- /* assumes no premature commitment */
- if (!o || (PL_parser && PL_parser->error_count)
- || (o->op_flags & OPf_WANT)
- || o->op_type == OP_RETURN)
- {
- return o;
- }
+ while (1) {
+ OP *next_kid = NULL; /* what op (if any) to process next */
+ OP *kid;
- o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_SCALAR;
+ /* assumes no premature commitment */
+ if (!o || (PL_parser && PL_parser->error_count)
+ || (o->op_flags & OPf_WANT)
+ || o->op_type == OP_RETURN)
+ {
+ goto do_next;
+ }
- switch (o->op_type) {
- case OP_REPEAT:
- scalar(cBINOPo->op_first);
- if (o->op_private & OPpREPEAT_DOLIST) {
- kid = cLISTOPx(cUNOPo->op_first)->op_first;
- assert(kid->op_type == OP_PUSHMARK);
- if (OpHAS_SIBLING(kid) && !OpHAS_SIBLING(OpSIBLING(kid))) {
- op_null(cLISTOPx(cUNOPo->op_first)->op_first);
- o->op_private &=~ OPpREPEAT_DOLIST;
- }
- }
- break;
- case OP_OR:
- case OP_AND:
- case OP_COND_EXPR:
- for (kid = OpSIBLING(cUNOPo->op_first); kid; kid = OpSIBLING(kid))
- scalar(kid);
- break;
- /* FALLTHROUGH */
- case OP_SPLIT:
- case OP_MATCH:
- case OP_QR:
- case OP_SUBST:
- case OP_NULL:
- default:
- if (o->op_flags & OPf_KIDS) {
- for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid))
- scalar(kid);
- }
- break;
- case OP_LEAVE:
- case OP_LEAVETRY:
- kid = cLISTOPo->op_first;
- scalar(kid);
- kid = OpSIBLING(kid);
- do_kids:
- while (kid) {
- OP *sib = OpSIBLING(kid);
- if (sib && kid->op_type != OP_LEAVEWHERESO
- && ( OpHAS_SIBLING(sib) || sib->op_type != OP_NULL
- || ( sib->op_targ != OP_NEXTSTATE
- && sib->op_targ != OP_DBSTATE )))
- scalarvoid(kid);
- else
- scalar(kid);
- kid = sib;
- }
- PL_curcop = &PL_compiling;
- break;
- case OP_SCOPE:
- case OP_LINESEQ:
- case OP_LIST:
- kid = cLISTOPo->op_first;
- goto do_kids;
- case OP_SORT:
- Perl_ck_warner(aTHX_ packWARN(WARN_VOID), "Useless use of sort in scalar context");
- break;
- case OP_KVHSLICE:
- case OP_KVASLICE:
- {
- /* Warn about scalar context */
- const char lbrack = o->op_type == OP_KVHSLICE ? '{' : '[';
- const char rbrack = o->op_type == OP_KVHSLICE ? '}' : ']';
- SV *name;
- SV *keysv;
- const char *key = NULL;
+ o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_SCALAR;
- /* This warning can be nonsensical when there is a syntax error. */
- if (PL_parser && PL_parser->error_count)
- break;
+ switch (o->op_type) {
+ case OP_REPEAT:
+ scalar(cBINOPo->op_first);
+ /* convert what initially looked like a list repeat into a
+ * scalar repeat, e.g. $s = (1) x $n
+ */
+ if (o->op_private & OPpREPEAT_DOLIST) {
+ kid = cLISTOPx(cUNOPo->op_first)->op_first;
+ assert(kid->op_type == OP_PUSHMARK);
+ if (OpHAS_SIBLING(kid) && !OpHAS_SIBLING(OpSIBLING(kid))) {
+ op_null(cLISTOPx(cUNOPo->op_first)->op_first);
+ o->op_private &=~ OPpREPEAT_DOLIST;
+ }
+ }
+ break;
+
+ case OP_OR:
+ case OP_AND:
+ case OP_COND_EXPR:
+ /* impose scalar context on everything except the condition */
+ next_kid = OpSIBLING(cUNOPo->op_first);
+ break;
- if (!ckWARN(WARN_SYNTAX)) break;
+ default:
+ if (o->op_flags & OPf_KIDS)
+ next_kid = cUNOPo->op_first; /* do all kids */
+ break;
- kid = cLISTOPo->op_first;
- kid = OpSIBLING(kid); /* get past pushmark */
- assert(OpSIBLING(kid));
- name = S_op_varname(aTHX_ OpSIBLING(kid));
- if (!name) /* XS module fiddling with the op tree */
- break;
- S_op_pretty(aTHX_ kid, &keysv, &key);
- assert(SvPOK(name));
- sv_chop(name,SvPVX(name)+1);
- if (key)
- /* diag_listed_as: %%s[%s] in scalar context better written as $%s[%s] */
- Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
- "%%%" SVf "%c%s%c in scalar context better written "
- "as $%" SVf "%c%s%c",
- SVfARG(name), lbrack, key, rbrack, SVfARG(name),
- lbrack, key, rbrack);
- else
- /* diag_listed_as: %%s[%s] in scalar context better written as $%s[%s] */
- Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
- "%%%" SVf "%c%" SVf "%c in scalar context better "
- "written as $%" SVf "%c%" SVf "%c",
- SVfARG(name), lbrack, SVfARG(keysv), rbrack,
- SVfARG(name), lbrack, SVfARG(keysv), rbrack);
- }
- }
- return o;
+ /* the children of these ops are usually a list of statements,
+ * except the leaves, whose first child is a corresponding enter
+ */
+ case OP_SCOPE:
+ case OP_LINESEQ:
+ case OP_LIST:
+ kid = cLISTOPo->op_first;
+ goto do_kids;
+ case OP_LEAVE:
+ case OP_LEAVETRY:
+ kid = cLISTOPo->op_first;
+ scalar(kid);
+ kid = OpSIBLING(kid);
+ do_kids:
+ while (kid) {
+ OP *sib = OpSIBLING(kid);
+ /* Apply void context to all kids except the last, which
+ * is scalar (ignoring a trailing ex-nextstate in determining
+ * if it's the last kid). E.g.
+ * $scalar = do { void; void; scalar }
+ * Except that 'when's are always scalar, e.g.
+ * $scalar = do { given(..) {
+ * when (..) { scalar }
+ * when (..) { scalar }
+ * ...
+ * }}
+ */
+ if (!sib
+ || ( !OpHAS_SIBLING(sib)
+ && sib->op_type == OP_NULL
+ && ( sib->op_targ == OP_NEXTSTATE
+ || sib->op_targ == OP_DBSTATE )
+ )
+ )
+ {
+ /* tail call optimise calling scalar() on the last kid */
+ next_kid = kid;
+ goto do_next;
+ }
+ else if (kid->op_type == OP_LEAVEWHEN)
+ scalar(kid);
+ else
+ scalarvoid(kid);
+ kid = sib;
+ }
+ NOT_REACHED; /* NOTREACHED */
+ break;
+
+ case OP_SORT:
+ Perl_ck_warner(aTHX_ packWARN(WARN_VOID), "Useless use of sort in scalar context");
+ break;
+
+ case OP_KVHSLICE:
+ case OP_KVASLICE:
+ {
+ /* Warn about scalar context */
+ const char lbrack = o->op_type == OP_KVHSLICE ? '{' : '[';
+ const char rbrack = o->op_type == OP_KVHSLICE ? '}' : ']';
+ SV *name;
+ SV *keysv;
+ const char *key = NULL;
+
+ /* This warning can be nonsensical when there is a syntax error. */
+ if (PL_parser && PL_parser->error_count)
+ break;
+
+ if (!ckWARN(WARN_SYNTAX)) break;
+
+ kid = cLISTOPo->op_first;
+ kid = OpSIBLING(kid); /* get past pushmark */
+ assert(OpSIBLING(kid));
+ name = S_op_varname(aTHX_ OpSIBLING(kid));
+ if (!name) /* XS module fiddling with the op tree */
+ break;
+ S_op_pretty(aTHX_ kid, &keysv, &key);
+ assert(SvPOK(name));
+ sv_chop(name,SvPVX(name)+1);
+ if (key)
+ /* diag_listed_as: %%s[%s] in scalar context better written as $%s[%s] */
+ Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+ "%%%" SVf "%c%s%c in scalar context better written "
+ "as $%" SVf "%c%s%c",
+ SVfARG(name), lbrack, key, rbrack, SVfARG(name),
+ lbrack, key, rbrack);
+ else
+ /* diag_listed_as: %%s[%s] in scalar context better written as $%s[%s] */
+ Perl_warner(aTHX_ packWARN(WARN_SYNTAX),
+ "%%%" SVf "%c%" SVf "%c in scalar context better "
+ "written as $%" SVf "%c%" SVf "%c",
+ SVfARG(name), lbrack, SVfARG(keysv), rbrack,
+ SVfARG(name), lbrack, SVfARG(keysv), rbrack);
+ }
+ } /* switch */
+
+ /* If next_kid is set, someone in the code above wanted us to process
+ * that kid and all its remaining siblings. Otherwise, work our way
+ * back up the tree */
+ do_next:
+ while (!next_kid) {
+ if (o == top_op)
+ return top_op; /* at top; no parents/siblings to try */
+ if (OpHAS_SIBLING(o))
+ next_kid = o->op_sibparent;
+ else {
+ o = o->op_sibparent; /*try parent's next sibling */
+ switch (o->op_type) {
+ case OP_SCOPE:
+ case OP_LINESEQ:
+ case OP_LIST:
+ case OP_LEAVE:
+ case OP_LEAVETRY:
+ /* should really restore PL_curcop to its old value, but
+ * setting it to PL_compiling is better than do nothing */
+ PL_curcop = &PL_compiling;
+ }
+ }
+ }
+ o = next_kid;
+ } /* while */
}
+
+/* apply void context to the optree arg */
+
OP *
Perl_scalarvoid(pTHX_ OP *arg)
{
dVAR;
OP *kid;
SV* sv;
- SSize_t defer_stack_alloc = 0;
- SSize_t defer_ix = -1;
- OP **defer_stack = NULL;
OP *o = arg;
PERL_ARGS_ASSERT_SCALARVOID;
- do {
+ while (1) {
U8 want;
SV *useless_sv = NULL;
const char* useless = NULL;
+ OP * next_kid = NULL;
if (o->op_type == OP_NEXTSTATE
|| o->op_type == OP_DBSTATE
want = o->op_flags & OPf_WANT;
if ((want && want != OPf_WANT_SCALAR)
|| (PL_parser && PL_parser->error_count)
- || o->op_type == OP_RETURN || o->op_type == OP_REQUIRE || o->op_type == OP_LEAVEWHERESO)
+ || o->op_type == OP_RETURN || o->op_type == OP_REQUIRE || o->op_type == OP_LEAVEWHEN)
{
- continue;
+ goto get_next_op;
}
if ((o->op_private & OPpTARGET_MY)
{
/* newASSIGNOP has already applied scalar context, which we
leave, as if this op is inside SASSIGN. */
- continue;
+ goto get_next_op;
}
o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_VOID;
if (o->op_type == OP_REPEAT)
scalar(cBINOPo->op_first);
goto func_ops;
+ case OP_CONCAT:
+ if ((o->op_flags & OPf_STACKED) &&
+ !(o->op_private & OPpCONCAT_NESTED))
+ break;
+ goto func_ops;
case OP_SUBSTR:
if (o->op_private == 4)
break;
case OP_DOR:
case OP_COND_EXPR:
case OP_ENTERGIVEN:
- case OP_ENTERWHERESO:
- for (kid = OpSIBLING(cUNOPo->op_first); kid; kid = OpSIBLING(kid))
- if (!(kid->op_flags & OPf_KIDS))
- scalarvoid(kid);
- else
- DEFER_OP(kid);
+ case OP_ENTERWHEN:
+ next_kid = OpSIBLING(cUNOPo->op_first);
break;
case OP_NULL:
case OP_LEAVETRY:
case OP_LEAVELOOP:
case OP_LINESEQ:
- case OP_LEAVEWHERESO:
+ case OP_LEAVEGIVEN:
+ case OP_LEAVEWHEN:
kids:
- for (kid = cLISTOPo->op_first; kid; kid = OpSIBLING(kid))
- if (!(kid->op_flags & OPf_KIDS))
- scalarvoid(kid);
- else
- DEFER_OP(kid);
+ next_kid = cLISTOPo->op_first;
break;
case OP_LIST:
/* If the first kid after pushmark is something that the padrange
"Useless use of %s in void context",
useless);
}
- } while ( (o = POP_DEFERRED_OP()) );
- Safefree(defer_stack);
+ get_next_op:
+ /* if a kid hasn't been nominated to process, continue with the
+ * next sibling, or if no siblings left, go back to the parent's
+ * siblings and so on
+ */
+ while (!next_kid) {
+ if (o == arg)
+ return arg; /* at top; no parents/siblings to try */
+ if (OpHAS_SIBLING(o))
+ next_kid = o->op_sibparent;
+ else
+ o = o->op_sibparent; /*try parent's next sibling */
+ }
+ o = next_kid;
+ }
return arg;
}
+
static OP *
S_listkids(pTHX_ OP *o)
{
return o;
}
+
+/* apply list context to the o subtree */
+
OP *
Perl_list(pTHX_ OP *o)
{
- OP *kid;
+ OP * top_op = o;
- /* assumes no premature commitment */
- if (!o || (o->op_flags & OPf_WANT)
- || (PL_parser && PL_parser->error_count)
- || o->op_type == OP_RETURN)
- {
- return o;
- }
+ while (1) {
+ OP *next_kid = NULL; /* what op (if any) to process next */
- if ((o->op_private & OPpTARGET_MY)
- && (PL_opargs[o->op_type] & OA_TARGLEX))/* OPp share the meaning */
- {
- return o; /* As if inside SASSIGN */
- }
+ OP *kid;
- o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_LIST;
+ /* assumes no premature commitment */
+ if (!o || (o->op_flags & OPf_WANT)
+ || (PL_parser && PL_parser->error_count)
+ || o->op_type == OP_RETURN)
+ {
+ goto do_next;
+ }
- switch (o->op_type) {
- case OP_FLOP:
- list(cBINOPo->op_first);
- break;
- case OP_REPEAT:
- if (o->op_private & OPpREPEAT_DOLIST
- && !(o->op_flags & OPf_STACKED))
- {
- list(cBINOPo->op_first);
- kid = cBINOPo->op_last;
- if (kid->op_type == OP_CONST && SvIOK(kSVOP_sv)
- && SvIVX(kSVOP_sv) == 1)
- {
- op_null(o); /* repeat */
- op_null(cUNOPx(cBINOPo->op_first)->op_first);/* pushmark */
- /* const (rhs): */
- op_free(op_sibling_splice(o, cBINOPo->op_first, 1, NULL));
- }
- }
- break;
- case OP_OR:
- case OP_AND:
- case OP_COND_EXPR:
- for (kid = OpSIBLING(cUNOPo->op_first); kid; kid = OpSIBLING(kid))
- list(kid);
- break;
- default:
- case OP_MATCH:
- case OP_QR:
- case OP_SUBST:
- case OP_NULL:
- if (!(o->op_flags & OPf_KIDS))
- break;
- if (!o->op_next && cUNOPo->op_first->op_type == OP_FLOP) {
- list(cBINOPo->op_first);
- return gen_constant_list(o);
- }
- listkids(o);
- break;
- case OP_LIST:
- listkids(o);
- if (cLISTOPo->op_first->op_type == OP_PUSHMARK) {
- op_null(cUNOPo->op_first); /* NULL the pushmark */
- op_null(o); /* NULL the list */
- }
- break;
- case OP_LEAVE:
- case OP_LEAVETRY:
- kid = cLISTOPo->op_first;
- list(kid);
- kid = OpSIBLING(kid);
- do_kids:
- while (kid) {
- OP *sib = OpSIBLING(kid);
- if (sib && kid->op_type != OP_LEAVEWHERESO)
- scalarvoid(kid);
- else
- list(kid);
- kid = sib;
- }
- PL_curcop = &PL_compiling;
- break;
- case OP_SCOPE:
- case OP_LINESEQ:
- kid = cLISTOPo->op_first;
- goto do_kids;
- }
- return o;
+ if ((o->op_private & OPpTARGET_MY)
+ && (PL_opargs[o->op_type] & OA_TARGLEX))/* OPp share the meaning */
+ {
+ goto do_next; /* As if inside SASSIGN */
+ }
+
+ o->op_flags = (o->op_flags & ~OPf_WANT) | OPf_WANT_LIST;
+
+ switch (o->op_type) {
+ case OP_REPEAT:
+ if (o->op_private & OPpREPEAT_DOLIST
+ && !(o->op_flags & OPf_STACKED))
+ {
+ list(cBINOPo->op_first);
+ kid = cBINOPo->op_last;
+ /* optimise away (.....) x 1 */
+ if (kid->op_type == OP_CONST && SvIOK(kSVOP_sv)
+ && SvIVX(kSVOP_sv) == 1)
+ {
+ op_null(o); /* repeat */
+ op_null(cUNOPx(cBINOPo->op_first)->op_first);/* pushmark */
+ /* const (rhs): */
+ op_free(op_sibling_splice(o, cBINOPo->op_first, 1, NULL));
+ }
+ }
+ break;
+
+ case OP_OR:
+ case OP_AND:
+ case OP_COND_EXPR:
+ /* impose list context on everything except the condition */
+ next_kid = OpSIBLING(cUNOPo->op_first);
+ break;
+
+ default:
+ if (!(o->op_flags & OPf_KIDS))
+ break;
+ /* possibly flatten 1..10 into a constant array */
+ if (!o->op_next && cUNOPo->op_first->op_type == OP_FLOP) {
+ list(cBINOPo->op_first);
+ gen_constant_list(o);
+ goto do_next;
+ }
+ next_kid = cUNOPo->op_first; /* do all kids */
+ break;
+
+ case OP_LIST:
+ if (cLISTOPo->op_first->op_type == OP_PUSHMARK) {
+ op_null(cUNOPo->op_first); /* NULL the pushmark */
+ op_null(o); /* NULL the list */
+ }
+ if (o->op_flags & OPf_KIDS)
+ next_kid = cUNOPo->op_first; /* do all kids */
+ break;
+
+ /* the children of these ops are usually a list of statements,
+ * except the leaves, whose first child is a corresponding enter
+ */
+ case OP_SCOPE:
+ case OP_LINESEQ:
+ kid = cLISTOPo->op_first;
+ goto do_kids;
+ case OP_LEAVE:
+ case OP_LEAVETRY:
+ kid = cLISTOPo->op_first;
+ list(kid);
+ kid = OpSIBLING(kid);
+ do_kids:
+ while (kid) {
+ OP *sib = OpSIBLING(kid);
+ /* Apply void context to all kids except the last, which
+ * is list. E.g.
+ * @a = do { void; void; list }
+ * Except that 'when's are always list context, e.g.
+ * @a = do { given(..) {
+ * when (..) { list }
+ * when (..) { list }
+ * ...
+ * }}
+ */
+ if (!sib) {
+ /* tail call optimise calling list() on the last kid */
+ next_kid = kid;
+ goto do_next;
+ }
+ else if (kid->op_type == OP_LEAVEWHEN)
+ list(kid);
+ else
+ scalarvoid(kid);
+ kid = sib;
+ }
+ NOT_REACHED; /* NOTREACHED */
+ break;
+
+ }
+
+ /* If next_kid is set, someone in the code above wanted us to process
+ * that kid and all its remaining siblings. Otherwise, work our way
+ * back up the tree */
+ do_next:
+ while (!next_kid) {
+ if (o == top_op)
+ return top_op; /* at top; no parents/siblings to try */
+ if (OpHAS_SIBLING(o))
+ next_kid = o->op_sibparent;
+ else {
+ o = o->op_sibparent; /*try parent's next sibling */
+ switch (o->op_type) {
+ case OP_SCOPE:
+ case OP_LINESEQ:
+ case OP_LIST:
+ case OP_LEAVE:
+ case OP_LEAVETRY:
+ /* should really restore PL_curcop to its old value, but
+ * setting it to PL_compiling is better than do nothing */
+ PL_curcop = &PL_compiling;
+ }
+ }
+
+
+ }
+ o = next_kid;
+ } /* while */
}
+
static OP *
S_scalarseq(pTHX_ OP *o)
{
/* for a helem/hslice/kvslice, if its a fixed hash, croak on invalid
* const fields. Also, convert CONST keys to HEK-in-SVs.
- * rop is the op that retrieves the hash;
+ * rop is the op that retrieves the hash;
* key_op is the first key
+ * real if false, only check (and possibly croak); don't update op
*/
STATIC void
-S_check_hash_fields_and_hekify(pTHX_ UNOP *rop, SVOP *key_op)
+S_check_hash_fields_and_hekify(pTHX_ UNOP *rop, SVOP *key_op, int real)
{
PADNAME *lexname;
GV **fields;
if ( !SvIsCOW_shared_hash(sv = *svp)
&& SvTYPE(sv) < SVt_PVMG
&& SvOK(sv)
- && !SvROK(sv))
+ && !SvROK(sv)
+ && real)
{
SSize_t keylen;
const char * const key = SvPV_const(sv, *(STRLEN*)&keylen);
STATIC void
S_maybe_multiconcat(pTHX_ OP *o)
{
+ dVAR;
OP *lastkidop; /* the right-most of any kids unshifted onto o */
OP *topop; /* the top-most op in the concat tree (often equals o,
unless there are assign/stringify ops above it */
SSize_t nargs = 0;
SSize_t nconst = 0;
+ SSize_t nadjconst = 0; /* adjacent consts - may be demoted to args */
STRLEN variant;
bool utf8 = FALSE;
bool kid_is_last = FALSE; /* most args will be the RHS kid of a concat op;
U8 private_flags = 0; /* ... op_private of the multiconcat op */
bool is_sprintf = FALSE; /* we're optimising an sprintf */
bool is_targable = FALSE; /* targetop is an OPpTARGET_MY candidate */
+ bool prev_was_const = FALSE; /* previous arg was a const */
/* -----------------------------------------------------------------
* Phase 1:
|| o->op_type == OP_SPRINTF
|| o->op_type == OP_STRINGIFY);
+ Zero(&sprintf_info, 1, struct sprintf_ismc_info);
+
/* first see if, at the top of the tree, there is an assign,
* append and/or stringify */
}
else if ( topop->op_type == OP_CONCAT
&& (topop->op_flags & OPf_STACKED)
- && (cUNOPo->op_first->op_flags & OPf_MOD))
+ && (!(topop->op_private & OPpCONCAT_NESTED))
+ )
{
/* expr .= ..... */
last = TRUE;
}
- if ( nargs > PERL_MULTICONCAT_MAXARG - 2
+ if ( nargs + nadjconst > PERL_MULTICONCAT_MAXARG - 2
|| (argp - args + 1) > (PERL_MULTICONCAT_MAXARG*2 + 1) - 2)
{
/* At least two spare slots are needed to decompose both
argp++->p = sv;
utf8 |= cBOOL(SvUTF8(sv));
nconst++;
+ if (prev_was_const)
+ /* this const may be demoted back to a plain arg later;
+ * make sure we have enough arg slots left */
+ nadjconst++;
+ prev_was_const = !prev_was_const;
}
else {
argp++->p = NULL;
nargs++;
+ prev_was_const = FALSE;
}
if (last)
if (stacked_last)
return; /* we don't support ((A.=B).=C)...) */
+ /* look for two adjacent consts and don't fold them together:
+ * $o . "a" . "b"
+ * should do
+ * $o->concat("a")->concat("b")
+ * rather than
+ * $o->concat("ab")
+ * (but $o .= "a" . "b" should still fold)
+ */
+ {
+ bool seen_nonconst = FALSE;
+ for (argp = toparg; argp >= args; argp--) {
+ if (argp->p == NULL) {
+ seen_nonconst = TRUE;
+ continue;
+ }
+ if (!seen_nonconst)
+ continue;
+ if (argp[1].p) {
+ /* both previous and current arg were constants;
+ * leave the current OP_CONST as-is */
+ argp->p = NULL;
+ nconst--;
+ nargs++;
+ }
+ }
+ }
+
/* -----------------------------------------------------------------
* Phase 2:
*
/* see if any strings would grow if converted to utf8 */
if (!utf8) {
- char *p = (char*)argp->p;
- STRLEN len = argp->len;
- while (len--) {
- U8 c = *p++;
- if (!UTF8_IS_INVARIANT(c))
- variant++;
- }
+ variant += variant_under_utf8_count((U8 *) argp->p,
+ (U8 *) argp->p + argp->len);
}
}
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;
}
-/* helper for optimize_optree() which optimises on op then recurses
+/* helper for optimize_optree() which optimises one op then recurses
* to optimise any children.
*/
STATIC void
S_optimize_op(pTHX_ OP* o)
{
- OP *kid;
+ OP *top_op = o;
PERL_ARGS_ASSERT_OPTIMIZE_OP;
- assert(o->op_type != OP_FREED);
- switch (o->op_type) {
- case OP_NEXTSTATE:
- case OP_DBSTATE:
- PL_curcop = ((COP*)o); /* for warnings */
- break;
+ while (1) {
+ OP * next_kid = NULL;
+ assert(o->op_type != OP_FREED);
- case OP_CONCAT:
- case OP_SASSIGN:
- case OP_STRINGIFY:
- case OP_SPRINTF:
- S_maybe_multiconcat(aTHX_ o);
- break;
+ switch (o->op_type) {
+ case OP_NEXTSTATE:
+ case OP_DBSTATE:
+ PL_curcop = ((COP*)o); /* for warnings */
+ break;
- case OP_SUBST:
- if (cPMOPo->op_pmreplrootu.op_pmreplroot)
- optimize_op(cPMOPo->op_pmreplrootu.op_pmreplroot);
- break;
- default:
- break;
- }
+ case OP_CONCAT:
+ case OP_SASSIGN:
+ case OP_STRINGIFY:
+ case OP_SPRINTF:
+ S_maybe_multiconcat(aTHX_ o);
+ break;
- if (!(o->op_flags & OPf_KIDS))
- return;
+ case OP_SUBST:
+ if (cPMOPo->op_pmreplrootu.op_pmreplroot) {
+ /* we can't assume that op_pmreplroot->op_sibparent == o
+ * and that it is thus possible to walk back up the tree
+ * past op_pmreplroot. So, although we try to avoid
+ * recursing through op trees, do it here. After all,
+ * there are unlikely to be many nested s///e's within
+ * the replacement part of a s///e.
+ */
+ optimize_op(cPMOPo->op_pmreplrootu.op_pmreplroot);
+ }
+ break;
+
+ default:
+ break;
+ }
+
+ if (o->op_flags & OPf_KIDS)
+ next_kid = cUNOPo->op_first;
+
+ /* if a kid hasn't been nominated to process, continue with the
+ * next sibling, or if no siblings left, go back to the parent's
+ * siblings and so on
+ */
+ while (!next_kid) {
+ if (o == top_op)
+ return; /* at top; no parents/siblings to try */
+ if (OpHAS_SIBLING(o))
+ next_kid = o->op_sibparent;
+ else
+ o = o->op_sibparent; /*try parent's next sibling */
+ }
- for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid))
- optimize_op(kid);
+ /* this label not yet used. Goto here if any code above sets
+ * next-kid
+ get_next_op:
+ */
+ o = next_kid;
+ }
}
}
#endif
+/*
+=for apidoc traverse_op_tree
+
+Return the next op in a depth-first traversal of the op tree,
+returning NULL when the traversal is complete.
+
+The initial call must supply the root of the tree as both top and o.
+
+For now it's static, but it may be exposed to the API in the future.
+
+=cut
+*/
+
+STATIC OP*
+S_traverse_op_tree(pTHX_ OP *top, OP *o) {
+ OP *sib;
+
+ PERL_ARGS_ASSERT_TRAVERSE_OP_TREE;
+
+ if ((o->op_flags & OPf_KIDS) && cUNOPo->op_first) {
+ return cUNOPo->op_first;
+ }
+ else if ((sib = OpSIBLING(o))) {
+ return sib;
+ }
+ else {
+ OP *parent = o->op_sibparent;
+ assert(!(o->op_moresib));
+ while (parent && parent != top) {
+ OP *sib = OpSIBLING(parent);
+ if (sib)
+ return sib;
+ parent = parent->op_sibparent;
+ }
+
+ return NULL;
+ }
+}
STATIC void
S_finalize_op(pTHX_ OP* o)
{
+ OP * const top = o;
PERL_ARGS_ASSERT_FINALIZE_OP;
- assert(o->op_type != OP_FREED);
+ do {
+ assert(o->op_type != OP_FREED);
- switch (o->op_type) {
- case OP_NEXTSTATE:
- case OP_DBSTATE:
- PL_curcop = ((COP*)o); /* for warnings */
- break;
- case OP_EXEC:
- if (OpHAS_SIBLING(o)) {
- OP *sib = OpSIBLING(o);
- if (( sib->op_type == OP_NEXTSTATE || sib->op_type == OP_DBSTATE)
- && ckWARN(WARN_EXEC)
- && OpHAS_SIBLING(sib))
- {
+ switch (o->op_type) {
+ case OP_NEXTSTATE:
+ case OP_DBSTATE:
+ PL_curcop = ((COP*)o); /* for warnings */
+ break;
+ case OP_EXEC:
+ if (OpHAS_SIBLING(o)) {
+ OP *sib = OpSIBLING(o);
+ if (( sib->op_type == OP_NEXTSTATE || sib->op_type == OP_DBSTATE)
+ && ckWARN(WARN_EXEC)
+ && OpHAS_SIBLING(sib))
+ {
const OPCODE type = OpSIBLING(sib)->op_type;
if (type != OP_EXIT && type != OP_WARN && type != OP_DIE) {
const line_t oldline = CopLINE(PL_curcop);
"\t(Maybe you meant system() when you said exec()?)\n");
CopLINE_set(PL_curcop, oldline);
}
- }
- }
- break;
+ }
+ }
+ break;
- case OP_GV:
- if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) {
- GV * const gv = cGVOPo_gv;
- if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX_const(GvCV(gv))) {
- /* XXX could check prototype here instead of just carping */
- SV * const sv = sv_newmortal();
- gv_efullname3(sv, gv, NULL);
- Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE),
- "%" SVf "() called too early to check prototype",
- SVfARG(sv));
- }
- }
- break;
+ case OP_GV:
+ if ((o->op_private & OPpEARLY_CV) && ckWARN(WARN_PROTOTYPE)) {
+ GV * const gv = cGVOPo_gv;
+ if (SvTYPE(gv) == SVt_PVGV && GvCV(gv) && SvPVX_const(GvCV(gv))) {
+ /* XXX could check prototype here instead of just carping */
+ SV * const sv = sv_newmortal();
+ gv_efullname3(sv, gv, NULL);
+ Perl_warner(aTHX_ packWARN(WARN_PROTOTYPE),
+ "%" SVf "() called too early to check prototype",
+ SVfARG(sv));
+ }
+ }
+ break;
- case OP_CONST:
- if (cSVOPo->op_private & OPpCONST_STRICT)
- no_bareword_allowed(o);
+ case OP_CONST:
+ if (cSVOPo->op_private & OPpCONST_STRICT)
+ no_bareword_allowed(o);
#ifdef USE_ITHREADS
- /* FALLTHROUGH */
- case OP_HINTSEVAL:
- op_relocate_sv(&cSVOPo->op_sv, &o->op_targ);
+ /* FALLTHROUGH */
+ case OP_HINTSEVAL:
+ op_relocate_sv(&cSVOPo->op_sv, &o->op_targ);
#endif
- break;
+ break;
#ifdef USE_ITHREADS
- /* Relocate all the METHOP's SVs to the pad for thread safety. */
- case OP_METHOD_NAMED:
- case OP_METHOD_SUPER:
- case OP_METHOD_REDIR:
- case OP_METHOD_REDIR_SUPER:
- op_relocate_sv(&cMETHOPx(o)->op_u.op_meth_sv, &o->op_targ);
- break;
+ /* Relocate all the METHOP's SVs to the pad for thread safety. */
+ case OP_METHOD_NAMED:
+ case OP_METHOD_SUPER:
+ case OP_METHOD_REDIR:
+ case OP_METHOD_REDIR_SUPER:
+ op_relocate_sv(&cMETHOPx(o)->op_u.op_meth_sv, &o->op_targ);
+ break;
#endif
- case OP_HELEM: {
- UNOP *rop;
- SVOP *key_op;
- OP *kid;
-
- if ((key_op = cSVOPx(((BINOP*)o)->op_last))->op_type != OP_CONST)
- break;
+ case OP_HELEM: {
+ UNOP *rop;
+ SVOP *key_op;
+ OP *kid;
- rop = (UNOP*)((BINOP*)o)->op_first;
+ if ((key_op = cSVOPx(((BINOP*)o)->op_last))->op_type != OP_CONST)
+ break;
- goto check_keys;
+ rop = (UNOP*)((BINOP*)o)->op_first;
- case OP_HSLICE:
- S_scalar_slice_warning(aTHX_ o);
- /* FALLTHROUGH */
+ goto check_keys;
- case OP_KVHSLICE:
- kid = OpSIBLING(cLISTOPo->op_first);
- if (/* I bet there's always a pushmark... */
- OP_TYPE_ISNT_AND_WASNT_NN(kid, OP_LIST)
- && OP_TYPE_ISNT_NN(kid, OP_CONST))
- {
- break;
- }
+ case OP_HSLICE:
+ S_scalar_slice_warning(aTHX_ o);
+ /* FALLTHROUGH */
- key_op = (SVOP*)(kid->op_type == OP_CONST
- ? kid
- : OpSIBLING(kLISTOP->op_first));
+ case OP_KVHSLICE:
+ kid = OpSIBLING(cLISTOPo->op_first);
+ if (/* I bet there's always a pushmark... */
+ OP_TYPE_ISNT_AND_WASNT_NN(kid, OP_LIST)
+ && OP_TYPE_ISNT_NN(kid, OP_CONST))
+ {
+ break;
+ }
- rop = (UNOP*)((LISTOP*)o)->op_last;
+ key_op = (SVOP*)(kid->op_type == OP_CONST
+ ? kid
+ : OpSIBLING(kLISTOP->op_first));
- check_keys:
- if (o->op_private & OPpLVAL_INTRO || rop->op_type != OP_RV2HV)
- rop = NULL;
- S_check_hash_fields_and_hekify(aTHX_ rop, key_op);
- break;
- }
- case OP_NULL:
- if (o->op_targ != OP_HSLICE && o->op_targ != OP_ASLICE)
- break;
- /* FALLTHROUGH */
- case OP_ASLICE:
- S_scalar_slice_warning(aTHX_ o);
- break;
+ rop = (UNOP*)((LISTOP*)o)->op_last;
- case OP_SUBST: {
- if (cPMOPo->op_pmreplrootu.op_pmreplroot)
- finalize_op(cPMOPo->op_pmreplrootu.op_pmreplroot);
- break;
- }
- default:
- break;
- }
+ check_keys:
+ if (o->op_private & OPpLVAL_INTRO || rop->op_type != OP_RV2HV)
+ rop = NULL;
+ S_check_hash_fields_and_hekify(aTHX_ rop, key_op, 1);
+ break;
+ }
+ case OP_NULL:
+ if (o->op_targ != OP_HSLICE && o->op_targ != OP_ASLICE)
+ break;
+ /* FALLTHROUGH */
+ case OP_ASLICE:
+ S_scalar_slice_warning(aTHX_ o);
+ break;
- if (o->op_flags & OPf_KIDS) {
- OP *kid;
+ case OP_SUBST: {
+ if (cPMOPo->op_pmreplrootu.op_pmreplroot)
+ finalize_op(cPMOPo->op_pmreplrootu.op_pmreplroot);
+ break;
+ }
+ default:
+ break;
+ }
#ifdef DEBUGGING
- /* check that op_last points to the last sibling, and that
- * the last op_sibling/op_sibparent field points back to the
- * parent, and that the only ops with KIDS are those which are
- * entitled to them */
- U32 type = o->op_type;
- U32 family;
- bool has_last;
-
- if (type == OP_NULL) {
- type = o->op_targ;
- /* ck_glob creates a null UNOP with ex-type GLOB
- * (which is a list op. So pretend it wasn't a listop */
- if (type == OP_GLOB)
- type = OP_NULL;
- }
- family = PL_opargs[type] & OA_CLASS_MASK;
-
- has_last = ( family == OA_BINOP
- || family == OA_LISTOP
- || family == OA_PMOP
- || family == OA_LOOP
- );
- assert( has_last /* has op_first and op_last, or ...
- ... has (or may have) op_first: */
- || family == OA_UNOP
- || family == OA_UNOP_AUX
- || family == OA_LOGOP
- || family == OA_BASEOP_OR_UNOP
- || family == OA_FILESTATOP
- || family == OA_LOOPEXOP
- || family == OA_METHOP
- || type == OP_CUSTOM
- || type == OP_NULL /* new_logop does this */
- );
-
- for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
-# ifdef PERL_OP_PARENT
- if (!OpHAS_SIBLING(kid)) {
- if (has_last)
- assert(kid == cLISTOPo->op_last);
- assert(kid->op_sibparent == o);
+ if (o->op_flags & OPf_KIDS) {
+ OP *kid;
+
+ /* check that op_last points to the last sibling, and that
+ * the last op_sibling/op_sibparent field points back to the
+ * parent, and that the only ops with KIDS are those which are
+ * entitled to them */
+ U32 type = o->op_type;
+ U32 family;
+ bool has_last;
+
+ if (type == OP_NULL) {
+ type = o->op_targ;
+ /* ck_glob creates a null UNOP with ex-type GLOB
+ * (which is a list op. So pretend it wasn't a listop */
+ if (type == OP_GLOB)
+ type = OP_NULL;
+ }
+ family = PL_opargs[type] & OA_CLASS_MASK;
+
+ has_last = ( family == OA_BINOP
+ || family == OA_LISTOP
+ || family == OA_PMOP
+ || family == OA_LOOP
+ );
+ assert( has_last /* has op_first and op_last, or ...
+ ... has (or may have) op_first: */
+ || family == OA_UNOP
+ || family == OA_UNOP_AUX
+ || family == OA_LOGOP
+ || family == OA_BASEOP_OR_UNOP
+ || family == OA_FILESTATOP
+ || family == OA_LOOPEXOP
+ || family == OA_METHOP
+ || type == OP_CUSTOM
+ || type == OP_NULL /* new_logop does this */
+ );
+
+ for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid)) {
+ if (!OpHAS_SIBLING(kid)) {
+ if (has_last)
+ assert(kid == cLISTOPo->op_last);
+ assert(kid->op_sibparent == o);
+ }
}
-# else
- if (has_last && !OpHAS_SIBLING(kid))
- assert(kid == cLISTOPo->op_last);
-# endif
}
#endif
-
- for (kid = cUNOPo->op_first; kid; kid = OpSIBLING(kid))
- finalize_op(kid);
- }
+ } while (( o = traverse_op_tree(top, o)) != NULL);
}
/*
-=for apidoc Amx|OP *|op_lvalue|OP *o|I32 type
+=for apidoc op_lvalue
Propagate lvalue ("modifiable") context to an op and its children.
C<type> represents the context type, roughly based on the type of op that
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
/* [20011101.069 (#7861)] File test operators interpret OPf_REF to mean that
their argument is a filehandle; thus \stat(".") should not set
it. AMS 20011102 */
- if (type == OP_REFGEN &&
- PL_check[o->op_type] == Perl_ck_ftst)
+ if (type == OP_REFGEN && OP_IS_STAT(o->op_type))
return o;
if (type != OP_LEAVESUBLV)
}
/*
-=for apidoc Amx|OP *|op_scope|OP *o
+=for apidoc op_scope
Wraps up an op tree with some additional ops so that at runtime a dynamic
scope will be created. The original ops run in the new dynamic scope,
}
/*
-=for apidoc Am|int|block_start|int full
+=for apidoc block_start
Handles compile-time scope entry.
Arranges for hints to be restored on block
}
/*
-=for apidoc Am|OP *|block_end|I32 floor|OP *seq
+=for apidoc block_end
Handles compile-time scope exit. C<floor>
is the savestack index returned by
/*
=head1 Compile-time scope hooks
-=for apidoc Aox||blockhook_register
+=for apidoc blockhook_register
Register a set of hooks to be called when the Perl lexical scope changes
at compile time. See L<perlguts/"Compile-time scope hooks">.
start = LINKLIST(PL_main_root);
PL_main_root->op_next = 0;
S_process_optree(aTHX_ NULL, PL_main_root, start);
- cv_forget_slab(PL_compcv);
+ if (!PL_parser->error_count)
+ /* on error, leave CV slabbed so that ops left lying around
+ * will eb cleaned up. Else unslab */
+ cv_forget_slab(PL_compcv);
PL_compcv = 0;
/* Register with debugger */
return o;
}
+/* This function exists solely to provide a scope to limit
+ setjmp/longjmp() messing with auto variables.
+ */
+PERL_STATIC_INLINE int
+S_fold_constants_eval(pTHX) {
+ int ret = 0;
+ dJMPENV;
+
+ JMPENV_PUSH(ret);
+
+ if (ret == 0) {
+ CALLRUNOPS(aTHX);
+ }
+
+ JMPENV_POP;
+
+ return ret;
+}
+
static OP *
S_fold_constants(pTHX_ OP *const o)
{
dVAR;
- OP * volatile curop;
+ OP *curop;
OP *newop;
- volatile I32 type = o->op_type;
+ I32 type = o->op_type;
bool is_stringify;
- SV * volatile sv = NULL;
+ SV *sv = NULL;
int ret = 0;
OP *old_next;
SV * const oldwarnhook = PL_warnhook;
COP not_compiling;
U8 oldwarn = PL_dowarn;
I32 old_cxix;
- dJMPENV;
PERL_ARGS_ASSERT_FOLD_CONSTANTS;
assert(IN_PERL_RUNTIME);
PL_warnhook = PERL_WARNHOOK_FATAL;
PL_diehook = NULL;
- JMPENV_PUSH(ret);
/* Effective $^W=1. */
if ( ! (PL_dowarn & G_WARN_ALL_MASK))
PL_dowarn |= G_WARN_ON;
+ ret = S_fold_constants_eval(aTHX);
+
switch (ret) {
case 0:
- CALLRUNOPS(aTHX);
sv = *(PL_stack_sp--);
if (o->op_targ && sv == PAD_SV(o->op_targ)) { /* grab pad temp? */
pad_swipe(o->op_targ, FALSE);
o->op_next = old_next;
break;
default:
- JMPENV_POP;
/* Don't expect 1 (setjmp failed) or 2 (something called my_exit) */
PL_warnhook = oldwarnhook;
PL_diehook = olddiehook;
* the stack - eg any nested evals */
Perl_croak(aTHX_ "panic: fold_constants JMPENV_PUSH returned %d", ret);
}
- JMPENV_POP;
PL_dowarn = oldwarn;
PL_warnhook = oldwarnhook;
PL_diehook = olddiehook;
return o;
}
-static OP *
+/* convert a constant range in list context into an OP_RV2AV, OP_CONST pair;
+ * the constant value being an AV holding the flattened range.
+ */
+
+static void
S_gen_constant_list(pTHX_ OP *o)
{
dVAR;
list(o);
if (PL_parser && PL_parser->error_count)
- return o; /* Don't attempt to run with errors */
+ return; /* Don't attempt to run with errors */
curop = LINKLIST(o);
old_next = o->op_next;
delete_eval_scope();
}
if (ret)
- return o;
+ return;
OpTYPE_set(o, OP_RV2AV);
o->op_flags &= ~OPf_REF; /* treat \(1..2) like an ordinary list */
SvREADONLY_on(*svp);
}
LINKLIST(o);
- return list(o);
+ list(o);
+ return;
}
/*
/* List constructors */
/*
-=for apidoc Am|OP *|op_append_elem|I32 optype|OP *first|OP *last
+=for apidoc op_append_elem
Append an item to the list of ops contained directly within a list-type
op, returning the lengthened list. C<first> is the list-type op,
}
/*
-=for apidoc Am|OP *|op_append_list|I32 optype|OP *first|OP *last
+=for apidoc op_append_list
Concatenate the lists of ops contained directly within two list-type ops,
returning the combined list. C<first> and C<last> are the list-type ops
}
/*
-=for apidoc Am|OP *|op_prepend_elem|I32 optype|OP *first|OP *last
+=for apidoc op_prepend_elem
Prepend an item to the list of ops contained directly within a list-type
op, returning the lengthened list. C<first> is the op to prepend to the
}
/*
-=for apidoc Am|OP *|op_convert_list|I32 type|I32 flags|OP *o
+=for apidoc op_convert_list
Converts C<o> into a list op if it is not one already, and then converts it
into the specified C<type>, calling its check function, allocating a target if
/*
=head1 Optree construction
-=for apidoc Am|OP *|newNULLLIST
+=for apidoc newNULLLIST
Constructs, checks, and returns a new C<stub> op, which represents an
empty list expression.
}
/*
-=for apidoc Am|OP *|newLISTOP|I32 type|I32 flags|OP *first|OP *last
+=for apidoc newLISTOP
Constructs, checks, and returns an op of any list type. C<type> is
the opcode. C<flags> gives the eight bits of C<op_flags>, except that
{
dVAR;
LISTOP *listop;
+ /* Note that allocating an OP_PUSHMARK can die under Safe.pm if
+ * pushmark is banned. So do it now while existing ops are in a
+ * consistent state, in case they suddenly get freed */
+ OP* const pushop = type == OP_LIST ? newOP(OP_PUSHMARK, 0) : NULL;
assert((PL_opargs[type] & OA_CLASS_MASK) == OA_LISTOP
|| type == OP_CUSTOM);
NewOp(1101, listop, 1, LISTOP);
-
OpTYPE_set(listop, type);
if (first || last)
flags |= OPf_KIDS;
OpMORESIB_set(first, last);
listop->op_first = first;
listop->op_last = last;
- if (type == OP_LIST) {
- OP* const pushop = newOP(OP_PUSHMARK, 0);
+
+ if (pushop) {
OpMORESIB_set(pushop, first);
listop->op_first = pushop;
listop->op_flags |= OPf_KIDS;
}
/*
-=for apidoc Am|OP *|newOP|I32 type|I32 flags
+=for apidoc newOP
Constructs, checks, and returns an op of any base type (any type that
has no extra fields). C<type> is the opcode. C<flags> gives the
}
/*
-=for apidoc Am|OP *|newUNOP|I32 type|I32 flags|OP *first
+=for apidoc newUNOP
Constructs, checks, and returns an op of any unary type. C<type> is
the opcode. C<flags> gives the eight bits of C<op_flags>, except that
}
/*
-=for apidoc Am|OP *|newMETHOP|I32 type|I32 flags|OP *first
+=for apidoc newMETHOP
Constructs, checks, and returns an op of method type with a method name
evaluated at runtime. C<type> is the opcode. C<flags> gives the eight
}
/*
-=for apidoc Am|OP *|newMETHOP_named|I32 type|I32 flags|SV *const_meth
+=for apidoc newMETHOP_named
Constructs, checks, and returns an op of method type with a constant
method name. C<type> is the opcode. C<flags> gives the eight bits of
}
/*
-=for apidoc Am|OP *|newBINOP|I32 type|I32 flags|OP *first|OP *last
+=for apidoc newBINOP
Constructs, checks, and returns an op of any binary type. C<type>
is the opcode. C<flags> gives the eight bits of C<op_flags>, except
return fold_constants(op_integerize(op_std_init((OP *)binop)));
}
+/* Helper function for S_pmtrans(): comparison function to sort an array
+ * of codepoint range pairs. Sorts by start point, or if equal, by end
+ * point */
+
static int uvcompare(const void *a, const void *b)
__attribute__nonnull__(1)
__attribute__nonnull__(2)
return 0;
}
+/* Given an OP_TRANS / OP_TRANSR op o, plus OP_CONST ops expr and repl
+ * containing the search and replacement strings, assemble into
+ * a translation table attached as o->op_pv.
+ * Free expr and repl.
+ * It expects the toker to have already set the
+ * OPpTRANS_COMPLEMENT
+ * OPpTRANS_SQUASH
+ * OPpTRANS_DELETE
+ * flags as appropriate; this function may add
+ * OPpTRANS_FROM_UTF
+ * OPpTRANS_TO_UTF
+ * OPpTRANS_IDENTICAL
+ * OPpTRANS_GROWS
+ * flags
+ */
+
static OP *
S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
{
SV * const tstr = ((SVOP*)expr)->op_sv;
- SV * const rstr =
- ((SVOP*)repl)->op_sv;
+ SV * const rstr = ((SVOP*)repl)->op_sv;
STRLEN tlen;
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;
o->op_private |= OPpTRANS_TO_UTF;
if (o->op_private & (OPpTRANS_FROM_UTF|OPpTRANS_TO_UTF)) {
+
+ /* for utf8 translations, op_sv will be set to point to a swash
+ * containing codepoint ranges. This is done by first assembling
+ * a textual representation of the ranges in listsv then compiling
+ * it using swash_init(). For more details of the textual format,
+ * see L<perlunicode.pod/"User-Defined Character Properties"> .
+ */
+
SV* const listsv = newSVpvs("# comment\n");
SV* transv = NULL;
const U8* tend = t + tlen;
* odd. */
if (complement) {
+ /* utf8 and /c:
+ * replace t/tlen/tend with a version that has the ranges
+ * complemented
+ */
U8 tmpbuf[UTF8_MAXBYTES+1];
UV *cp;
UV nextmin = 0;
Newx(cp, 2*tlen, UV);
i = 0;
transv = newSVpvs("");
+
+ /* convert search string into array of (start,end) range
+ * codepoint pairs stored in cp[]. Most "ranges" will start
+ * and end at the same char */
while (t < tend) {
cp[2*i] = utf8n_to_uvchr(t, tend-t, &ulen, flags);
t += ulen;
+ /* the toker converts X-Y into (X, ILLEGAL_UTF8_BYTE, Y) */
if (t < tend && *t == ILLEGAL_UTF8_BYTE) {
t++;
cp[2*i+1] = utf8n_to_uvchr(t, tend-t, &ulen, flags);
}
i++;
}
+
+ /* sort the ranges */
qsort(cp, i, 2*sizeof(UV), uvcompare);
+
+ /* Create a utf8 string containing the complement of the
+ * codepoint ranges. For example if cp[] contains [A,B], [C,D],
+ * then transv will contain the equivalent of:
+ * join '', map chr, 0, ILLEGAL_UTF8_BYTE, A - 1,
+ * B + 1, ILLEGAL_UTF8_BYTE, C - 1,
+ * D + 1, ILLEGAL_UTF8_BYTE, 0x7fffffff;
+ * A range of a single char skips the ILLEGAL_UTF8_BYTE and
+ * end cp.
+ */
for (j = 0; j < i; j++) {
UV val = cp[2*j];
diff = val - nextmin;
if (val >= nextmin)
nextmin = val + 1;
}
+
t = uvchr_to_utf8(tmpbuf,nextmin);
sv_catpvn(transv, (char*)tmpbuf, t - tmpbuf);
{
else if (!rlen && !del) {
r = t; rlen = tlen; rend = tend;
}
+
if (!squash) {
if ((!rlen && !del) || t == r ||
(tlen == rlen && memEQ((char *)t, (char *)r, tlen)))
}
}
+ /* extract char ranges from t and r and append them to listsv */
+
while (t < tend || tfirst <= tlast) {
/* see if we need more "t" chars */
if (tfirst > tlast) {
tfirst += diff + 1;
}
+ /* compile listsv into a swash and attach to o */
+
none = ++max;
if (del)
- del = ++max;
+ ++max;
if (max > 0xffff)
bits = 32;
goto warnins;
}
- tbl = (short*)PerlMemShared_calloc(
- (o->op_private & OPpTRANS_COMPLEMENT) &&
- !(o->op_private & OPpTRANS_DELETE) ? 258 : 256,
- sizeof(short));
+ /* 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.
+ *
+ * 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.
+ */
+
+ /* 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) {
- for (i = 0; i < (I32)tlen; i++)
- tbl[t[i]] = -1;
+ 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 < 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;
}
}
- if (!del) {
- if (!rlen) {
- j = rlen;
- if (!squash)
- o->op_private |= OPpTRANS_IDENTICAL;
- }
- else if (j >= (I32)rlen)
- j = rlen - 1;
- else {
- tbl =
- (short *)
- PerlMemShared_realloc(tbl,
- (0x101+rlen-j) * sizeof(short));
- cPVOPo->op_pv = (char*)tbl;
- }
- tbl[0x100] = (short)(rlen - j);
- 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 */
+
warnins:
if(del && rlen == tlen) {
Perl_ck_warner(aTHX_ packWARN(WARN_MISC), "Useless use of /d modifier in transliteration operator");
return o;
}
+
/*
-=for apidoc Am|OP *|newPMOP|I32 type|I32 flags
+=for apidoc newPMOP
Constructs, checks, and returns an op of any pattern matching type.
C<type> is the opcode. C<flags> gives the eight bits of C<op_flags>
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 */
rx_flags |= RXf_SPLIT;
}
- /* Skip compiling if parser found an error for this pattern */
- if (pm->op_pmflags & PMf_HAS_ERROR) {
- return o;
- }
-
if (!has_code || !eng->op_comp) {
/* compile-time simple constant pattern */
# endif
}
#endif
- /* But we know that one op is using this CV's slab. */
- cv_forget_slab(PL_compcv);
+ /* This LEAVE_SCOPE will restore PL_compcv to point to the
+ * outer CV (the one whose slab holds the pm op). The
+ * inner CV (which holds expr) will be freed later, once
+ * all the entries on the parse stack have been popped on
+ * return from this function. Which is why its safe to
+ * call op_free(expr) below.
+ */
LEAVE_SCOPE(floor);
pm->op_pmflags &= ~PMf_HAS_CV;
}
+ /* Skip compiling if parser found an error for this pattern */
+ if (pm->op_pmflags & PMf_HAS_ERROR) {
+ return o;
+ }
+
PM_SETRE(pm,
eng->op_comp
? eng->op_comp(aTHX_ NULL, 0, expr, eng, NULL, NULL,
}
else {
/* compile-time pattern that includes literal code blocks */
- REGEXP* re = eng->op_comp(aTHX_ NULL, 0, expr, eng, NULL, NULL,
+
+ REGEXP* re;
+
+ /* Skip compiling if parser found an error for this pattern */
+ if (pm->op_pmflags & PMf_HAS_ERROR) {
+ return o;
+ }
+
+ re = eng->op_comp(aTHX_ NULL, 0, expr, eng, NULL, NULL,
rx_flags,
(pm->op_pmflags |
((PL_hints & HINT_RE_EVAL) ? PMf_USE_RE_EVAL : 0))
}
/*
-=for apidoc Am|OP *|newSVOP|I32 type|I32 flags|SV *sv
+=for apidoc newSVOP
Constructs, checks, and returns an op of any type that involves an
embedded SV. C<type> is the opcode. C<flags> gives the eight bits
}
/*
-=for apidoc Am|OP *|newDEFSVOP|
+=for apidoc newDEFSVOP
Constructs and returns an op to access C<$_>.
#ifdef USE_ITHREADS
/*
-=for apidoc Am|OP *|newPADOP|I32 type|I32 flags|SV *sv
+=for apidoc newPADOP
Constructs, checks, and returns an op of any type that involves a
reference to a pad element. C<type> is the opcode. C<flags> gives the
#endif /* USE_ITHREADS */
/*
-=for apidoc Am|OP *|newGVOP|I32 type|I32 flags|GV *gv
+=for apidoc newGVOP
Constructs, checks, and returns an op of any type that involves an
embedded reference to a GV. C<type> is the opcode. C<flags> gives the
}
/*
-=for apidoc Am|OP *|newPVOP|I32 type|I32 flags|char *pv
+=for apidoc newPVOP
Constructs, checks, and returns an op of any type that involves an
embedded C-level pointer (PV). C<type> is the opcode. C<flags> gives
Perl_vload_module(pTHX_ U32 flags, SV *name, SV *ver, va_list *args)
{
OP *veop, *imop;
- OP * const modname = newSVOP(OP_CONST, 0, name);
+ OP * modname;
+ I32 floor;
PERL_ARGS_ASSERT_VLOAD_MODULE;
+ /* utilize() fakes up a BEGIN { require ..; import ... }, so make sure
+ * that it has a PL_parser to play with while doing that, and also
+ * that it doesn't mess with any existing parser, by creating a tmp
+ * new parser with lex_start(). This won't actually be used for much,
+ * since pp_require() will create another parser for the real work.
+ * The ENTER/LEAVE pair protect callers from any side effects of use.
+ *
+ * start_subparse() creates a new PL_compcv. This means that any ops
+ * allocated below will be allocated from that CV's op slab, and so
+ * will be automatically freed if the utilise() fails
+ */
+
+ ENTER;
+ SAVEVPTR(PL_curcop);
+ lex_start(NULL, NULL, LEX_START_SAME_FILTER);
+ floor = start_subparse(FALSE, 0);
+
+ modname = newSVOP(OP_CONST, 0, name);
modname->op_private |= OPpCONST_BARE;
if (ver) {
veop = newSVOP(OP_CONST, 0, ver);
}
}
- /* utilize() fakes up a BEGIN { require ..; import ... }, so make sure
- * that it has a PL_parser to play with while doing that, and also
- * that it doesn't mess with any existing parser, by creating a tmp
- * new parser with lex_start(). This won't actually be used for much,
- * since pp_require() will create another parser for the real work.
- * The ENTER/LEAVE pair protect callers from any side effects of use. */
-
- ENTER;
- SAVEVPTR(PL_curcop);
- lex_start(NULL, NULL, LEX_START_SAME_FILTER);
- utilize(!(flags & PERL_LOADMOD_DENY), start_subparse(FALSE, 0),
- veop, modname, imop);
+ utilize(!(flags & PERL_LOADMOD_DENY), floor, veop, modname, imop);
LEAVE;
}
/*
=head1 Optree construction
-=for apidoc Am|OP *|newSLICEOP|I32 flags|OP *subscript|OP *listval
+=for apidoc newSLICEOP
Constructs, checks, and returns an C<lslice> (list slice) op. C<flags>
gives the eight bits of C<op_flags>, except that C<OPf_KIDS> will
list(force_list(listval, 1)) );
}
+#define ASSIGN_SCALAR 0
#define ASSIGN_LIST 1
#define ASSIGN_REF 2
+/* given the optree o on the LHS of an assignment, determine whether its:
+ * ASSIGN_SCALAR $x = ...
+ * ASSIGN_LIST ($x) = ...
+ * ASSIGN_REF \$x = ...
+ */
+
STATIC I32
S_assignment_type(pTHX_ const OP *o)
{
U8 ret;
if (!o)
- return TRUE;
+ return ASSIGN_LIST;
- if ((o->op_type == OP_NULL) && (o->op_flags & OPf_KIDS))
- o = cUNOPo->op_first;
+ if (o->op_type == OP_SREFGEN)
+ {
+ OP * const kid = cUNOPx(cUNOPo->op_first)->op_first;
+ type = kid->op_type;
+ flags = o->op_flags | kid->op_flags;
+ if (!(flags & OPf_PARENS)
+ && (kid->op_type == OP_RV2AV || kid->op_type == OP_PADAV ||
+ kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV ))
+ return ASSIGN_REF;
+ ret = ASSIGN_REF;
+ } else {
+ if ((o->op_type == OP_NULL) && (o->op_flags & OPf_KIDS))
+ o = cUNOPo->op_first;
+ flags = o->op_flags;
+ type = o->op_type;
+ ret = ASSIGN_SCALAR;
+ }
- flags = o->op_flags;
- type = o->op_type;
if (type == OP_COND_EXPR) {
OP * const sib = OpSIBLING(cLOGOPo->op_first);
const I32 t = assignment_type(sib);
return ASSIGN_LIST;
if ((t == ASSIGN_LIST) ^ (f == ASSIGN_LIST))
yyerror("Assignment to both a list and a scalar");
- return FALSE;
- }
-
- if (type == OP_SREFGEN)
- {
- OP * const kid = cUNOPx(cUNOPo->op_first)->op_first;
- type = kid->op_type;
- flags |= kid->op_flags;
- if (!(flags & OPf_PARENS)
- && (kid->op_type == OP_RV2AV || kid->op_type == OP_PADAV ||
- kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV ))
- return ASSIGN_REF;
- ret = ASSIGN_REF;
+ return ASSIGN_SCALAR;
}
- else ret = 0;
if (type == OP_LIST &&
(flags & OPf_WANT) == OPf_WANT_SCALAR &&
type == OP_RV2AV || type == OP_RV2HV ||
type == OP_ASLICE || type == OP_HSLICE ||
type == OP_KVASLICE || type == OP_KVHSLICE || type == OP_REFGEN)
- return TRUE;
+ return ASSIGN_LIST;
if (type == OP_PADAV || type == OP_PADHV)
- return TRUE;
+ return ASSIGN_LIST;
if (type == OP_RV2SV)
return ret;
static OP *
S_newONCEOP(pTHX_ OP *initop, OP *padop)
{
+ dVAR;
const PADOFFSET target = padop->op_targ;
OP *const other = newOP(OP_PADSV,
padop->op_flags
}
/*
-=for apidoc Am|OP *|newASSIGNOP|I32 flags|OP *left|I32 optype|OP *right
+=for apidoc newASSIGNOP
Constructs, checks, and returns an assignment op. C<left> and C<right>
supply the parameters of the assignment; they are consumed by this
}
/*
-=for apidoc Am|OP *|newSTATEOP|I32 flags|char *label|OP *o
+=for apidoc newSTATEOP
Constructs a state op (COP). The state op is normally a C<nextstate> op,
but will be a C<dbstate> op if debugging is enabled for currently-compiled
}
/*
-=for apidoc Am|OP *|newLOGOP|I32 type|I32 flags|OP *first|OP *other
+=for apidoc newLOGOP
Constructs, checks, and returns a logical (flow control) op. C<type>
is the opcode. C<flags> gives the eight bits of C<op_flags>, except
return new_logop(type, flags, &first, &other);
}
+
+/* See if the optree o contains a single OP_CONST (plus possibly
+ * surrounding enter/nextstate/null etc). If so, return it, else return
+ * NULL.
+ */
+
STATIC OP *
S_search_const(pTHX_ OP *o)
{
PERL_ARGS_ASSERT_SEARCH_CONST;
+ redo:
switch (o->op_type) {
case OP_CONST:
return o;
case OP_NULL:
- if (o->op_flags & OPf_KIDS)
- return search_const(cUNOPo->op_first);
+ if (o->op_flags & OPf_KIDS) {
+ o = cUNOPo->op_first;
+ goto redo;
+ }
break;
case OP_LEAVE:
case OP_SCOPE:
if (!(o->op_flags & OPf_KIDS))
return NULL;
kid = cLISTOPo->op_first;
+
do {
switch (kid->op_type) {
case OP_ENTER:
goto last;
}
} while (kid);
+
if (!kid)
kid = cLISTOPo->op_last;
last:
- return search_const(kid);
+ o = kid;
+ goto redo;
}
}
return NULL;
}
+
STATIC OP *
S_new_logop(pTHX_ I32 type, I32 flags, OP** firstp, OP** otherp)
{
&& 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;
}
/*
-=for apidoc Am|OP *|newCONDOP|I32 flags|OP *first|OP *trueop|OP *falseop
+=for apidoc newCONDOP
Constructs, checks, and returns a conditional-expression (C<cond_expr>)
op. C<flags> gives the eight bits of C<op_flags>, except that C<OPf_KIDS>
}
/*
-=for apidoc Am|OP *|newRANGE|I32 flags|OP *left|OP *right
+=for apidoc newRANGE
Constructs and returns a C<range> op, with subordinate C<flip> and
C<flop> ops. C<flags> gives the eight bits of C<op_flags> for the
}
/*
-=for apidoc Am|OP *|newLOOPOP|I32 flags|I32 debuggable|OP *expr|OP *block
+=for apidoc newLOOPOP
Constructs, checks, and returns an op tree expressing a loop. This is
only a loop in the control flow through the op tree; it does not have
))
/* Return the block now, so that S_new_logop does not try to
fold it away. */
- return block; /* do {} while 0 does once */
+ {
+ op_free(expr);
+ return block; /* do {} while 0 does once */
+ }
+
if (expr->op_type == OP_READLINE
|| expr->op_type == OP_READDIR
|| expr->op_type == OP_GLOB
}
/*
-=for apidoc Am|OP *|newWHILEOP|I32 flags|I32 debuggable|LOOP *loop|OP *expr|OP *block|OP *cont|I32 has_my
+=for apidoc newWHILEOP
Constructs, checks, and returns an op tree expressing a C<while> loop.
This is a heavyweight loop, with structure that allows exiting the loop
}
/*
-=for apidoc Am|OP *|newFOROP|I32 flags|OP *sv|OP *expr|OP *block|OP *cont
+=for apidoc newFOROP
Constructs, checks, and returns an op tree expressing a C<foreach>
loop (iteration through a list of values). This is a heavyweight loop,
if (sv->op_type == OP_RV2SV) { /* symbol table variable */
iterpflags = sv->op_private & OPpOUR_INTRO; /* for our $x () */
OpTYPE_set(sv, OP_RV2GV);
+
+ /* The op_type check is needed to prevent a possible segfault
+ * if the loop variable is undeclared and 'strict vars' is in
+ * effect. This is illegal but is nonetheless parsed, so we
+ * may reach this point with an OP_CONST where we're expecting
+ * an OP_GV.
+ */
+ if (cUNOPx(sv)->op_first->op_type == OP_GV
+ && cGVOPx_gv(cUNOPx(sv)->op_first) == PL_defgv)
+ iterpflags |= OPpITER_DEF;
}
else if (sv->op_type == OP_PADSV) { /* private variable */
iterpflags = sv->op_private & OPpLVAL_INTRO; /* for my $x () */
NOOP;
else
Perl_croak(aTHX_ "Can't use %s for loop variable", PL_op_desc[sv->op_type]);
+ if (padoff) {
+ PADNAME * const pn = PAD_COMPNAME(padoff);
+ const char * const name = PadnamePV(pn);
+
+ if (PadnameLEN(pn) == 2 && name[0] == '$' && name[1] == '_')
+ iterpflags |= OPpITER_DEF;
+ }
}
else {
sv = newGVOP(OP_GV, 0, PL_defgv);
+ iterpflags |= OPpITER_DEF;
}
if (expr->op_type == OP_RV2AV || expr->op_type == OP_PADAV) {
LOOP *tmp;
NewOp(1234,tmp,1,LOOP);
Copy(loop,tmp,1,LISTOP);
-#ifdef PERL_OP_PARENT
assert(loop->op_last->op_sibparent == (OP*)loop);
OpLASTSIB_set(loop->op_last, (OP*)tmp); /*point back to new parent */
-#endif
S_op_destroy(aTHX_ (OP*)loop);
loop = tmp;
}
else if (!loop->op_slabbed)
{
loop = (LOOP*)PerlMemShared_realloc(loop, sizeof(LOOP));
-#ifdef PERL_OP_PARENT
OpLASTSIB_set(loop->op_last, (OP*)loop);
-#endif
}
loop->op_targ = padoff;
wop = newWHILEOP(flags, 1, loop, newOP(OP_ITER, 0), block, cont, 0);
}
/*
-=for apidoc Am|OP *|newLOOPEX|I32 type|OP *label
+=for apidoc newLOOPEX
Constructs, checks, and returns a loop-exiting op (such as C<goto>
or C<last>). C<type> is the opcode. C<label> supplies the parameter
return o;
}
+/* if the condition is a literal array or hash
+ (or @{ ... } etc), make a reference to it.
+ */
+STATIC OP *
+S_ref_array_or_hash(pTHX_ OP *cond)
+{
+ if (cond
+ && (cond->op_type == OP_RV2AV
+ || cond->op_type == OP_PADAV
+ || cond->op_type == OP_RV2HV
+ || cond->op_type == OP_PADHV))
+
+ return newUNOP(OP_REFGEN, 0, op_lvalue(cond, OP_REFGEN));
+
+ else if(cond
+ && (cond->op_type == OP_ASLICE
+ || cond->op_type == OP_KVASLICE
+ || cond->op_type == OP_HSLICE
+ || cond->op_type == OP_KVHSLICE)) {
+
+ /* anonlist now needs a list from this op, was previously used in
+ * scalar context */
+ cond->op_flags &= ~(OPf_WANT_SCALAR | OPf_REF);
+ cond->op_flags |= OPf_WANT_LIST;
+
+ return newANONLIST(op_lvalue(cond, OP_ANONLIST));
+ }
+
+ else
+ return cond;
+}
+
+/* These construct the optree fragments representing given()
+ and when() blocks.
+
+ entergiven and enterwhen are LOGOPs; the op_other pointer
+ points up to the associated leave op. We need this so we
+ can put it in the context and make break/continue work.
+ (Also, of course, pp_enterwhen will jump straight to
+ op_other if the match fails.)
+ */
+
+STATIC OP *
+S_newGIVWHENOP(pTHX_ OP *cond, OP *block,
+ I32 enter_opcode, I32 leave_opcode,
+ PADOFFSET entertarg)
+{
+ dVAR;
+ LOGOP *enterop;
+ OP *o;
+
+ PERL_ARGS_ASSERT_NEWGIVWHENOP;
+ PERL_UNUSED_ARG(entertarg); /* used to indicate targ of lexical $_ */
+
+ enterop = alloc_LOGOP(enter_opcode, block, NULL);
+ enterop->op_targ = 0;
+ enterop->op_private = 0;
+
+ o = newUNOP(leave_opcode, 0, (OP *) enterop);
+
+ if (cond) {
+ /* prepend cond if we have one */
+ op_sibling_splice((OP*)enterop, NULL, 0, scalar(cond));
+
+ o->op_next = LINKLIST(cond);
+ cond->op_next = (OP *) enterop;
+ }
+ else {
+ /* This is a default {} block */
+ enterop->op_flags |= OPf_SPECIAL;
+ o ->op_flags |= OPf_SPECIAL;
+
+ o->op_next = (OP *) enterop;
+ }
+
+ CHECKOP(enter_opcode, enterop); /* Currently does nothing, since
+ entergiven and enterwhen both
+ use ck_null() */
+
+ enterop->op_next = LINKLIST(block);
+ block->op_next = enterop->op_other = o;
+
+ return o;
+}
+
+/* Does this look like a boolean operation? For these purposes
+ a boolean operation is:
+ - a subroutine call [*]
+ - a logical connective
+ - a comparison operator
+ - a filetest operator, with the exception of -s -M -A -C
+ - defined(), exists() or eof()
+ - /$re/ or $foo =~ /$re/
+
+ [*] possibly surprising
+ */
+STATIC bool
+S_looks_like_bool(pTHX_ const OP *o)
+{
+ PERL_ARGS_ASSERT_LOOKS_LIKE_BOOL;
+
+ switch(o->op_type) {
+ case OP_OR:
+ case OP_DOR:
+ return looks_like_bool(cLOGOPo->op_first);
+
+ case OP_AND:
+ {
+ OP* sibl = OpSIBLING(cLOGOPo->op_first);
+ ASSUME(sibl);
+ return (
+ looks_like_bool(cLOGOPo->op_first)
+ && looks_like_bool(sibl));
+ }
+
+ case OP_NULL:
+ case OP_SCALAR:
+ return (
+ o->op_flags & OPf_KIDS
+ && looks_like_bool(cUNOPo->op_first));
+
+ case OP_ENTERSUB:
+
+ case OP_NOT: case OP_XOR:
+
+ case OP_EQ: case OP_NE: case OP_LT:
+ case OP_GT: case OP_LE: case OP_GE:
+
+ case OP_I_EQ: case OP_I_NE: case OP_I_LT:
+ case OP_I_GT: case OP_I_LE: case OP_I_GE:
+
+ case OP_SEQ: case OP_SNE: case OP_SLT:
+ case OP_SGT: case OP_SLE: case OP_SGE:
+
+ case OP_SMARTMATCH:
+
+ case OP_FTRREAD: case OP_FTRWRITE: case OP_FTREXEC:
+ case OP_FTEREAD: case OP_FTEWRITE: case OP_FTEEXEC:
+ case OP_FTIS: case OP_FTEOWNED: case OP_FTROWNED:
+ case OP_FTZERO: case OP_FTSOCK: case OP_FTCHR:
+ case OP_FTBLK: case OP_FTFILE: case OP_FTDIR:
+ case OP_FTPIPE: case OP_FTLINK: case OP_FTSUID:
+ case OP_FTSGID: case OP_FTSVTX: case OP_FTTTY:
+ case OP_FTTEXT: case OP_FTBINARY:
+
+ case OP_DEFINED: case OP_EXISTS:
+ case OP_MATCH: case OP_EOF:
+
+ 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 */
+ if (cSVOPo->op_sv == &PL_sv_yes
+ || cSVOPo->op_sv == &PL_sv_no)
+
+ return TRUE;
+ else
+ return FALSE;
+ /* FALLTHROUGH */
+ default:
+ return FALSE;
+ }
+}
+
/*
-=for apidoc Am|OP *|newGIVENOP|OP *cond|OP *block|PADOFFSET defsv_off
+=for apidoc newGIVENOP
Constructs, checks, and returns an op tree expressing a C<given> block.
C<cond> supplies the expression to whose value C<$_> will be locally
OP *
Perl_newGIVENOP(pTHX_ OP *cond, OP *block, PADOFFSET defsv_off)
{
- OP *enterop, *leaveop;
PERL_ARGS_ASSERT_NEWGIVENOP;
PERL_UNUSED_ARG(defsv_off);
- assert(!defsv_off);
- NewOpSz(1101, enterop, sizeof(LOOP));
- OpTYPE_set(enterop, OP_ENTERGIVEN);
- cLOOPx(enterop)->op_first = scalar(cond);
- cLOOPx(enterop)->op_last = block;
- OpMORESIB_set(cond, block);
- OpLASTSIB_set(block, enterop);
- enterop->op_flags = OPf_KIDS;
-
- leaveop = newBINOP(OP_LEAVELOOP, 0, enterop, newOP(OP_NULL, 0));
- leaveop->op_next = LINKLIST(cond);
- cond->op_next = enterop;
- enterop = CHECKOP(OP_ENTERGIVEN, enterop);
- cLOOPx(enterop)->op_redoop = enterop->op_next = LINKLIST(block);
- cLOOPx(enterop)->op_lastop = cLOOPx(enterop)->op_nextop = block->op_next =
- leaveop;
-
- return leaveop;
+ assert(!defsv_off);
+ return newGIVWHENOP(
+ ref_array_or_hash(cond),
+ block,
+ OP_ENTERGIVEN, OP_LEAVEGIVEN,
+ 0);
}
/*
-=for apidoc Am|OP *|newWHERESOOP|OP *cond|OP *block
+=for apidoc newWHENOP
-Constructs, checks, and returns an op tree expressing a C<whereso> block.
+Constructs, checks, and returns an op tree expressing a C<when> block.
C<cond> supplies the test expression, and C<block> supplies the block
that will be executed if the test evaluates to true; they are consumed
-by this function and become part of the constructed op tree.
+by this function and become part of the constructed op tree. C<cond>
+will be interpreted DWIMically, often as a comparison against C<$_>,
+and may be null to generate a C<default> block.
=cut
*/
OP *
-Perl_newWHERESOOP(pTHX_ OP *cond, OP *block)
+Perl_newWHENOP(pTHX_ OP *cond, OP *block)
{
- OP *enterop, *leaveop;
- PERL_ARGS_ASSERT_NEWWHERESOOP;
-
- NewOpSz(1101, enterop, sizeof(LOGOP));
- OpTYPE_set(enterop, OP_ENTERWHERESO);
- cLOGOPx(enterop)->op_first = scalar(cond);
- OpMORESIB_set(cond, block);
- OpLASTSIB_set(block, enterop);
- enterop->op_flags = OPf_KIDS;
-
- leaveop = newUNOP(OP_LEAVEWHERESO, 0, enterop);
- leaveop->op_next = LINKLIST(cond);
- cond->op_next = enterop;
- enterop = CHECKOP(OP_ENTERWHERESO, enterop);
- enterop->op_next = LINKLIST(block);
- cLOGOPx(enterop)->op_other = block->op_next = leaveop;
+ const bool cond_llb = (!cond || looks_like_bool(cond));
+ OP *cond_op;
+
+ PERL_ARGS_ASSERT_NEWWHENOP;
- return leaveop;
+ if (cond_llb)
+ cond_op = cond;
+ else {
+ cond_op = newBINOP(OP_SMARTMATCH, OPf_SPECIAL,
+ newDEFSVOP(),
+ scalar(ref_array_or_hash(cond)));
+ }
+
+ return newGIVWHENOP(cond_op, block, OP_ENTERWHEN, OP_LEAVEWHEN, 0);
}
/* must not conflict with SVf_UTF8 */
if (cv) { /* must reuse cv in case stub is referenced elsewhere */
/* transfer PL_compcv to cv */
if (block) {
+ bool free_file = CvFILE(cv) && CvDYNFILE(cv);
cv_flags_t preserved_flags =
CvFLAGS(cv) & (CVf_BUILTIN_ATTRS|CVf_NAMED);
PADLIST *const temp_padl = CvPADLIST(cv);
CvFLAGS(compcv) &= ~(CVf_SLABBED|CVf_WEAKOUTSIDE);
CvFLAGS(compcv) |= other_flags;
- if (CvFILE(cv) && CvDYNFILE(cv)) {
+ if (free_file) {
Safefree(CvFILE(cv));
+ CvFILE(cv) = NULL;
}
/* inner references to compcv must be fixed up ... */
if (const_sv)
goto clone;
+ if (CvFILE(cv) && CvDYNFILE(cv))
+ Safefree(CvFILE(cv));
CvFILE_set_from_cop(cv, PL_curcop);
CvSTASH_set(cv, PL_curstash);
return cv;
}
+/*
+=for apidoc newATTRSUB_x
+
+Construct a Perl subroutine, also performing some surrounding jobs.
+
+This function is expected to be called in a Perl compilation context,
+and some aspects of the subroutine are taken from global variables
+associated with compilation. In particular, C<PL_compcv> represents
+the subroutine that is currently being compiled. It must be non-null
+when this function is called, and some aspects of the subroutine being
+constructed are taken from it. The constructed subroutine may actually
+be a reuse of the C<PL_compcv> object, but will not necessarily be so.
+
+If C<block> is null then the subroutine will have no body, and for the
+time being it will be an error to call it. This represents a forward
+subroutine declaration such as S<C<sub foo ($$);>>. If C<block> is
+non-null then it provides the Perl code of the subroutine body, which
+will be executed when the subroutine is called. This body includes
+any argument unwrapping code resulting from a subroutine signature or
+similar. The pad use of the code must correspond to the pad attached
+to C<PL_compcv>. The code is not expected to include a C<leavesub> or
+C<leavesublv> op; this function will add such an op. C<block> is consumed
+by this function and will become part of the constructed subroutine.
+
+C<proto> specifies the subroutine's prototype, unless one is supplied
+as an attribute (see below). If C<proto> is null, then the subroutine
+will not have a prototype. If C<proto> is non-null, it must point to a
+C<const> op whose value is a string, and the subroutine will have that
+string as its prototype. If a prototype is supplied as an attribute, the
+attribute takes precedence over C<proto>, but in that case C<proto> should
+preferably be null. In any case, C<proto> is consumed by this function.
+
+C<attrs> supplies attributes to be applied the subroutine. A handful of
+attributes take effect by built-in means, being applied to C<PL_compcv>
+immediately when seen. Other attributes are collected up and attached
+to the subroutine by this route. C<attrs> may be null to supply no
+attributes, or point to a C<const> op for a single attribute, or point
+to a C<list> op whose children apart from the C<pushmark> are C<const>
+ops for one or more attributes. Each C<const> op must be a string,
+giving the attribute name optionally followed by parenthesised arguments,
+in the manner in which attributes appear in Perl source. The attributes
+will be applied to the sub by this function. C<attrs> is consumed by
+this function.
+
+If C<o_is_gv> is false and C<o> is null, then the subroutine will
+be anonymous. If C<o_is_gv> is false and C<o> is non-null, then C<o>
+must point to a C<const> op, which will be consumed by this function,
+and its string value supplies a name for the subroutine. The name may
+be qualified or unqualified, and if it is unqualified then a default
+stash will be selected in some manner. If C<o_is_gv> is true, then C<o>
+doesn't point to an C<OP> at all, but is instead a cast pointer to a C<GV>
+by which the subroutine will be named.
+
+If there is already a subroutine of the specified name, then the new
+sub will either replace the existing one in the glob or be merged with
+the existing one. A warning may be generated about redefinition.
+
+If the subroutine has one of a few special names, such as C<BEGIN> or
+C<END>, then it will be claimed by the appropriate queue for automatic
+running of phase-related subroutines. In this case the relevant glob will
+be left not containing any subroutine, even if it did contain one before.
+In the case of C<BEGIN>, the subroutine will be executed and the reference
+to it disposed of before this function returns.
+
+The function returns a pointer to the constructed subroutine. If the sub
+is anonymous then ownership of one counted reference to the subroutine
+is transferred to the caller. If the sub is named then the caller does
+not get ownership of a reference. In most such cases, where the sub
+has a non-phase name, the sub will be alive at the point it is returned
+by virtue of being contained in the glob that names it. A phase-named
+subroutine will usually be alive by virtue of the reference owned by the
+phase's automatic run queue. But a C<BEGIN> subroutine, having already
+been executed, will quite likely have been destroyed already by the
+time this function returns, making it erroneous for the caller to make
+any use of the returned pointer. It is the caller's responsibility to
+ensure that it knows which of these situations applies.
+
+=cut
+*/
/* _x = extended */
CV *
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;
NULL, name, namlen, name_is_utf8 ? SVf_UTF8 : 0,
const_sv
);
+ assert(cv);
+ assert(SvREFCNT((SV*)cv) != 0);
CvFLAGS(cv) |= CvMETHOD(PL_compcv);
}
else {
if (cv) { /* must reuse cv if autoloaded */
/* transfer PL_compcv to cv */
if (block) {
+ bool free_file = CvFILE(cv) && CvDYNFILE(cv);
cv_flags_t existing_builtin_attrs = CvFLAGS(cv) & CVf_BUILTIN_ATTRS;
PADLIST *const temp_av = CvPADLIST(cv);
CV *const temp_cv = CvOUTSIDE(cv);
CvFLAGS(PL_compcv) &= ~(CVf_SLABBED|CVf_WEAKOUTSIDE);
CvFLAGS(PL_compcv) |= other_flags;
- if (CvFILE(cv) && CvDYNFILE(cv)) {
+ if (free_file) {
Safefree(CvFILE(cv));
}
CvFILE_set_from_cop(cv, PL_curcop);
mro_method_changed_in(PL_curstash);
}
}
+ assert(cv);
+ assert(SvREFCNT((SV*)cv) != 0);
if (!CvHASGV(cv)) {
if (isGV(gv))
process_special_blocks(floor, name, gv, cv);
}
}
+ assert(cv);
done:
+ assert(!cv || evanescent || SvREFCNT((SV*)cv) != 0);
if (PL_parser)
PL_parser->copline = NOLINE;
LEAVE_SCOPE(floor);
+ assert(!cv || evanescent || SvREFCNT((SV*)cv) != 0);
if (!evanescent) {
#ifdef PERL_DEBUG_READONLY_OPS
if (slab)
return FALSE;
} else {
if (*name == 'E') {
- if strEQ(name, "END") {
+ if (strEQ(name, "END")) {
DEBUG_x( dump_sub(gv) );
Perl_av_create_and_unshift_one(aTHX_ &PL_endav, MUTABLE_SV(cv));
} else
/*
=for apidoc newCONSTSUB
-See L</newCONSTSUB_flags>.
+Behaves like L</newCONSTSUB_flags>, except that C<name> is nul-terminated
+rather than of counted length, and no flags are set. (This means that
+C<name> is always interpreted as Latin-1.)
=cut
*/
/*
=for apidoc newCONSTSUB_flags
-Creates a constant sub equivalent to Perl S<C<sub FOO () { 123 }>> which is
-eligible for inlining at compile-time.
-
-Currently, the only useful value for C<flags> is C<SVf_UTF8>.
-
-The newly created subroutine takes ownership of a reference to the passed in
-SV.
-
-Passing C<NULL> for SV creates a constant sub equivalent to S<C<sub BAR () {}>>,
-which won't be called if used as a destructor, but will suppress the overhead
-of a call to C<AUTOLOAD>. (This form, however, isn't eligible for inlining at
-compile time.)
+Construct a constant subroutine, also performing some surrounding
+jobs. A scalar constant-valued subroutine is eligible for inlining
+at compile-time, and in Perl code can be created by S<C<sub FOO () {
+123 }>>. Other kinds of constant subroutine have other treatment.
+
+The subroutine will have an empty prototype and will ignore any arguments
+when called. Its constant behaviour is determined by C<sv>. If C<sv>
+is null, the subroutine will yield an empty list. If C<sv> points to a
+scalar, the subroutine will always yield that scalar. If C<sv> points
+to an array, the subroutine will always yield a list of the elements of
+that array in list context, or the number of elements in the array in
+scalar context. This function takes ownership of one counted reference
+to the scalar or array, and will arrange for the object to live as long
+as the subroutine does. If C<sv> points to a scalar then the inlining
+assumes that the value of the scalar will never change, so the caller
+must ensure that the scalar is not subsequently written to. If C<sv>
+points to an array then no such assumption is made, so it is ostensibly
+safe to mutate the array or its elements, but whether this is really
+supported has not been determined.
+
+The subroutine will have C<CvFILE> set according to C<PL_curcop>.
+Other aspects of the subroutine will be left in their default state.
+The caller is free to mutate the subroutine beyond its initial state
+after this function has returned.
+
+If C<name> is null then the subroutine will be anonymous, with its
+C<CvGV> referring to an C<__ANON__> glob. If C<name> is non-null then the
+subroutine will be named accordingly, referenced by the appropriate glob.
+C<name> is a string of length C<len> bytes giving a sigilless symbol
+name, in UTF-8 if C<flags> has the C<SVf_UTF8> bit set and in Latin-1
+otherwise. The name may be either qualified or unqualified. If the
+name is unqualified then it defaults to being in the stash specified by
+C<stash> if that is non-null, or to C<PL_curstash> if C<stash> is null.
+The symbol is always added to the stash if necessary, with C<GV_ADDMULTI>
+semantics.
+
+C<flags> should not have bits set other than C<SVf_UTF8>.
+
+If there is already a subroutine of the specified name, then the new sub
+will replace the existing one in the glob. A warning may be generated
+about the redefinition.
+
+If the subroutine has one of a few special names, such as C<BEGIN> or
+C<END>, then it will be claimed by the appropriate queue for automatic
+running of phase-related subroutines. In this case the relevant glob will
+be left not containing any subroutine, even if it did contain one before.
+Execution of the subroutine will likely be a no-op, unless C<sv> was
+a tied array or the caller modified the subroutine in some interesting
+way before it was executed. In the case of C<BEGIN>, the treatment is
+buggy: the sub will be executed when only half built, and may be deleted
+prematurely, possibly causing a crash.
+
+The function returns a pointer to the constructed subroutine. If the sub
+is anonymous then ownership of one counted reference to the subroutine
+is transferred to the caller. If the sub is named then the caller does
+not get ownership of a reference. In most such cases, where the sub
+has a non-phase name, the sub will be alive at the point it is returned
+by virtue of being contained in the glob that names it. A phase-named
+subroutine will usually be alive by virtue of the reference owned by
+the phase's automatic run queue. A C<BEGIN> subroutine may have been
+destroyed already by the time this function returns, but currently bugs
+occur in that case before the caller gets control. It is the caller's
+responsibility to ensure that it knows which of these situations applies.
=cut
*/
: const_sv_xsub,
file ? file : "", "",
&sv, XS_DYNAMIC_FILENAME | flags);
+ assert(cv);
+ assert(SvREFCNT((SV*)cv) != 0);
CvXSUBANY(cv).any_ptr = SvREFCNT_inc_simple(sv);
CvCONST_on(cv);
}
/*
-=for apidoc U||newXS
+=for apidoc newXS
Used by C<xsubpp> to hook up XSUBs as Perl subs. C<filename> needs to be
static storage, as it is used directly as CvFILE(), without a copy being made.
);
}
+/*
+=for apidoc newXS_len_flags
+
+Construct an XS subroutine, also performing some surrounding jobs.
+
+The subroutine will have the entry point C<subaddr>. It will have
+the prototype specified by the nul-terminated string C<proto>, or
+no prototype if C<proto> is null. The prototype string is copied;
+the caller can mutate the supplied string afterwards. If C<filename>
+is non-null, it must be a nul-terminated filename, and the subroutine
+will have its C<CvFILE> set accordingly. By default C<CvFILE> is set to
+point directly to the supplied string, which must be static. If C<flags>
+has the C<XS_DYNAMIC_FILENAME> bit set, then a copy of the string will
+be taken instead.
+
+Other aspects of the subroutine will be left in their default state.
+If anything else needs to be done to the subroutine for it to function
+correctly, it is the caller's responsibility to do that after this
+function has constructed it. However, beware of the subroutine
+potentially being destroyed before this function returns, as described
+below.
+
+If C<name> is null then the subroutine will be anonymous, with its
+C<CvGV> referring to an C<__ANON__> glob. If C<name> is non-null then the
+subroutine will be named accordingly, referenced by the appropriate glob.
+C<name> is a string of length C<len> bytes giving a sigilless symbol name,
+in UTF-8 if C<flags> has the C<SVf_UTF8> bit set and in Latin-1 otherwise.
+The name may be either qualified or unqualified, with the stash defaulting
+in the same manner as for C<gv_fetchpvn_flags>. C<flags> may contain
+flag bits understood by C<gv_fetchpvn_flags> with the same meaning as
+they have there, such as C<GV_ADDWARN>. The symbol is always added to
+the stash if necessary, with C<GV_ADDMULTI> semantics.
+
+If there is already a subroutine of the specified name, then the new sub
+will replace the existing one in the glob. A warning may be generated
+about the redefinition. If the old subroutine was C<CvCONST> then the
+decision about whether to warn is influenced by an expectation about
+whether the new subroutine will become a constant of similar value.
+That expectation is determined by C<const_svp>. (Note that the call to
+this function doesn't make the new subroutine C<CvCONST> in any case;
+that is left to the caller.) If C<const_svp> is null then it indicates
+that the new subroutine will not become a constant. If C<const_svp>
+is non-null then it indicates that the new subroutine will become a
+constant, and it points to an C<SV*> that provides the constant value
+that the subroutine will have.
+
+If the subroutine has one of a few special names, such as C<BEGIN> or
+C<END>, then it will be claimed by the appropriate queue for automatic
+running of phase-related subroutines. In this case the relevant glob will
+be left not containing any subroutine, even if it did contain one before.
+In the case of C<BEGIN>, the subroutine will be executed and the reference
+to it disposed of before this function returns, and also before its
+prototype is set. If a C<BEGIN> subroutine would not be sufficiently
+constructed by this function to be ready for execution then the caller
+must prevent this happening by giving the subroutine a different name.
+
+The function returns a pointer to the constructed subroutine. If the sub
+is anonymous then ownership of one counted reference to the subroutine
+is transferred to the caller. If the sub is named then the caller does
+not get ownership of a reference. In most such cases, where the sub
+has a non-phase name, the sub will be alive at the point it is returned
+by virtue of being contained in the glob that names it. A phase-named
+subroutine will usually be alive by virtue of the reference owned by the
+phase's automatic run queue. But a C<BEGIN> subroutine, having already
+been executed, will quite likely have been destroyed already by the
+time this function returns, making it erroneous for the caller to make
+any use of the returned pointer. It is the caller's responsibility to
+ensure that it knows which of these situations applies.
+
+=cut
+*/
+
CV *
Perl_newXS_len_flags(pTHX_ const char *name, STRLEN len,
XSUBADDR_t subaddr, const char *const filename,
{
CV *cv;
bool interleave = FALSE;
+ bool evanescent = FALSE;
PERL_ARGS_ASSERT_NEWXS_LEN_FLAGS;
gv_method_changed(gv); /* newXS */
}
}
+ assert(cv);
+ assert(SvREFCNT((SV*)cv) != 0);
CvGV_set(cv, gv);
if(filename) {
#endif
if (name)
- process_special_blocks(0, name, gv, cv);
+ evanescent = process_special_blocks(0, name, gv, cv);
else
CvANON_on(cv);
} /* <- not a conditional branch */
+ assert(cv);
+ assert(evanescent || SvREFCNT((SV*)cv) != 0);
- sv_setpv(MUTABLE_SV(cv), proto);
+ if (!evanescent) sv_setpv(MUTABLE_SV(cv), proto);
if (interleave) LEAVE;
+ assert(evanescent || SvREFCNT((SV*)cv) != 0);
return cv;
}
+/* Add a stub CV to a typeglob.
+ * This is the implementation of a forward declaration, 'sub foo';'
+ */
+
CV *
Perl_newSTUB(pTHX_ GV *gv, bool fake)
{
OP *newop = NULL;
OP *sibl;
PERL_ARGS_ASSERT_CK_BACKTICK;
+ o = ck_fun(o);
/* qx and `` have a null pushmark; CORE::readpipe has only one kid. */
if (o->op_flags & OPf_KIDS && (sibl = OpSIBLING(cUNOPo->op_first))
&& (gv = gv_override("readpipe",8)))
o->op_private = (U8)(PL_hints & HINT_INTEGER);
- if (o->op_type == OP_NBIT_OR || o->op_type == OP_SBIT_OR
- || o->op_type == OP_NBIT_XOR || o->op_type == OP_SBIT_XOR
- || o->op_type == OP_NBIT_AND || o->op_type == OP_SBIT_AND
- || o->op_type == OP_NCOMPLEMENT || o->op_type == OP_SCOMPLEMENT)
- Perl_ck_warner_d(aTHX_ packWARN(WARN_EXPERIMENTAL__BITWISE),
- "The bitwise feature is experimental");
if (!(o->op_flags & OPf_STACKED) /* Not an assignment */
&& OP_IS_INFIX_BIT(o->op_type))
{
/* reuse the padtmp returned by the concat child */
if (kid->op_type == OP_CONCAT && !(kid->op_private & OPpTARGET_MY) &&
!(kUNOP->op_first->op_flags & OPf_MOD))
+ {
o->op_flags |= OPf_STACKED;
+ o->op_private |= OPpCONCAT_NESTED;
+ }
return o;
}
scalar((OP *) kid);
if ((PL_hints & HINT_FILETEST_ACCESS) && OP_IS_FILETEST_ACCESS(o->op_type))
o->op_private |= OPpFT_ACCESS;
- if (type != OP_STAT && type != OP_LSTAT
- && PL_check[kidtype] == Perl_ck_ftst
- && kidtype != OP_STAT && kidtype != OP_LSTAT
+ if (OP_IS_FILETEST(type)
+ && OP_IS_FILETEST(kidtype)
) {
o->op_private |= OPpFT_STACKED;
kid->op_private |= OPpFT_STACKING;
|| SvTYPE(SvRV(cSVOPx_sv(kid))) != SVt_PVAV )
)
bad_type_pv(numargs, "array", o, kid);
+ else if (kid->op_type == OP_RV2HV || kid->op_type == OP_PADHV
+ || kid->op_type == OP_RV2GV) {
+ bad_type_pv(1, "array", o, kid);
+ }
else if (kid->op_type != OP_RV2AV && kid->op_type != OP_PADAV) {
yyerror_pv(Perl_form(aTHX_ "Experimental %s on scalar is now forbidden",
PL_op_desc[type]), 0);
if (o->op_flags & OPf_KIDS) {
OP *kid = cLISTOPo->op_first;
if (kid->op_type == OP_RV2GV) kid->op_private |= OPpALLOW_FAKE;
+ scalar(kid);
}
else {
OP * const newop
return listkids(o);
}
+OP *
+Perl_ck_smartmatch(pTHX_ OP *o)
+{
+ dVAR;
+ PERL_ARGS_ASSERT_CK_SMARTMATCH;
+ if (0 == (o->op_flags & OPf_SPECIAL)) {
+ OP *first = cBINOPo->op_first;
+ OP *second = OpSIBLING(first);
+
+ /* Implicitly take a reference to an array or hash */
+
+ /* remove the original two siblings, then add back the
+ * (possibly different) first and second sibs.
+ */
+ op_sibling_splice(o, NULL, 1, NULL);
+ op_sibling_splice(o, NULL, 1, NULL);
+ first = ref_array_or_hash(first);
+ second = ref_array_or_hash(second);
+ op_sibling_splice(o, NULL, 0, second);
+ op_sibling_splice(o, NULL, 0, first);
+
+ /* Implicitly take a reference to a regular expression */
+ if (first->op_type == OP_MATCH && !(first->op_flags & OPf_STACKED)) {
+ OpTYPE_set(first, OP_QR);
+ }
+ if (second->op_type == OP_MATCH && !(second->op_flags & OPf_STACKED)) {
+ OpTYPE_set(second, OP_QR);
+ }
+ }
+
+ return o;
+}
+
+
static OP *
S_maybe_targlex(pTHX_ OP *o)
{
OP * const kid = cUNOPx(kidparent)->op_first;
o->op_private |= OPpLVREF_CV;
if (kid->op_type == OP_GV) {
+ SV *sv = (SV*)cGVOPx_gv(kid);
varop = kidparent;
+ if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVCV) {
+ /* a CVREF here confuses pp_refassign, so make sure
+ it gets a GV */
+ CV *const cv = (CV*)SvRV(sv);
+ SV *name_sv = sv_2mortal(newSVhek(CvNAME_HEK(cv)));
+ (void)gv_init_sv((GV*)sv, CvSTASH(cv), name_sv, 0);
+ assert(SvTYPE(sv) == SVt_PVGV);
+ }
goto detach_and_stack;
}
if (kid->op_type != OP_PADCV) goto bad;
*tmpbuf = '&';
assert (len < 256);
Copy(name, tmpbuf+1, len, char);
- off = pad_findmy_pvn(tmpbuf, len+1, SvUTF8(kSVOP_sv));
+ off = pad_findmy_pvn(tmpbuf, len+1, 0);
if (off != NOT_IN_PAD) {
if (PAD_COMPNAME_FLAGS_isOUR(off)) {
SV * const fq =
}
/*
-=for apidoc Am|CV *|rv2cv_op_cv|OP *cvop|U32 flags
+=for apidoc rv2cv_op_cv
Examines an op, which is expected to identify a subroutine at runtime,
and attempts to determine at compile time which subroutine it identifies.
}
/*
-=for apidoc Am|OP *|ck_entersub_args_list|OP *entersubop
+=for apidoc ck_entersub_args_list
Performs the default fixup of the arguments part of an C<entersub>
op tree. This consists of applying list context to each of the
}
/*
-=for apidoc Am|OP *|ck_entersub_args_proto|OP *entersubop|GV *namegv|SV *protosv
+=for apidoc ck_entersub_args_proto
Performs the fixup of the arguments part of an C<entersub> op tree
based on a subroutine prototype. This makes various modifications to
}
/*
-=for apidoc Am|OP *|ck_entersub_args_proto_or_list|OP *entersubop|GV *namegv|SV *protosv
+=for apidoc ck_entersub_args_proto_or_list
Performs the fixup of the arguments part of an C<entersub> op tree either
based on a subroutine prototype or using default list-context processing.
case OA_UNOP:
case OA_BASEOP_OR_UNOP:
case OA_FILESTATOP:
- return aop ? newUNOP(opnum,flags,aop) : newOP(opnum,flags);
+ if (!aop)
+ return newOP(opnum,flags); /* zero args */
+ if (aop == prev)
+ return newUNOP(opnum,flags,aop); /* one arg */
+ /* too many args */
+ /* FALLTHROUGH */
case OA_BASEOP:
if (aop) {
- SV *namesv = cv_name((CV *)namegv, NULL, CV_NAME_NOTQUAL);
+ SV *namesv;
+ OP *nextop;
+
+ namesv = cv_name((CV *)namegv, NULL, CV_NAME_NOTQUAL);
yyerror_pv(Perl_form(aTHX_ "Too many arguments for %" SVf,
SVfARG(namesv)), SvUTF8(namesv));
- op_free(aop);
+ while (aop) {
+ nextop = OpSIBLING(aop);
+ op_free(aop);
+ aop = nextop;
+ }
+
}
return opnum == OP_RUNCV
? newPVOP(OP_RUNCV,0,NULL)
}
/*
-=for apidoc Am|void|cv_get_call_checker_flags|CV *cv|U32 gflags|Perl_call_checker *ckfun_p|SV **ckobj_p|U32 *ckflags_p
+=for apidoc cv_get_call_checker_flags
Retrieves the function that will be used to fix up a call to C<cv>.
Specifically, the function is applied to an C<entersub> op tree for a
only the C<CALL_CHECKER_REQUIRE_GV> bit currently has a defined meaning
(for which see above). All other bits should be clear.
-=for apidoc Am|void|cv_get_call_checker|CV *cv|Perl_call_checker *ckfun_p|SV **ckobj_p
+=for apidoc cv_get_call_checker
The original form of L</cv_get_call_checker_flags>, which does not return
checker flags. When using a checker function returned by this function,
}
/*
-=for apidoc Am|void|cv_set_call_checker_flags|CV *cv|Perl_call_checker ckfun|SV *ckobj|U32 ckflags
+=for apidoc cv_set_call_checker_flags
Sets the function that will be used to fix up a call to C<cv>.
Specifically, the function is applied to an C<entersub> op tree for a
The current setting for a particular CV can be retrieved by
L</cv_get_call_checker_flags>.
-=for apidoc Am|void|cv_set_call_checker|CV *cv|Perl_call_checker ckfun|SV *ckobj
+=for apidoc cv_set_call_checker
The original form of L</cv_set_call_checker_flags>, which passes it the
C<CALL_CHECKER_REQUIRE_GV> flag for backward-compatibility. The effect
if (kid->op_type == OP_NULL)
kid = OpSIBLING(kid);
if (kid)
- op_lvalue(kid, o->op_type);
+ /* Historically, substr(delete $foo{bar},...) has been allowed
+ with 4-arg substr. Keep it working by applying entersub
+ lvalue context. */
+ op_lvalue(kid, OP_ENTERSUB);
}
return o;
* the extra hassle for those edge cases */
break;
- if (pass) {
+ {
UNOP *rop = NULL;
OP * helem_op = o->op_next;
ASSUME( helem_op->op_type == OP_HELEM
- || helem_op->op_type == OP_NULL);
+ || helem_op->op_type == OP_NULL
+ || pass == 0);
if (helem_op->op_type == OP_HELEM) {
rop = (UNOP*)(((BINOP*)helem_op)->op_first);
if ( helem_op->op_private & OPpLVAL_INTRO
)
rop = NULL;
}
- S_check_hash_fields_and_hekify(aTHX_ rop, cSVOPo);
+ /* on first pass just check; on second pass
+ * hekify */
+ S_check_hash_fields_and_hekify(aTHX_ rop, cSVOPo,
+ pass);
+ }
+ if (pass) {
#ifdef USE_ITHREADS
/* Relocate sv to the pad for thread safety */
op_relocate_sv(&cSVOPo->op_sv, &o->op_targ);
/* 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)
#ifdef DEBUGGING
OP *n = o->op_next;
while (n && ( n->op_type == OP_NULL
- || n->op_type == OP_LIST))
+ || n->op_type == OP_LIST
+ || n->op_type == OP_SCALAR))
n = n->op_next;
assert(n && n->op_type == OP_LEAVE);
#endif
o->op_flags &= ~(OPf_REF|OPf_WANT);
o->op_flags |= want;
o->op_private |= (o->op_type == OP_PADHV ?
- OPpRV2HV_ISKEYS : OPpRV2HV_ISKEYS);
+ OPpPADHV_ISKEYS : OPpRV2HV_ISKEYS);
/* for keys(%lex), hold onto the OP_KEYS's targ
* since padhv doesn't have its own targ to return
* an int with */
case OP_ENTERLOOP:
case OP_ENTERITER:
- case OP_ENTERGIVEN:
while (cLOOP->op_redoop->op_type == OP_NULL)
cLOOP->op_redoop = cLOOP->op_redoop->op_next;
while (cLOOP->op_nextop->op_type == OP_NULL)
/*
=head1 Custom Operators
-=for apidoc Ao||custom_op_xop
+=for apidoc custom_op_xop
Return the XOP structure for a given custom op. This macro should be
considered internal to C<OP_NAME> and the other access macros: use them instead.
This macro does call a function. Prior
=cut
*/
+
+/* use PERL_MAGIC_ext to call a function to free the xop structure when
+ * freeing PL_custom_ops */
+
+static int
+custom_op_register_free(pTHX_ SV *sv, MAGIC *mg)
+{
+ XOP *xop;
+
+ PERL_UNUSED_ARG(mg);
+ xop = INT2PTR(XOP *, SvIV(sv));
+ Safefree(xop->xop_name);
+ Safefree(xop->xop_desc);
+ Safefree(xop);
+ return 0;
+}
+
+
+static const MGVTBL custom_op_register_vtbl = {
+ 0, /* get */
+ 0, /* set */
+ 0, /* len */
+ 0, /* clear */
+ custom_op_register_free, /* free */
+ 0, /* copy */
+ 0, /* dup */
+#ifdef MGf_LOCAL
+ 0, /* local */
+#endif
+};
+
+
XOPRETANY
Perl_custom_op_get_field(pTHX_ const OP *o, const xop_flags_enum field)
{
if (PL_custom_ops)
he = hv_fetch_ent(PL_custom_ops, keysv, 0, 0);
- /* assume noone will have just registered a desc */
+ /* See if the op isn't registered, but its name *is* registered.
+ * That implies someone is using the pre-5.14 API,where only name and
+ * description could be registered. If so, fake up a real
+ * registration.
+ * We only check for an existing name, and assume no one will have
+ * just registered a desc */
if (!he && PL_custom_op_names &&
(he = hv_fetch_ent(PL_custom_op_names, keysv, 0, 0))
) {
XopENTRY_set(xop, xop_desc, savepvn(pv, l));
}
Perl_custom_op_register(aTHX_ o->op_ppaddr, xop);
+ he = hv_fetch_ent(PL_custom_ops, keysv, 0, 0);
+ /* add magic to the SV so that the xop struct (pointed to by
+ * SvIV(sv)) is freed. Normally a static xop is registered, but
+ * for this backcompat hack, we've alloced one */
+ (void)sv_magicext(HeVAL(he), NULL, PERL_MAGIC_ext,
+ &custom_op_register_vtbl, NULL, 0);
+
}
else {
if (!he)
}
/*
-=for apidoc Ao||custom_op_register
+=for apidoc custom_op_register
Register a custom op. See L<perlguts/"Custom Operators">.
=cut
Perl_coresub_op(pTHX_ SV * const coreargssv, const int code,
const int opnum)
{
- OP * const argop = newSVOP(OP_COREARGS,0,coreargssv);
+ OP * const argop = (opnum == OP_SELECT && code) ? NULL :
+ newSVOP(OP_COREARGS,0,coreargssv);
OP *o;
PERL_ARGS_ASSERT_CORESUB_OP;
*/
/*
-=for apidoc Am|void|wrap_op_checker|Optype opcode|Perl_check_t new_checker|Perl_check_t *old_checker_p
+=for apidoc wrap_op_checker
Puts a C function into the chain of check functions for a specified op
type. This is the preferred way to manipulate the L</PL_check> array.
XSRETURN(AvFILLp(av)+1);
}
+/* Copy an existing cop->cop_warnings field.
+ * If it's one of the standard addresses, just re-use the address.
+ * This is the e implementation for the DUP_WARNINGS() macro
+ */
+
+STRLEN*
+Perl_dup_warnings(pTHX_ STRLEN* warnings)
+{
+ Size_t size;
+ STRLEN *new_warnings;
+
+ if (warnings == NULL || specialWARN(warnings))
+ return warnings;
+
+ size = sizeof(*warnings) + *warnings;
+
+ new_warnings = (STRLEN*)PerlMemShared_malloc(size);
+ Copy(warnings, new_warnings, size, char);
+ return new_warnings;
+}
/*
* ex: set ts=8 sts=4 sw=4 et: