This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
op.c: S_fold_constants_eval can't be inlined
[perl5.git] / op.c
diff --git a/op.c b/op.c
index c04bdc1..a3ad215 100644 (file)
--- a/op.c
+++ b/op.c
@@ -254,6 +254,46 @@ S_new_slab(pTHX_ OPSLAB *head, size_t sz)
     return slab;
 }
 
+/* opslot_size includes the size of the slot header, and an op can't be smaller than BASEOP */
+#define OPSLOT_SIZE_BASE (SIZE_TO_PSIZE(sizeof(OP)) + OPSLOT_HEADER_P)
+#define OPSLOT_SIZE_TO_INDEX(sz) ((sz) - OPSLOT_SIZE_BASE)
+
+#define link_freed_op(slab, o) S_link_freed_op(aTHX_ slab, o)
+static void
+S_link_freed_op(pTHX_ OPSLAB *slab, OP *o) {
+    U16 sz = OpSLOT(o)->opslot_size;
+    U16 index = OPSLOT_SIZE_TO_INDEX(sz);
+
+    assert(sz >= OPSLOT_SIZE_BASE);
+    /* make sure the array is large enough to include ops this large */
+    if (!slab->opslab_freed) {
+        /* we don't have a free list array yet, make a new one */
+        slab->opslab_freed_size = index+1;
+        slab->opslab_freed = (OP**)PerlMemShared_calloc((slab->opslab_freed_size), sizeof(OP*));
+
+        if (!slab->opslab_freed)
+            croak_no_mem();
+    }
+    else if (index >= slab->opslab_freed_size) {
+        /* It's probably not worth doing exponential expansion here, the number of op sizes
+           is small.
+        */
+        /* We already have a list that isn't large enough, expand it */
+        size_t newsize = index+1;
+        OP **p = (OP **)PerlMemShared_realloc(slab->opslab_freed, newsize * sizeof(OP*));
+
+        if (!p)
+            croak_no_mem();
+
+        Zero(p+slab->opslab_freed_size, newsize - slab->opslab_freed_size, OP *);
+
+        slab->opslab_freed = p;
+        slab->opslab_freed_size = newsize;
+    }
+
+    o->op_next = slab->opslab_freed[index];
+    slab->opslab_freed[index] = o;
+}
 
 /* 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.
@@ -300,28 +340,28 @@ Perl_Slab_Alloc(pTHX_ size_t sz)
     opsz = SIZE_TO_PSIZE(sz);
     sz = opsz + OPSLOT_HEADER_P;
 
-    /* The slabs maintain a free list of OPs. In particular, constant folding
+    /* The head slab for each CV maintains a free list of OPs. In particular, constant folding
        will free up OPs, so it makes sense to re-use them where possible. A
        freed up slot is used in preference to a new allocation.  */
-    if (head_slab->opslab_freed) {
-       OP **too = &head_slab->opslab_freed;
-       o = *too;
-        DEBUG_S_warn((aTHX_ "found free op at %p, slab %p, head slab %p",
-            (void*)o,
-            (I32**)OpSLOT(o) - OpSLOT(o)->opslot_offset,
-            (void*)head_slab));
-
-       while (o && OpSLOT(o)->opslot_size < sz) {
-           DEBUG_S_warn((aTHX_ "Alas! too small"));
-           o = *(too = &o->op_next);
-           if (o) { DEBUG_S_warn((aTHX_ "found another free op at %p", (void*)o)); }
-       }
-       if (o) {
+    if (head_slab->opslab_freed &&
+        OPSLOT_SIZE_TO_INDEX(sz) < head_slab->opslab_freed_size) {
+        U16 base_index;
+
+        /* look for a large enough size with any freed ops */
+        for (base_index = OPSLOT_SIZE_TO_INDEX(sz);
+             base_index < head_slab->opslab_freed_size && !head_slab->opslab_freed[base_index];
+             ++base_index) {
+        }
+
+        if (base_index < head_slab->opslab_freed_size) {
+            /* found a freed op */
+            o = head_slab->opslab_freed[base_index];
+
             DEBUG_S_warn((aTHX_ "realloced  op at %p, slab %p, head slab %p",
                 (void*)o,
                 (I32**)OpSLOT(o) - OpSLOT(o)->opslot_offset,
                 (void*)head_slab));
-           *too = o->op_next;
+           head_slab->opslab_freed[base_index] = o->op_next;
            Zero(o, opsz, I32 *);
            o->op_slabbed = 1;
            goto gotit;
@@ -345,8 +385,7 @@ Perl_Slab_Alloc(pTHX_ size_t sz)
            slot = &slab2->opslab_slots;
            INIT_OPSLOT(slab2->opslab_free_space);
            o->op_type = OP_FREED;
-           o->op_next = head_slab->opslab_freed;
-           head_slab->opslab_freed = o;
+            link_freed_op(head_slab, o);
        }
 
        /* Create a new slab.  Make this one twice as big. */
@@ -463,8 +502,7 @@ Perl_Slab_Free(pTHX_ void *op)
     /* If this op is already freed, our refcount will get screwy. */
     assert(o->op_type != OP_FREED);
     o->op_type = OP_FREED;
-    o->op_next = slab->opslab_freed;
-    slab->opslab_freed = o;
+    link_freed_op(slab, o);
     DEBUG_S_warn((aTHX_ "freeing    op at %p, slab %p, head slab %p",
         (void*)o,
         (I32**)OpSLOT(o) - OpSLOT(o)->opslot_offset,
@@ -503,6 +541,7 @@ Perl_opslab_free(pTHX_ OPSLAB *slab)
     PERL_UNUSED_CONTEXT;
     DEBUG_S_warn((aTHX_ "freeing slab %p", (void*)slab));
     assert(slab->opslab_refcnt == 1);
+    PerlMemShared_free(slab->opslab_freed);
     do {
        slab2 = slab->opslab_next;
 #ifdef DEBUGGING
@@ -711,7 +750,7 @@ Perl_allocmy(pTHX_ const char *const name, const STRLEN len, const U32 flags)
 
        if (!(flags & SVf_UTF8 && UTF8_IS_START(name[1]))
         && isASCII(name[1])
-        && (!isPRINT(name[1]) || strchr("\t\n\r\f", name[1]))) {
+        && (!isPRINT(name[1]) || memCHRs("\t\n\r\f", name[1]))) {
            /* diag_listed_as: Can't use global %s in %s */
            yyerror(Perl_form(aTHX_ "Can't use global %c^%c%.*s in %s",
                              name[0], toCTRL(name[1]),
@@ -2915,6 +2954,18 @@ S_maybe_multiconcat(pTHX_ OP *o)
         targetop = OpSIBLING(topop);
         if (!targetop) /* probably some sort of syntax error */
             return;
+
+        /* don't optimise away assign in 'local $foo = ....' */
+        if (   (targetop->op_private & OPpLVAL_INTRO)
+            /* these are the common ops which do 'local', but
+             * not all */
+            && (   targetop->op_type == OP_GVSV
+                || targetop->op_type == OP_RV2SV
+                || targetop->op_type == OP_AELEM
+                || targetop->op_type == OP_HELEM
+                )
+        )
+            return;
     }
     else if (   topop->op_type == OP_CONCAT
              && (topop->op_flags & OPf_STACKED)
@@ -5766,18 +5817,18 @@ Perl_localize(pTHX_ OP *o, I32 lex)
            bool sigil = FALSE;
 
            /* some heuristics to detect a potential error */
-           while (*s && (strchr(", \t\n", *s)))
+           while (*s && (memCHRs(", \t\n", *s)))
                s++;
 
            while (1) {
-               if (*s && (strchr("@$%", *s) || (!lex && *s == '*'))
+               if (*s && (memCHRs("@$%", *s) || (!lex && *s == '*'))
                       && *++s
                       && (isWORDCHAR(*s) || UTF8_IS_CONTINUED(*s))) {
                    s++;
                    sigil = TRUE;
                    while (*s && (isWORDCHAR(*s) || UTF8_IS_CONTINUED(*s)))
                        s++;
-                   while (*s && (strchr(", \t\n", *s)))
+                   while (*s && (memCHRs(", \t\n", *s)))
                        s++;
                }
                else
@@ -5855,9 +5906,10 @@ S_op_integerize(pTHX_ OP *o)
 }
 
 /* This function exists solely to provide a scope to limit
-   setjmp/longjmp() messing with auto variables.
+   setjmp/longjmp() messing with auto variables.  It cannot be inlined because
+   it uses setjmp
  */
-PERL_STATIC_INLINE int
+STATIC int
 S_fold_constants_eval(pTHX) {
     int ret = 0;
     dJMPENV;
@@ -6506,6 +6558,8 @@ is automatically set.  C<first> supplies an optional op to be the direct
 child of the unary op; it is consumed by this function and become part
 of the constructed op tree.
 
+=for apidoc Amnh||OPf_KIDS
+
 =cut
 */
 
@@ -7011,6 +7065,20 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
 
     t_invlist = _new_invlist(1);
 
+    /* Initialize to a single range */
+    t_invlist = _add_range_to_invlist(t_invlist, 0, UV_MAX);
+
+    /* For the first pass, the lhs is partitioned such that the
+     * number of UTF-8 bytes required to represent a code point in each
+     * partition is the same as the number for any other code point in
+     * that partion.  We copy the pre-compiled partion. */
+    len = C_ARRAY_LENGTH(PL_partition_by_byte_length);
+    invlist_extend(t_invlist, len);
+    t_array = invlist_array(t_invlist);
+    Copy(PL_partition_by_byte_length, t_array, len, UV);
+    invlist_set_len(t_invlist, len, *(get_invlist_offset_addr(t_invlist)));
+    Newx(r_map, len + 1, UV);
+
     /* Parse the (potentially adjusted) input, creating the inversion map.
      * This is done in two passes.  The first pass is to determine if the
      * transliteration can be done in place.  The inversion map it creates
@@ -7018,30 +7086,13 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
      * output of the second pass, which starts with a more compact table and
      * allows more ranges to be merged */
     for (pass2 = 0; pass2 < 2; pass2++) {
-
-        /* Initialize to a single range */
-        t_invlist = _add_range_to_invlist(t_invlist, 0, UV_MAX);
-
-        /* In the second pass, we just have the single range */
-
         if (pass2) {
-            len = 1;
-            t_array = invlist_array(t_invlist);
-        }
-        else {
+            /* Initialize to a single range */
+            t_invlist = _add_range_to_invlist(t_invlist, 0, UV_MAX);
 
-            /* But in the first pass, the lhs is partitioned such that the
-             * number of UTF-8 bytes required to represent a code point in each
-             * partition is the same as the number for any other code point in
-             * that partion.  We copy the pre-compiled partion. */
-            len = C_ARRAY_LENGTH(PL_partition_by_byte_length);
-            invlist_extend(t_invlist, len);
+            /* In the second pass, we just have the single range */
+            len = 1;
             t_array = invlist_array(t_invlist);
-            Copy(PL_partition_by_byte_length, t_array, len, UV);
-            invlist_set_len(t_invlist,
-                            len,
-                            *(get_invlist_offset_addr(t_invlist)));
-            Newx(r_map, len + 1, UV);
         }
 
         /* And the mapping of each of the ranges is initialized.  Initially,
@@ -7103,7 +7154,7 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
          * This routine modifies traditional inversion maps to reserve two
          * mappings:
          *
-         *  TR_UNLISTED (or -1) indicates that the no code point in the range
+         *  TR_UNLISTED (or -1) indicates that no code point in the range
          *      is listed in the tr/// searchlist.  At runtime, these are
          *      always passed through unchanged.  In the inversion map, all
          *      points in the range are mapped to -1, instead of increasing,
@@ -7850,13 +7901,14 @@ S_pmtrans(pTHX_ OP *o, OP *expr, OP *repl)
         }
         else {
             /* no more replacement chars than search chars */
+        }
 #endif
 
     }
 
     DEBUG_y(PerlIO_printf(Perl_debug_log,
             "/d=%d, /s=%d, /c=%d, identical=%d, grows=%d,"
-            " use_svop=%d, can_force_utf8=%d,\nexpansion=%g\n",
+            " use_svop=%d, can_force_utf8=%d,\nexpansion=%" NVgf "\n",
             del, squash, complement,
             cBOOL(o->op_private & OPpTRANS_IDENTICAL),
             cBOOL(o->op_private & OPpTRANS_USE_SVOP),
@@ -8017,22 +8069,22 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl, UV flags, I32 floor)
     is_compiletime = 1;
     has_code = 0;
     if (expr->op_type == OP_LIST) {
-        OP *this_o;
-        for (this_o = cLISTOPx(expr)->op_first; this_o; this_o = OpSIBLING(this_o)) {
-            if (this_o->op_type == OP_NULL && (this_o->op_flags & OPf_SPECIAL)) {
+        OP *child;
+        for (child = cLISTOPx(expr)->op_first; child; child = OpSIBLING(child)) {
+            if (child->op_type == OP_NULL && (child->op_flags & OPf_SPECIAL)) {
                 has_code = 1;
-                assert(!this_o->op_next);
-                if (UNLIKELY(!OpHAS_SIBLING(this_o))) {
+                assert(!child->op_next);
+                if (UNLIKELY(!OpHAS_SIBLING(child))) {
                     assert(PL_parser && PL_parser->error_count);
                     /* This can happen with qr/ (?{(^{})/.  Just fake up
                        the op we were expecting to see, to avoid crashing
                        elsewhere.  */
-                    op_sibling_splice(expr, this_o, 0,
+                    op_sibling_splice(expr, child, 0,
                               newSVOP(OP_CONST, 0, &PL_sv_no));
                 }
-                this_o->op_next = OpSIBLING(this_o);
+                child->op_next = OpSIBLING(child);
             }
-            else if (this_o->op_type != OP_CONST && this_o->op_type != OP_PUSHMARK)
+            else if (child->op_type != OP_CONST && child->op_type != OP_PUSHMARK)
             is_compiletime = 0;
         }
     }
@@ -8045,42 +8097,42 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl, UV flags, I32 floor)
      * also, mark any arrays as LIST/REF */
 
     if (expr->op_type == OP_LIST) {
-       OP *o;
-       for (o = cLISTOPx(expr)->op_first; o; o = OpSIBLING(o)) {
+        OP *child;
+        for (child = cLISTOPx(expr)->op_first; child; child = OpSIBLING(child)) {
 
-            if (o->op_type == OP_PADAV || o->op_type == OP_RV2AV) {
-                assert( !(o->op_flags  & OPf_WANT));
+            if (child->op_type == OP_PADAV || child->op_type == OP_RV2AV) {
+                assert( !(child->op_flags  & OPf_WANT));
                 /* push the array rather than its contents. The regex
                  * engine will retrieve and join the elements later */
-                o->op_flags |= (OPf_WANT_LIST | OPf_REF);
+                child->op_flags |= (OPf_WANT_LIST | OPf_REF);
                 continue;
             }
 
-           if (!(o->op_type == OP_NULL && (o->op_flags & OPf_SPECIAL)))
-               continue;
-           o->op_next = NULL; /* undo temporary hack from above */
-           scalar(o);
-           LINKLIST(o);
-           if (cLISTOPo->op_first->op_type == OP_LEAVE) {
-               LISTOP *leaveop = cLISTOPx(cLISTOPo->op_first);
-               /* skip ENTER */
-               assert(leaveop->op_first->op_type == OP_ENTER);
-               assert(OpHAS_SIBLING(leaveop->op_first));
-               o->op_next = OpSIBLING(leaveop->op_first);
-               /* skip leave */
-               assert(leaveop->op_flags & OPf_KIDS);
-               assert(leaveop->op_last->op_next == (OP*)leaveop);
-               leaveop->op_next = NULL; /* stop on last op */
-               op_null((OP*)leaveop);
-           }
-           else {
-               /* skip SCOPE */
-               OP *scope = cLISTOPo->op_first;
-               assert(scope->op_type == OP_SCOPE);
-               assert(scope->op_flags & OPf_KIDS);
-               scope->op_next = NULL; /* stop on last op */
-               op_null(scope);
-           }
+            if (!(child->op_type == OP_NULL && (child->op_flags & OPf_SPECIAL)))
+                continue;
+            child->op_next = NULL; /* undo temporary hack from above */
+            scalar(child);
+            LINKLIST(child);
+            if (cLISTOPx(child)->op_first->op_type == OP_LEAVE) {
+                LISTOP *leaveop = cLISTOPx(cLISTOPx(child)->op_first);
+                /* skip ENTER */
+                assert(leaveop->op_first->op_type == OP_ENTER);
+                assert(OpHAS_SIBLING(leaveop->op_first));
+                child->op_next = OpSIBLING(leaveop->op_first);
+                /* skip leave */
+                assert(leaveop->op_flags & OPf_KIDS);
+                assert(leaveop->op_last->op_next == (OP*)leaveop);
+                leaveop->op_next = NULL; /* stop on last op */
+                op_null((OP*)leaveop);
+            }
+            else {
+                /* skip SCOPE */
+                OP *scope = cLISTOPx(child)->op_first;
+                assert(scope->op_type == OP_SCOPE);
+                assert(scope->op_flags & OPf_KIDS);
+                scope->op_next = NULL; /* stop on last op */
+                op_null(scope);
+            }
 
             /* XXX optimize_optree() must be called on o before
              * CALL_PEEP(), as currently S_maybe_multiconcat() can't
@@ -8090,16 +8142,16 @@ Perl_pmruntime(pTHX_ OP *o, OP *expr, OP *repl, UV flags, I32 floor)
              * 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 */
-           CALL_PEEP(o);
-            S_prune_chain_head(&(o->op_next));
-           if (is_compiletime)
-               /* runtime finalizes as part of finalizing whole tree */
-               finalize_optree(o);
-       }
+            optimize_optree(child);
+
+            /* have to peep the DOs individually as we've removed it from
+             * the op_next chain */
+            CALL_PEEP(child);
+            S_prune_chain_head(&(child->op_next));
+            if (is_compiletime)
+                /* runtime finalizes as part of finalizing whole tree */
+                finalize_optree(child);
+        }
     }
     else if (expr->op_type == OP_PADAV || expr->op_type == OP_RV2AV) {
         assert( !(expr->op_flags  & OPf_WANT));
@@ -8714,6 +8766,10 @@ decremented. In addition, the C<name> argument is modified.
 If C<PERL_LOADMOD_DENY> is set, the module is loaded as if with C<no> rather
 than C<use>.
 
+=for apidoc Amnh||PERL_LOADMOD_DENY
+=for apidoc Amnh||PERL_LOADMOD_NOIMPORT
+=for apidoc Amnh||PERL_LOADMOD_IMPORT_OPS
+
 =cut */
 
 void
@@ -14150,6 +14206,11 @@ referencing GV.  The resulting C<GV*> is cast to C<CV*> to be returned.
 A null pointer is returned as usual if there is no statically-determinable
 subroutine.
 
+=for apidoc Amnh||OPpEARLY_CV
+=for apidoc Amnh||OPpENTERSUB_AMPER
+=for apidoc Amnh||RV2CVOPCV_MARK_EARLY
+=for apidoc Amnh||RV2CVOPCV_RETURN_NAME_GV
+
 =cut
 */
 
@@ -14353,7 +14414,7 @@ Perl_ck_entersub_args_proto(pTHX_ OP *entersubop, GV *namegv, SV *protosv)
                continue;
            case '_':
                /* _ must be at the end */
-               if (proto[1] && !strchr(";@%", proto[1]))
+               if (proto[1] && !memCHRs(";@%", proto[1]))
                    goto oops;
                 /* FALLTHROUGH */
            case '$':
@@ -14726,6 +14787,8 @@ C<gflags> is a bitset passed into C<cv_get_call_checker_flags>, in which
 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 Amnh||CALL_CHECKER_REQUIRE_GV
+
 =for apidoc cv_get_call_checker
 
 The original form of L</cv_get_call_checker_flags>, which does not return
@@ -15749,12 +15812,11 @@ S_maybe_multideref(pTHX_ OP *start, OP *orig_o, UV orig_action, U8 hints)
         bool next_is_hash    = FALSE; /* is the next lookup to be a hash? */
         bool is_last         = FALSE; /* no more derefs to follow */
         bool maybe_aelemfast = FALSE; /* we can replace with aelemfast? */
+        UV action_word       = 0;     /* all actions so far */
         UNOP_AUX_item *arg     = arg_buf;
         UNOP_AUX_item *action_ptr = arg_buf;
 
-        if (pass)
-            action_ptr->uv = 0;
-        arg++;
+        arg++; /* reserve slot for first action word */
 
         switch (action) {
         case MDEREF_HV_gvsv_vivify_rv2hv_helem:
@@ -16145,16 +16207,16 @@ S_maybe_multideref(pTHX_ OP *start, OP *orig_o, UV orig_action, U8 hints)
                     arg--;
             }
 
-            if (pass)
-                action_ptr->uv |= (action << (action_ix * MDEREF_SHIFT));
+            action_word |= (action << (action_ix * MDEREF_SHIFT));
             action_ix++;
             action_count++;
-            /* if there's no space for the next action, create a new slot
+            /* if there's no space for the next action, reserve a new slot
              * for it *before* we start adding args for that action */
             if ((action_ix + 1) * MDEREF_SHIFT > UVSIZE*8) {
-                action_ptr = arg;
                 if (pass)
-                    arg->uv = 0;
+                    action_ptr->uv = action_word;
+                action_word = 0;
+                action_ptr = arg;
                 arg++;
                 action_ix = 0;
             }
@@ -16162,6 +16224,12 @@ S_maybe_multideref(pTHX_ OP *start, OP *orig_o, UV orig_action, U8 hints)
 
         /* success! */
 
+        if (!action_ix)
+            /* slot reserved for next action word not now needed */
+            arg--;
+        else if (pass)
+            action_ptr->uv = action_word;
+
         if (pass) {
             OP *mderef;
             OP *p, *q;