This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
Dick Hardt's patch for build on Alpha
[perl5.git] / pp_ctl.c
index 2f3b2b7..36baae5 100644 (file)
--- a/pp_ctl.c
+++ b/pp_ctl.c
@@ -42,7 +42,7 @@ static I32 sortcxix;
 
 PP(pp_wantarray)
 {
-    dSP;
+    djSP;
     I32 cxix;
     EXTEND(SP, 1);
 
@@ -66,7 +66,7 @@ PP(pp_regcmaybe)
 }
 
 PP(pp_regcomp) {
-    dSP;
+    djSP;
     register PMOP *pm = (PMOP*)cLOGOP->op_other;
     register char *t;
     SV *tmpstr;
@@ -103,7 +103,7 @@ PP(pp_regcomp) {
 
 PP(pp_substcont)
 {
-    dSP;
+    djSP;
     register PMOP *pm = (PMOP*) cLOGOP->op_other;
     register CONTEXT *cx = &cxstack[cxstack_ix];
     register SV *dstr = cx->sb_dstr;
@@ -164,9 +164,7 @@ PP(pp_substcont)
 }
 
 void
-rxres_save(rsp, rx)
-void **rsp;
-REGEXP *rx;
+rxres_save(void **rsp, REGEXP *rx)
 {
     UV *p = (UV*)*rsp;
     U32 i;
@@ -194,9 +192,7 @@ REGEXP *rx;
 }
 
 void
-rxres_restore(rsp, rx)
-void **rsp;
-REGEXP *rx;
+rxres_restore(void **rsp, REGEXP *rx)
 {
     UV *p = (UV*)*rsp;
     U32 i;
@@ -216,8 +212,7 @@ REGEXP *rx;
 }
 
 void
-rxres_free(rsp)
-void **rsp;
+rxres_free(void **rsp)
 {
     UV *p = (UV*)*rsp;
 
@@ -230,7 +225,7 @@ void **rsp;
 
 PP(pp_formline)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     register SV *form = *++MARK;
     register U16 *fpc;
     register char *t;
@@ -523,7 +518,7 @@ PP(pp_formline)
 
 PP(pp_grepstart)
 {
-    dSP;
+    djSP;
     SV *src;
 
     if (stack_base + *markstack_ptr == sp) {
@@ -560,7 +555,7 @@ PP(pp_mapstart)
 
 PP(pp_mapwhile)
 {
-    dSP;
+    djSP;
     I32 diff = (sp - stack_base) - *markstack_ptr;
     I32 count;
     I32 shift;
@@ -624,7 +619,7 @@ PP(pp_mapwhile)
 
 PP(pp_sort)
 {
-    dSP; dMARK; dORIGMARK;
+    djSP; dMARK; dORIGMARK;
     register SV **up;
     SV **myorigmark = ORIGMARK;
     register I32 max;
@@ -698,7 +693,7 @@ PP(pp_sort)
            bool oldcatch = CATCH_GET;
 
            SAVETMPS;
-           SAVESPTR(op);
+           SAVEOP();
 
            oldstack = curstack;
            if (!sortstack) {
@@ -724,7 +719,7 @@ PP(pp_sort)
                cx->blk_gimme = G_SCALAR;
                PUSHSUB(cx);
                if (!CvDEPTH(cv))
-                   SvREFCNT_inc(cv);   /* in preparation for POPSUB */
+                   (void)SvREFCNT_inc(cv); /* in preparation for POPSUB */
            }
            sortcxix = cxstack_ix;
 
@@ -758,7 +753,7 @@ PP(pp_range)
 
 PP(pp_flip)
 {
-    dSP;
+    djSP;
 
     if (GIMME == G_ARRAY) {
        RETURNOP(((CONDOP*)cUNOP->op_first)->op_false);
@@ -773,6 +768,7 @@ PP(pp_flip)
            sv_setiv(PAD_SV(cUNOP->op_first->op_targ), 1);
            if (op->op_flags & OPf_SPECIAL) {
                sv_setiv(targ, 1);
+               SETs(targ);
                RETURN;
            }
            else {
@@ -789,7 +785,7 @@ PP(pp_flip)
 
 PP(pp_flop)
 {
-    dSP;
+    djSP;
 
     if (GIMME == G_ARRAY) {
        dPOPPOPssrl;
@@ -846,8 +842,7 @@ PP(pp_flop)
 /* Control. */
 
 static I32
-dopoptolabel(label)
-char *label;
+dopoptolabel(char *label)
 {
     dTHR;
     register I32 i;
@@ -887,14 +882,14 @@ char *label;
 }
 
 I32
-dowantarray()
+dowantarray(void)
 {
     I32 gimme = block_gimme();
     return (gimme == G_VOID) ? G_SCALAR : gimme;
 }
 
 I32
-block_gimme()
+block_gimme(void)
 {
     dTHR;
     I32 cxix;
@@ -904,20 +899,19 @@ block_gimme()
        return G_VOID;
 
     switch (cxstack[cxix].blk_gimme) {
-    case G_VOID:
-       return G_VOID;
     case G_SCALAR:
        return G_SCALAR;
     case G_ARRAY:
        return G_ARRAY;
     default:
        croak("panic: bad gimme: %d\n", cxstack[cxix].blk_gimme);
+    case G_VOID:
+       return G_VOID;
     }
 }
 
 static I32
-dopoptosub(startingblock)
-I32 startingblock;
+dopoptosub(I32 startingblock)
 {
     dTHR;
     I32 i;
@@ -937,8 +931,7 @@ I32 startingblock;
 }
 
 static I32
-dopoptoeval(startingblock)
-I32 startingblock;
+dopoptoeval(I32 startingblock)
 {
     dTHR;
     I32 i;
@@ -957,8 +950,7 @@ I32 startingblock;
 }
 
 static I32
-dopoptoloop(startingblock)
-I32 startingblock;
+dopoptoloop(I32 startingblock)
 {
     dTHR;
     I32 i;
@@ -991,8 +983,7 @@ I32 startingblock;
 }
 
 void
-dounwind(cxix)
-I32 cxix;
+dounwind(I32 cxix)
 {
     dTHR;
     register CONTEXT *cx;
@@ -1025,8 +1016,7 @@ I32 cxix;
 }
 
 OP *
-die_where(message)
-char *message;
+die_where(char *message)
 {
     dTHR;
     if (in_eval) {
@@ -1039,21 +1029,21 @@ char *message;
            SV **svp;
            STRLEN klen = strlen(message);
            
-           svp = hv_fetch(GvHV(errgv), message, klen, TRUE);
+           svp = hv_fetch(errhv, message, klen, TRUE);
            if (svp) {
                if (!SvIOK(*svp)) {
                    static char prefix[] = "\t(in cleanup) ";
                    sv_upgrade(*svp, SVt_IV);
                    (void)SvIOK_only(*svp);
-                   SvGROW(GvSV(errgv), SvCUR(GvSV(errgv))+sizeof(prefix)+klen);
-                   sv_catpvn(GvSV(errgv), prefix, sizeof(prefix)-1);
-                   sv_catpvn(GvSV(errgv), message, klen);
+                   SvGROW(errsv, SvCUR(errsv)+sizeof(prefix)+klen);
+                   sv_catpvn(errsv, prefix, sizeof(prefix)-1);
+                   sv_catpvn(errsv, message, klen);
                }
                sv_inc(*svp);
            }
        }
        else
-           sv_setpv(GvSV(errgv), message);
+           sv_setpv(errsv, message);
        
        cxix = dopoptoeval(cxstack_ix);
        if (cxix >= 0) {
@@ -1076,7 +1066,7 @@ char *message;
            LEAVE;
 
            if (optype == OP_REQUIRE) {
-               char* msg = SvPVx(GvSV(errgv), na);
+               char* msg = SvPV(errsv, na);
                DIE("%s", *msg ? msg : "Compilation failed in require");
            }
            return pop_return();
@@ -1091,7 +1081,7 @@ char *message;
 
 PP(pp_xor)
 {
-    dSP; dPOPTOPssrl;
+    djSP; dPOPTOPssrl;
     if (SvTRUE(left) != SvTRUE(right))
        RETSETYES;
     else
@@ -1100,7 +1090,7 @@ PP(pp_xor)
 
 PP(pp_andassign)
 {
-    dSP;
+    djSP;
     if (!SvTRUE(TOPs))
        RETURN;
     else
@@ -1109,31 +1099,16 @@ PP(pp_andassign)
 
 PP(pp_orassign)
 {
-    dSP;
+    djSP;
     if (SvTRUE(TOPs))
        RETURN;
     else
        RETURNOP(cLOGOP->op_other);
 }
        
-#ifdef DEPRECATED
-PP(pp_entersubr)
-{
-    dSP;
-    SV** mark = (stack_base + *markstack_ptr + 1);
-    SV* cv = *mark;
-    while (mark < sp) {        /* emulate old interface */
-       *mark = mark[1];
-       mark++;
-    }
-    *sp = cv;
-    return pp_entersub(ARGS);
-}
-#endif
-
 PP(pp_caller)
 {
-    dSP;
+    djSP;
     register I32 cxix = dopoptosub(cxstack_ix);
     register CONTEXT *cx;
     I32 dbcxix;
@@ -1229,9 +1204,7 @@ PP(pp_caller)
 }
 
 static int
-sortcv(a, b)
-const void *a;
-const void *b;
+sortcv(const void *a, const void *b)
 {
     dTHR;
     SV * const *str1 = (SV * const *)a;
@@ -1257,69 +1230,20 @@ const void *b;
 }
 
 static int
-sortcmp(a, b)
-const void *a;
-const void *b;
+sortcmp(const void *a, const void *b)
 {
     return sv_cmp(*(SV * const *)a, *(SV * const *)b);
 }
 
 static int
-sortcmp_locale(a, b)
-const void *a;
-const void *b;
+sortcmp_locale(const void *a, const void *b)
 {
     return sv_cmp_locale(*(SV * const *)a, *(SV * const *)b);
 }
 
-#ifdef USE_THREADS
-static void
-unlock_condpair(svv)
-void *svv;
-{
-    dTHR;
-    MAGIC *mg = mg_find((SV*)svv, 'm');
-    
-    if (!mg)
-       croak("panic: unlock_condpair unlocking non-mutex");
-    MUTEX_LOCK(MgMUTEXP(mg));
-    if (MgOWNER(mg) != thr)
-       croak("panic: unlock_condpair unlocking mutex that we don't own");
-    MgOWNER(mg) = 0;
-    COND_SIGNAL(MgOWNERCONDP(mg));
-    MUTEX_UNLOCK(MgMUTEXP(mg));
-}
-#endif /* USE_THREADS */
-
 PP(pp_reset)
 {
-    dSP;
-#ifdef USE_THREADS
-    dTOPss;
-    MAGIC *mg;
-    
-    if (MAXARG < 1)
-       croak("reset requires mutex argument with USE_THREADS");
-    if (SvROK(sv)) {
-       /*
-        * Kludge to allow lock of real objects without requiring
-        * to pass in every type of argument by explicit reference.
-        */
-       sv = SvRV(sv);
-    }
-    mg = condpair_magic(sv);
-    MUTEX_LOCK(MgMUTEXP(mg));
-    if (MgOWNER(mg) == thr)
-       MUTEX_UNLOCK(MgMUTEXP(mg));
-    else {
-       while (MgOWNER(mg))
-           COND_WAIT(MgOWNERCONDP(mg), MgMUTEXP(mg));
-       MgOWNER(mg) = thr;
-       MUTEX_UNLOCK(MgMUTEXP(mg));
-       save_destructor(unlock_condpair, sv);
-    }
-    RETURN;
-#else
+    djSP;
     char *tmps;
 
     if (MAXARG < 1)
@@ -1329,7 +1253,6 @@ PP(pp_reset)
     sv_reset(tmps, curcop->cop_stash);
     PUSHs(&sv_yes);
     RETURN;
-#endif /* USE_THREADS */
 }
 
 PP(pp_lineseq)
@@ -1390,7 +1313,7 @@ PP(pp_scope)
 
 PP(pp_enteriter)
 {
-    dSP; dMARK;
+    djSP; dMARK;
     register CONTEXT *cx;
     I32 gimme = GIMME_V;
     SV **svp;
@@ -1422,7 +1345,7 @@ PP(pp_enteriter)
 
 PP(pp_enterloop)
 {
-    dSP;
+    djSP;
     register CONTEXT *cx;
     I32 gimme = GIMME_V;
 
@@ -1438,7 +1361,7 @@ PP(pp_enterloop)
 
 PP(pp_leaveloop)
 {
-    dSP;
+    djSP;
     register CONTEXT *cx;
     struct block_loop cxloop;
     I32 gimme;
@@ -1479,7 +1402,7 @@ PP(pp_leaveloop)
 
 PP(pp_return)
 {
-    dSP; dMARK;
+    djSP; dMARK;
     I32 cxix;
     register CONTEXT *cx;
     struct block_sub cxsub;
@@ -1555,7 +1478,7 @@ PP(pp_return)
 
 PP(pp_last)
 {
-    dSP;
+    djSP;
     I32 cxix;
     register CONTEXT *cx;
     struct block_loop cxloop;
@@ -1688,11 +1611,7 @@ PP(pp_redo)
 static OP* lastgotoprobe;
 
 static OP *
-dofindlabel(o,label,opstack,oplimit)
-OP *o;
-char *label;
-OP **opstack;
-OP **oplimit;
+dofindlabel(OP *o, char *label, OP **opstack, OP **oplimit)
 {
     OP *kid;
     OP **ops = opstack;
@@ -1741,7 +1660,7 @@ PP(pp_dump)
 
 PP(pp_goto)
 {
-    dSP;
+    djSP;
     OP *retop = 0;
     I32 ix;
     register CONTEXT *cx;
@@ -1788,8 +1707,10 @@ PP(pp_goto)
                EXTEND(stack_sp, items); /* @_ could have been extended. */
                Copy(AvARRAY(av), stack_sp, items, SV*);
                stack_sp += items;
+#ifndef USE_THREADS
                SvREFCNT_dec(GvAV(defgv));
                GvAV(defgv) = cx->blk_sub.savearray;
+#endif /* USE_THREADS */
                AvREAL_off(av);
                av_clear(av);
            }
@@ -1872,15 +1793,34 @@ PP(pp_goto)
                        svp = AvARRAY(padlist);
                    }
                }
+#ifdef USE_THREADS
+               if (!cx->blk_sub.hasargs) {
+                   AV* av = (AV*)curpad[0];
+                   
+                   items = AvFILL(av) + 1;
+                   if (items) {
+                       /* Mark is at the end of the stack. */
+                       EXTEND(sp, items);
+                       Copy(AvARRAY(av), sp + 1, items, SV*);
+                       sp += items;
+                       PUTBACK ;                   
+                   }
+               }
+#endif /* USE_THREADS */               
                SAVESPTR(curpad);
                curpad = AvARRAY((AV*)svp[CvDEPTH(cv)]);
-               if (cx->blk_sub.hasargs) {
+#ifndef USE_THREADS
+               if (cx->blk_sub.hasargs)
+#endif /* USE_THREADS */
+               {
                    AV* av = (AV*)curpad[0];
                    SV** ary;
 
+#ifndef USE_THREADS
                    cx->blk_sub.savearray = GvAV(defgv);
-                   cx->blk_sub.argarray = av;
                    GvAV(defgv) = (AV*)SvREFCNT_inc(av);
+#endif /* USE_THREADS */
+                   cx->blk_sub.argarray = av;
                    ++mark;
 
                    if (items >= AvMAX(av) + 1) {
@@ -1905,7 +1845,7 @@ PP(pp_goto)
                        mark++;
                    }
                }
-               if (perldb && curstash != debstash) {
+               if (PERLDB_SUB && curstash != debstash) {
                    /*
                     * We do not care about using sv to call CV;
                     * it's for informational purposes only.
@@ -1993,6 +1933,11 @@ PP(pp_goto)
            OP *oldop = op;
            for (ix = 1; enterops[ix]; ix++) {
                op = enterops[ix];
+               /* Eventually we may want to stack the needed arguments
+                * for each op.  For now, we punt on the hard ones. */
+               if (op->op_type == OP_ENTERITER)
+                   DIE("Can't \"goto\" into the middle of a foreach loop",
+                       label);
                (*op->op_ppaddr)(ARGS);
            }
            op = oldop;
@@ -2022,7 +1967,7 @@ PP(pp_goto)
 
 PP(pp_exit)
 {
-    dSP;
+    djSP;
     I32 anum;
 
     if (MAXARG < 1)
@@ -2042,7 +1987,7 @@ PP(pp_exit)
 #ifdef NOTYET
 PP(pp_nswitch)
 {
-    dSP;
+    djSP;
     double value = SvNVx(GvSV(cCOP->cop_gv));
     register I32 match = I_32(value);
 
@@ -2061,7 +2006,7 @@ PP(pp_nswitch)
 
 PP(pp_cswitch)
 {
-    dSP;
+    djSP;
     register I32 match;
 
     if (multiline)
@@ -2082,9 +2027,7 @@ PP(pp_cswitch)
 /* Eval. */
 
 static void
-save_lines(array, sv)
-AV *array;
-SV *sv;
+save_lines(AV *array, SV *sv)
 {
     register char *s = SvPVX(sv);
     register char *send = SvPVX(sv) + SvCUR(sv);
@@ -2108,8 +2051,7 @@ SV *sv;
 }
 
 static OP *
-docatch(o)
-OP *o;
+docatch(OP *o)
 {
     dTHR;
     int ret;
@@ -2148,25 +2090,16 @@ OP *o;
     return Nullop;
 }
 
+/* With USE_THREADS, eval_owner must be held on entry to doeval */
 static OP *
-doeval(gimme)
-int gimme;
+doeval(int gimme)
 {
-    dTHR;
     dSP;
     OP *saveop = op;
     HV *newstash;
     CV *caller;
     AV* comppadlist;
 
-#ifdef USE_THREADS
-    MUTEX_LOCK(&eval_mutex);
-    if (eval_owner && eval_owner != thr)
-       while (eval_owner)
-           COND_WAIT(&eval_cond, &eval_mutex);
-    eval_owner = thr;
-    MUTEX_UNLOCK(&eval_mutex);
-#endif /* USE_THREADS */
     in_eval = 1;
 
     PUSHMARK(SP);
@@ -2188,22 +2121,22 @@ int gimme;
     CvUNIQUE_on(compcv);
 #ifdef USE_THREADS
     CvOWNER(compcv) = 0;
-    New(666, CvMUTEXP(compcv), 1, pthread_mutex_t);
+    New(666, CvMUTEXP(compcv), 1, perl_mutex);
     MUTEX_INIT(CvMUTEXP(compcv));
-    New(666, CvCONDP(compcv), 1, pthread_cond_t);
-    COND_INIT(CvCONDP(compcv));
 #endif /* USE_THREADS */
 
     comppad = newAV();
+    av_push(comppad, Nullsv);
+    curpad = AvARRAY(comppad);
     comppad_name = newAV();
     comppad_name_fill = 0;
+    min_intro_pending = 0;
+    padix = 0;
 #ifdef USE_THREADS
     av_store(comppad_name, 0, newSVpv("@_", 2));
+    curpad[0] = (SV*)newAV();
+    SvPADMY_on(curpad[0]);     /* XXX Needed? */
 #endif /* USE_THREADS */
-    min_intro_pending = 0;
-    av_push(comppad, Nullsv);
-    curpad = AvARRAY(comppad);
-    padix = 0;
 
     comppadlist = newAV();
     AvREAL_off(comppadlist);
@@ -2238,7 +2171,7 @@ int gimme;
     if (saveop->op_flags & OPf_SPECIAL)
        in_eval |= 4;
     else
-       sv_setpv(GvSV(errgv),"");
+       sv_setpv(errsv,"");
     if (yyparse() || error_count || !eval_root) {
        SV **newsp;
        I32 gimme;
@@ -2257,11 +2190,17 @@ int gimme;
        lex_end();
        LEAVE;
        if (optype == OP_REQUIRE) {
-           char* msg = SvPVx(GvSV(errgv), na);
+           char* msg = SvPV(errsv, na);
            DIE("%s", *msg ? msg : "Compilation failed in require");
        }
        SvREFCNT_dec(rs);
        rs = SvREFCNT_inc(nrs);
+#ifdef USE_THREADS
+       MUTEX_LOCK(&eval_mutex);
+       eval_owner = 0;
+       COND_SIGNAL(&eval_cond);
+       MUTEX_UNLOCK(&eval_mutex);
+#endif /* USE_THREADS */
        RETPUSHUNDEF;
     }
     SvREFCNT_dec(rs);
@@ -2278,7 +2217,7 @@ int gimme;
     DEBUG_x(dump_eval());
 
     /* Register with debugger: */
-    if (perldb && saveop->op_type == OP_REQUIRE) {
+    if (PERLDB_INTER && saveop->op_type == OP_REQUIRE) {
        CV *cv = perl_get_cv("DB::postponed", FALSE);
        if (cv) {
            dSP;
@@ -2293,6 +2232,7 @@ int gimme;
 
     CvDEPTH(compcv) = 1;
     SP = stack_base + POPMARK;         /* pop original mark */
+    op = saveop;                                       /* The caller may need it. */
 #ifdef USE_THREADS
     MUTEX_LOCK(&eval_mutex);
     eval_owner = 0;
@@ -2305,7 +2245,7 @@ int gimme;
 
 PP(pp_require)
 {
-    dSP;
+    djSP;
     register CONTEXT *cx;
     SV *sv;
     char *name;
@@ -2341,6 +2281,9 @@ PP(pp_require)
 #ifdef DOSISH
       || (name[0] && name[1] == ':')
 #endif
+#ifdef WIN32
+      || (name[0] == '\\' && name[1] == '\\')  /* UNC path */
+#endif
 #ifdef VMS
        || (strchr(name,':')  || ((*name == '[' || *name == '<') &&
            (isALNUM(name[1]) || strchr("$-_]>",name[1]))))
@@ -2386,10 +2329,21 @@ PP(pp_require)
     if (!tryrsfp) {
        if (op->op_type == OP_REQUIRE) {
            SV *msg = sv_2mortal(newSVpvf("Can't locate %s in @INC", name));
+           SV *dirmsgsv = NEWSV(0, 0);
+           AV *ar = GvAVn(incgv);
+           I32 i;
            if (instr(SvPVX(msg), ".h "))
                sv_catpv(msg, " (change .h to .ph maybe?)");
            if (instr(SvPVX(msg), ".ph "))
                sv_catpv(msg, " (did you run h2ph?)");
+           sv_catpv(msg, " (@INC contains:");
+           for (i = 0; i <= AvFILL(ar); i++) {
+               char *dir = SvPVx(*av_fetch(ar, i, TRUE), na);
+               sv_setpvf(dirmsgsv, " %s", dir);
+               sv_catsv(msg, dirmsgsv);
+           }
+           sv_catpvn(msg, ")", 1);
+           SvREFCNT_dec(dirmsgsv);
            DIE("%_", msg);
        }
 
@@ -2423,6 +2377,14 @@ PP(pp_require)
     compiling.cop_line = 0;
 
     PUTBACK;
+#ifdef USE_THREADS
+    MUTEX_LOCK(&eval_mutex);
+    if (eval_owner && eval_owner != thr)
+       while (eval_owner)
+           COND_WAIT(&eval_cond, &eval_mutex);
+    eval_owner = thr;
+    MUTEX_UNLOCK(&eval_mutex);
+#endif /* USE_THREADS */
     return DOCATCH(doeval(G_SCALAR));
 }
 
@@ -2433,7 +2395,7 @@ PP(pp_dofile)
 
 PP(pp_entereval)
 {
-    dSP;
+    djSP;
     register CONTEXT *cx;
     dPOPss;
     I32 gimme = GIMME_V, was = sub_generation;
@@ -2472,11 +2434,20 @@ PP(pp_entereval)
 
     /* prepare to compile string */
 
-    if (perldb && curstash != debstash)
+    if (PERLDB_LINE && curstash != debstash)
        save_lines(GvAV(compiling.cop_filegv), linestr);
     PUTBACK;
+#ifdef USE_THREADS
+    MUTEX_LOCK(&eval_mutex);
+    if (eval_owner && eval_owner != thr)
+       while (eval_owner)
+           COND_WAIT(&eval_cond, &eval_mutex);
+    eval_owner = thr;
+    MUTEX_UNLOCK(&eval_mutex);
+#endif /* USE_THREADS */
     ret = doeval(gimme);
-    if (perldb && was != sub_generation) { /* Some subs defined here. */
+    if (PERLDB_INTER && was != sub_generation /* Some subs defined here. */
+       && ret != op->op_next) {        /* Successive compilation. */
        strcpy(safestr, "_<(eval )");   /* Anything fake and short. */
     }
     return DOCATCH(ret);
@@ -2484,7 +2455,7 @@ PP(pp_entereval)
 
 PP(pp_leaveeval)
 {
-    dSP;
+    djSP;
     register SV **mark;
     SV **newsp;
     PMOP *newpm;
@@ -2525,6 +2496,36 @@ PP(pp_leaveeval)
     }
     curpm = newpm;     /* Don't pop $1 et al till now */
 
+    /*
+     * Closures mentioned at top level of eval cannot be referenced
+     * again, and their presence indirectly causes a memory leak.
+     * (Note that the fact that compcv and friends are still set here
+     * is, AFAIK, an accident.)  --Chip
+     */
+    if (AvFILL(comppad_name) >= 0) {
+       SV **svp = AvARRAY(comppad_name);
+       I32 ix;
+       for (ix = AvFILL(comppad_name); ix >= 0; ix--) {
+           SV *sv = svp[ix];
+           if (sv && sv != &sv_undef && *SvPVX(sv) == '&') {
+               SvREFCNT_dec(sv);
+               svp[ix] = &sv_undef;
+
+               sv = curpad[ix];
+               if (CvCLONE(sv)) {
+                   SvREFCNT_dec(CvOUTSIDE(sv));
+                   CvOUTSIDE(sv) = Nullcv;
+               }
+               else {
+                   SvREFCNT_dec(sv);
+                   sv = NEWSV(0,0);
+                   SvPADTMP_on(sv);
+                   curpad[ix] = sv;
+               }
+           }
+       }
+    }
+
 #ifdef DEBUGGING
     assert(CvDEPTH(compcv) == 1);
 #endif
@@ -2543,14 +2544,14 @@ PP(pp_leaveeval)
     LEAVE;
 
     if (!(save_flags & OPf_SPECIAL))
-       sv_setpv(GvSV(errgv),"");
+       sv_setpv(errsv,"");
 
     RETURNOP(retop);
 }
 
 PP(pp_entertry)
 {
-    dSP;
+    djSP;
     register CONTEXT *cx;
     I32 gimme = GIMME_V;
 
@@ -2563,14 +2564,14 @@ PP(pp_entertry)
     eval_root = op;            /* Only needed so that goto works right. */
 
     in_eval = 1;
-    sv_setpv(GvSV(errgv),"");
+    sv_setpv(errsv,"");
     PUTBACK;
     return DOCATCH(op->op_next);
 }
 
 PP(pp_leavetry)
 {
-    dSP;
+    djSP;
     register SV **mark;
     SV **newsp;
     PMOP *newpm;
@@ -2611,13 +2612,12 @@ PP(pp_leavetry)
     curpm = newpm;     /* Don't pop $1 et al till now */
 
     LEAVE;
-    sv_setpv(GvSV(errgv),"");
+    sv_setpv(errsv,"");
     RETURN;
 }
 
 static void
-doparseform(sv)
-SV *sv;
+doparseform(SV *sv)
 {
     STRLEN len;
     register char *s = SvPV_force(sv, len);
@@ -2793,3 +2793,4 @@ SV *sv;
     sv_magic(sv, Nullsv, 'f', Nullch, 0);
     SvCOMPILED_on(sv);
 }
+