in reply to Re: Intercept any changes to the sv_refcnt/SvREFCNT of an object
in thread Intercept any changes to the sv_refcnt/SvREFCNT of an object

I've looked at those modules and a few others, but they don't touch on what I'm trying to achieve.
I'd like to "hook" into when an object's REFCNT goes up or down anywhere in the program.

The closest I could find was Variable::Magic, but it hooks into a variable not the thing it's referencing and it doesn't have hooks for REFCNTs.

Thanx, though.

  • Comment on Re^2: Intercept any changes to the sv_refcnt/SvREFCNT of an object

Replies are listed 'Best First'.
Re^3: Intercept any changes to the sv_refcnt/SvREFCNT of an object
by Corion (Patriarch) on Sep 13, 2011 at 15:16 UTC

    As incrementing/decrementing the reference count happens (very) often, these are implemented as C macros and not hookable function calls in sv.c:

    #if defined(__GNUC__) && !defined(PERL_GCC_BRACE_GROUPS_FORBIDDEN) # define SvREFCNT_inc(sv) \ ({ \ SV * const _sv = MUTABLE_SV(sv); \ if (_sv) \ (SvREFCNT(_sv))++; \ _sv; \ }) # define SvREFCNT_inc_simple(sv) \ ({ \ if (sv) \ (SvREFCNT(sv))++; \ MUTABLE_SV(sv); \ }) # define SvREFCNT_inc_NN(sv) \ ({ \ SV * const _sv = MUTABLE_SV(sv); \ SvREFCNT(_sv)++; \ _sv; \ }) # define SvREFCNT_inc_void(sv) \ ({ \ SV * const _sv = MUTABLE_SV(sv); \ if (_sv) \ (void)(SvREFCNT(_sv)++); \ }) #else # define SvREFCNT_inc(sv) \ ((PL_Sv=MUTABLE_SV(sv)) ? (++(SvREFCNT(PL_Sv)),PL_Sv) : NULL) # define SvREFCNT_inc_simple(sv) \ ((sv) ? (SvREFCNT(sv)++,MUTABLE_SV(sv)) : NULL) # define SvREFCNT_inc_NN(sv) \ (PL_Sv=MUTABLE_SV(sv),++(SvREFCNT(PL_Sv)),PL_Sv) # define SvREFCNT_inc_void(sv) \ (void)((PL_Sv=MUTABLE_SV(sv)) ? ++(SvREFCNT(PL_Sv)) : 0) #endif

    The "easy" way is to just redefine these macros and recompile Perl. You should be aware that invoking Perl code from within such a hook would be very unwise, as Perl code inevitably will allocate values whose refcount needs to be incremented, which would invoke your hook, recursively.

    This is also the hard way.

      Yep, recompiling perl could make anything possible.
      Unfortunately it's not possible to recompile perl in this case. :-(

Re^3: Intercept any changes to the sv_refcnt/SvREFCNT of an object
by Khen1950fx (Canon) on Sep 13, 2011 at 15:20 UTC
    Clone::Fast has programatic hooks that could be integrated into B. Give that a try.

      Unfortuantely this requires code to call the clone method, so won't work for me.

        I'm probably just as confused as you are, but I had been thinking that, short of modifying the macros, that something like this might help:
        #!/usr/bin/perl -slw use strict; use warnings; use B; use Clone::Fast; use Object::Destroyer; my $ref = {}; print B::svref_2object($ref)->REFCNT; my $copy = Clone::Fast::clone($ref); print B::svref_2object($ref)->REFCNT; my $sentry = Object::Destroyer->new(sub { undef $copy }); print B::svref_2object($ref)->REFCNT;
        Then I ran it using Devel::FindRef:
        #!/usr/bin/perl use strict; use B; use Clone::Fast; use Devel::FindRef; use Scalar::Util; use Object::Destroyer; our $ref = {}; my $global_my = \$ref; our(%global_hash) = (ukukey => \$ref); our(%global_hashref) = {ukukey2 => \$ref}; sub testsub { my $testsub_local = my $global_hashref; print Devel::FindRef::track(\$ref); } my $closure = sub { my $closure_var = \$_[0]; Scalar::Util::weaken (my $weak_ref = \$ref); testsub; }; sub my_ref { my $ref = {}; print B::svref_2object($ref)->REFCNT; my $copy = Clone::Fast::clone($ref); print B::svref_2object($ref)->REFCNT; my $sentry = Object::Destroyer->new(sub {undef $copy}); print B::svref_2object($ref)->REFCNT; testsub; } $closure->($ref);