This is a live mirror of the Perl 5 development currently hosted at https://github.com/perl/perl5
[perl #75176] Symbol::delete_package does not free certain memory associated with...
authorFather Chrysostomos <sprout@cpan.org>
Tue, 9 Nov 2010 03:24:07 +0000 (19:24 -0800)
committerFather Chrysostomos <sprout@cpan.org>
Tue, 9 Nov 2010 03:25:47 +0000 (19:25 -0800)
commit80ebaca223149b3ac705ec4546d4483110daf2d8
tree259d50d0cd37a79907d28d75efd849b14ef84f5f
parent84601d63a7e34958da47dad1e61e27cb3bd467d1
[perl #75176] Symbol::delete_package does not free certain memory associated with package::ISA

This commit makes @ISA changes and package aliasing update PL_isarev
properly, removing old, unnecessary entries in addition to adding new
entries. So now it is capable of shrinking, not just growing.

------------
Gory Details
------------

There is a chicken-and-egg problem when it comes to calling
mro_isa_changed_in on the affected classes: When an isa linearisation
is recalculated, it uses the existing linearisations of the super-
classes (if any) (or at least the DFS implementation does). Since an
assigned package (e.g., the *b:: in *a:: = *b::) can contain nested
packages that inherit from each other in any order (b::c isa b::c::d
or b::c::e isa b::c), this means that mro_isa_changed_in *must not* be
called on any stash while another stash contains stale data.

So mro_package_moved has been restructured. It is no longer recurs-
ive. The recursive code for iterating through nested stashes has been
moved into a separate, static routine: mro_gather_and_rename. Instead
of calling mro_isa_changed_in during the iteration, it adds all the
classes to ‘the big hash’, which mro_package_moved holds a pointer to.
When mro_gather_and_rename returns, mro_package_moved iterates through
the big hash twice: the first time to wipe caches; the second to call
mro_isa_changed_in on all the stashes.

This ‘big hash’ is now used in place of the seen_stashes that
mro_package_moved used before.

Both mro_package_moved and mro_isa_changed_in now use the existing
mrometa->isa hash to determine which classes used to be superclasses
of the stash in question. A separate routine, S_mro_clean_isarev,
deletes entries mention in isa, except for those that still exist in
the new isa hash.

mro_isa_changed_in now does two iterations through isarev, just like
mro_package_moved. It has to call get_linear_isa on the subclasses so
that it can see what is in the new meta->isa hash created thereby.
Consequently, it has to make sure that all the subclasses have their
caches deleted before it can update anything. It makes the same
changes to isarev for each subclass that are made further down on the
class for which mro_isa_changed_in was called. Yes, it is repetitive.
But calling mro_isa_changed_in recursively has more overhead and would
do more unnecessary work. (Maybe we could make some macros for this
repetitive code.)

The loop through the superclasses near the end of mro_isa_changed_in
no longer adds the subclasses to all the superclasses’ isarev hashes,
because that is taken care of further up.

------------
Side Effects
------------

One result of this change is that mro::is_universal no longer
returns true for classes that are no longer universal. I consider
that a bug fix.

-------------
Miscellaneous
-------------

This also removes obsolete comments in mro_isa_changed_in, concerning
fake and universal flags on stashes, that have been invalid since
dd69841bebe.
embed.fnc
embed.h
mro.c
proto.h
t/mro/basic.t
t/mro/isarev.t
t/op/universal.t