{
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
{
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);
}
}
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)