In perl.git, the branch blead has been updated

<http://perl5.git.perl.org/perl.git/commitdiff/a3d47e0d2ac20034d8d96f777e886b55ab96dd0f?hp=fa542f558f44c8c868faa064d630855ce315e339>

- Log -----------------------------------------------------------------
commit a3d47e0d2ac20034d8d96f777e886b55ab96dd0f
Author: syber <[email protected]>
Date:   Thu Aug 28 01:05:41 2014 +0400

    avoid local *f = \&foo resetting the method cache
    
    {
        local *MyClass::func = sub {...}; # LINE A
        ...
    } # LINE B
    
    This example caused global method cache reset at both lines A and B
    because glob_assign_ref and leave_scope thought that GV's GP refcnt was 2
    (because of saving to Save Stack).
    
    Issue has been fixed.
    SAVEt_GVSLOT (on leave_scope) now requires refcnt > 2 to reset cache
    globally).  Additionally, glob_assign_ref when GvINTRO is set temporarily
    decrements gp's refcnt by 1.  This handles all common cases, however there
    are still uncommon use cases when perl still resets cache globally, for
    example:
    
    {
        local *MyClass::func = sub {...}; # OK
        *MyClass::func = sub {...}; # OOPS :(
    } # OK
    or
    {
        local *MyClass::func = sub {...}; # OK
        {
            local *MyClass::func = sub {...}; # OOPS :(
        } # OOPS :(
    } # OK
    
    * OOPS is a line where global cache reset occurs
    * OK - one package cache reset
-----------------------------------------------------------------------

Summary of changes:
 scope.c |  2 +-
 sv.c    | 10 +++++++++-
 2 files changed, 10 insertions(+), 2 deletions(-)

diff --git a/scope.c b/scope.c
index 66589ab..50036d0 100644
--- a/scope.c
+++ b/scope.c
@@ -846,7 +846,7 @@ Perl_leave_scope(pTHX_ I32 base)
            {
                if ((char *)svp < (char *)GvGP(ARG2_GV)
                 || (char *)svp > (char *)GvGP(ARG2_GV) + sizeof(struct gp)
-                || GvREFCNT(ARG2_GV) > 1)
+                || GvREFCNT(ARG2_GV) > 2) /* "> 2" to ignore savestack's ref */
                    PL_sub_generation++;
                else mro_method_changed_in(hv);
            }
diff --git a/sv.c b/sv.c
index da21d25..291406e 100644
--- a/sv.c
+++ b/sv.c
@@ -3968,7 +3968,15 @@ S_glob_assign_ref(pTHX_ SV *const dstr, SV *const sstr)
            }
            GvCVGEN(dstr) = 0; /* Switch off cacheness. */
            GvASSUMECV_on(dstr);
-           if(GvSTASH(dstr)) gv_method_changed(dstr); /* sub foo { 1 } sub bar 
{ 2 } *bar = \&foo */
+           if(GvSTASH(dstr)) { /* sub foo { 1 } sub bar { 2 } *bar = \&foo */
+               if (intro && GvREFCNT(dstr) > 1) {
+                   /* temporary remove extra savestack's ref */
+                   --GvREFCNT(dstr);
+                   gv_method_changed(dstr);
+                   ++GvREFCNT(dstr);
+               }
+               else gv_method_changed(dstr);
+           }
        }
        *location = SvREFCNT_inc_simple_NN(sref);
        if (import_flag && !(GvFLAGS(dstr) & import_flag)

--
Perl5 Master Repository

Reply via email to