Initial Commit

This commit is contained in:
Riley Schneider
2025-12-03 16:38:10 +01:00
parent c5e26bf594
commit b732d8d4b5
17680 changed files with 5977495 additions and 2 deletions

View File

@@ -0,0 +1,177 @@
package B::Hooks::EndOfScope; # git description: 0.23-2-ga391106
# ABSTRACT: Execute code after a scope finished compilation
# KEYWORDS: code hooks execution scope
use strict;
use warnings;
our $VERSION = '0.24';
use 5.006001;
BEGIN {
use Module::Implementation 0.05;
Module::Implementation::build_loader_sub(
implementations => [ 'XS', 'PP' ],
symbols => [ 'on_scope_end' ],
)->();
}
use Sub::Exporter::Progressive 0.001006 -setup => {
exports => [ 'on_scope_end' ],
groups => { default => ['on_scope_end'] },
};
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
B::Hooks::EndOfScope - Execute code after a scope finished compilation
=head1 VERSION
version 0.24
=head1 SYNOPSIS
on_scope_end { ... };
=head1 DESCRIPTION
This module allows you to execute code when perl finished compiling the
surrounding scope.
=head1 FUNCTIONS
=head2 on_scope_end
on_scope_end { ... };
on_scope_end $code;
Registers C<$code> to be executed after the surrounding scope has been
compiled.
This is exported by default. See L<Sub::Exporter> on how to customize it.
=head1 LIMITATIONS
=head2 Pure-perl mode caveat
This caveat applies to B<any> version of perl where L<Variable::Magic>
is unavailable or otherwise disabled.
While L<Variable::Magic> has access to some very dark sorcery to make it
possible to throw an exception from within a callback, the pure-perl
implementation does not have access to these hacks. Therefore, what
would have been a B<compile-time exception> is instead B<converted to a
warning>, and your execution will continue as if the exception never
happened.
To explicitly request an XS (or PP) implementation one has two choices. Either
to import from the desired implementation explicitly:
use B::Hooks::EndOfScope::XS
or
use B::Hooks::EndOfScope::PP
or by setting C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> to either C<XS> or
C<PP>.
=head2 Perl 5.8.0 ~ 5.8.3
Due to a L<core interpreter bug
|https://rt.perl.org/Public/Bug/Display.html?id=27040#txn-82797> present in
older perl versions, the implementation of B::Hooks::EndOfScope deliberately
leaks a single empty hash for every scope being cleaned. This is done to
avoid the memory corruption associated with the bug mentioned above.
In order to stabilize this workaround use of L<Variable::Magic> is disabled
on perls prior to version 5.8.4. On such systems loading/requesting
L<B::Hooks::EndOfScope::XS> explicitly will result in a compile-time
exception.
=head2 Perl versions 5.6.x
Versions of perl before 5.8.0 lack a feature allowing changing the visibility
of C<%^H> via setting bit 17 within C<$^H>. As such the only way to achieve
the effect necessary for this module to work, is to use the C<local> operator
explicitly on these platforms. This might lead to unexpected interference
with other scope-driven libraries relying on the same mechanism. On the flip
side there are no such known incompatibilities at the time this note was
written.
For further details on the unavailable behavior please refer to the test
file F<t/02-localise.t> included with the distribution.
=head1 SEE ALSO
L<Sub::Exporter>
L<Variable::Magic>
=head1 SUPPORT
Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=B-Hooks-EndOfScope>
(or L<bug-B-Hooks-EndOfScope@rt.cpan.org|mailto:bug-B-Hooks-EndOfScope@rt.cpan.org>).
=head1 AUTHORS
=over 4
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Peter Rabbitson <ribasushi@leporine.io>
=back
=head1 CONTRIBUTORS
=for stopwords Karen Etheridge Tatsuhiko Miyagawa Christian Walde Tomas Doran Graham Knop Simon Wilper
=over 4
=item *
Karen Etheridge <ether@cpan.org>
=item *
Tatsuhiko Miyagawa <miyagawa@bulknews.net>
=item *
Christian Walde <walde.christian@googlemail.com>
=item *
Tomas Doran <bobtfish@bobtfish.net>
=item *
Graham Knop <haarg@haarg.org>
=item *
Simon Wilper <sxw@chronowerks.de>
=back
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2008 by Florian Ragwitz.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,110 @@
package B::Hooks::EndOfScope::PP;
# ABSTRACT: Execute code after a scope finished compilation - PP implementation
use warnings;
use strict;
our $VERSION = '0.24';
use constant _PERL_VERSION => "$]";
BEGIN {
if (_PERL_VERSION =~ /^5\.009/) {
# CBA to figure out where %^H got broken and which H::U::HH is sane enough
die "By design B::Hooks::EndOfScope does not operate in pure-perl mode on perl 5.9.X\n"
}
elsif (_PERL_VERSION < '5.010') {
require B::Hooks::EndOfScope::PP::HintHash;
*on_scope_end = \&B::Hooks::EndOfScope::PP::HintHash::on_scope_end;
}
else {
require B::Hooks::EndOfScope::PP::FieldHash;
*on_scope_end = \&B::Hooks::EndOfScope::PP::FieldHash::on_scope_end;
}
}
use Sub::Exporter::Progressive 0.001006 -setup => {
exports => ['on_scope_end'],
groups => { default => ['on_scope_end'] },
};
sub __invoke_callback {
local $@;
eval { $_[0]->(); 1 } or do {
my $err = $@;
require Carp;
Carp::cluck( (join ' ',
'A scope-end callback raised an exception, which can not be propagated when',
'B::Hooks::EndOfScope operates in pure-perl mode. Your program will CONTINUE',
'EXECUTION AS IF NOTHING HAPPENED AFTER THIS WARNING. Below is the complete',
'exception text, followed by a stack-trace of the callback execution:',
) . "\n\n$err\n\r" );
sleep 1 if -t *STDERR; # maybe a bad idea...?
};
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
B::Hooks::EndOfScope::PP - Execute code after a scope finished compilation - PP implementation
=head1 VERSION
version 0.24
=head1 DESCRIPTION
This is the pure-perl implementation of L<B::Hooks::EndOfScope> based only on
modules available as part of the perl core. Its leaner sibling
L<B::Hooks::EndOfScope::XS> will be automatically preferred if all
dependencies are available and C<$ENV{B_HOOKS_ENDOFSCOPE_IMPLEMENTATION}> is
not set to C<'PP'>.
=head1 FUNCTIONS
=head2 on_scope_end
on_scope_end { ... };
on_scope_end $code;
Registers C<$code> to be executed after the surrounding scope has been
compiled.
This is exported by default. See L<Sub::Exporter> on how to customize it.
=head1 SUPPORT
Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=B-Hooks-EndOfScope>
(or L<bug-B-Hooks-EndOfScope@rt.cpan.org|mailto:bug-B-Hooks-EndOfScope@rt.cpan.org>).
=head1 AUTHORS
=over 4
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Peter Rabbitson <ribasushi@leporine.io>
=back
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2008 by Florian Ragwitz.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,45 @@
# Implementation of a pure-perl on_scope_end for perls > 5.10
# (relies on Hash::Util:FieldHash)
package # hide from pause
B::Hooks::EndOfScope::PP::FieldHash;
use strict;
use warnings;
our $VERSION = '0.24';
use Tie::Hash ();
use Hash::Util::FieldHash 'fieldhash';
# Here we rely on a combination of several behaviors:
#
# * %^H is deallocated on scope exit, so any references to it disappear
# * A lost weakref in a fieldhash causes the corresponding key to be deleted
# * Deletion of a key on a tied hash triggers DELETE
#
# Therefore the DELETE of a tied fieldhash containing a %^H reference will
# be the hook to fire all our callbacks.
fieldhash my %hh;
{
package # hide from pause too
B::Hooks::EndOfScope::PP::_TieHintHashFieldHash;
our @ISA = ( 'Tie::StdHash' ); # in Tie::Hash, in core
sub DELETE {
my $ret = shift->SUPER::DELETE(@_);
B::Hooks::EndOfScope::PP::__invoke_callback($_) for @$ret;
$ret;
}
}
sub on_scope_end (&) {
$^H |= 0x020000;
tie(%hh, 'B::Hooks::EndOfScope::PP::_TieHintHashFieldHash')
unless tied %hh;
push @{ $hh{\%^H} ||= [] }, $_[0];
}
1;

View File

@@ -0,0 +1,94 @@
# Implementation of a pure-perl on_scope_end for perls < 5.10
# (relies on lack of compile/runtime duality of %^H before 5.10
# which makes guard object operation possible)
package # hide from the pauses
B::Hooks::EndOfScope::PP::HintHash;
use strict;
use warnings;
our $VERSION = '0.24';
use Scalar::Util ();
use constant _NEEDS_MEMORY_CORRUPTION_FIXUP => (
"$]" >= 5.008
and
"$]" < 5.008004
) ? 1 : 0;
use constant _PERL_VERSION => "$]";
# This is the original implementation, which sadly is broken
# on perl 5.10+ within string evals
sub on_scope_end (&) {
# the scope-implicit %^H localization is a 5.8+ feature
$^H |= 0x020000
if _PERL_VERSION >= 5.008;
# the explicit localization of %^H works on anything < 5.10
# but we use it only on 5.6 where fiddling $^H has no effect
local %^H = %^H
if _PERL_VERSION < 5.008;
# Workaround for memory corruption during implicit $^H-induced
# localization of %^H on 5.8.0~5.8.3, see extended comment below
bless \%^H, 'B::Hooks::EndOfScope::PP::HintHash::__GraveyardTransport' if (
_NEEDS_MEMORY_CORRUPTION_FIXUP
and
ref \%^H eq 'HASH' # only bless if it is a "pure hash" to start with
);
# localised %^H behaves funny on 5.8 - a
# 'local %^H;'
# is in effect the same as
# 'local %^H = %^H;'
# therefore make sure we use different keys so that things do not
# fire too early due to hashkey overwrite
push @{
$^H{sprintf '__B_H_EOS__guardstack_0X%x', Scalar::Util::refaddr(\%^H) }
||= bless ([], 'B::Hooks::EndOfScope::PP::_SG_STACK')
}, $_[0];
}
sub B::Hooks::EndOfScope::PP::_SG_STACK::DESTROY {
B::Hooks::EndOfScope::PP::__invoke_callback($_) for @{$_[0]};
}
# This scope implements a clunky yet effective workaround for a core perl bug
# https://rt.perl.org/Public/Bug/Display.html?id=27040#txn-82797
#
# While we can not prevent the hinthash being marked for destruction twice,
# we *can* intercept the first DESTROY pass, and squirrel away the entire
# structure, until a time it can (hopefully) no longer do any visible harm
#
# There still *will* be corruption by the time we get to free it for real,
# since we can not prevent Perl's erroneous SAVEFREESV mark. What we hope is
# that by then the corruption will no longer matter
#
# Yes, this code does leak by design. Yes it is better than the alternative.
{
my @Hint_Hash_Graveyard;
# "Leak" this entire structure: ensures it and its contents will not be
# garbage collected until the very very very end
push @Hint_Hash_Graveyard, \@Hint_Hash_Graveyard
if _NEEDS_MEMORY_CORRUPTION_FIXUP;
sub B::Hooks::EndOfScope::PP::HintHash::__GraveyardTransport::DESTROY {
# Resurrect the hinthash being destroyed, persist it into the graveyard
push @Hint_Hash_Graveyard, $_[0];
# ensure we won't try to re-resurrect during GlobalDestroy
bless $_[0], 'B::Hooks::EndOfScope::PP::HintHash::__DeactivateGraveyardTransport';
# Perform explicit free of elements (if any) triggering all callbacks
# This is what would have happened without this code being active
%{$_[0]} = ();
}
}
1;

View File

@@ -0,0 +1,108 @@
package B::Hooks::EndOfScope::XS;
# ABSTRACT: Execute code after a scope finished compilation - XS implementation
use strict;
use warnings;
our $VERSION = '0.24';
# Limit the V::M-based (XS) version to perl 5.8.4+
#
# Given the unorthodox stuff we do to work around the hinthash double-free
# might as well play it safe and only implement it in the PP version
# and leave it at that
# https://rt.perl.org/Public/Bug/Display.html?id=27040#txn-82797
#
use 5.008004;
use Variable::Magic 0.48 ();
use Sub::Exporter::Progressive 0.001006 -setup => {
exports => ['on_scope_end'],
groups => { default => ['on_scope_end'] },
};
my $wiz = Variable::Magic::wizard
data => sub { [$_[1]] },
free => sub { $_->() for @{ $_[1] }; () },
# When someone localise %^H, our magic doesn't want to be copied
# down. We want it to be around only for the scope we've initially
# attached ourselves to. Merely having MGf_LOCAL and a noop svt_local
# callback achieves this. If anything wants to attach more magic of our
# kind to a localised %^H, things will continue to just work as we'll be
# attached with a new and empty callback list.
local => \undef
;
sub on_scope_end (&) {
$^H |= 0x020000;
if (my $stack = Variable::Magic::getdata %^H, $wiz) {
push @{ $stack }, $_[0];
}
else {
Variable::Magic::cast %^H, $wiz, $_[0];
}
}
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
B::Hooks::EndOfScope::XS - Execute code after a scope finished compilation - XS implementation
=head1 VERSION
version 0.24
=head1 DESCRIPTION
This is the implementation of L<B::Hooks::EndOfScope> based on
L<Variable::Magic>, which is an XS module dependent on a compiler. It will
always be automatically preferred if L<Variable::Magic> is available.
=head1 FUNCTIONS
=head2 on_scope_end
on_scope_end { ... };
on_scope_end $code;
Registers C<$code> to be executed after the surrounding scope has been
compiled.
This is exported by default. See L<Sub::Exporter> on how to customize it.
=head1 SUPPORT
Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=B-Hooks-EndOfScope>
(or L<bug-B-Hooks-EndOfScope@rt.cpan.org|mailto:bug-B-Hooks-EndOfScope@rt.cpan.org>).
=head1 AUTHORS
=over 4
=item *
Florian Ragwitz <rafl@debian.org>
=item *
Peter Rabbitson <ribasushi@leporine.io>
=back
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2008 by Florian Ragwitz.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,129 @@
use strict;
use warnings;
package B::Hooks::OP::Check; # git description: 0.21-5-g968d5ca
# ABSTRACT: Wrap OP check callbacks
require 5.008001;
use parent qw/DynaLoader/;
our $VERSION = '0.22';
sub dl_load_flags { 0x01 }
__PACKAGE__->bootstrap($VERSION);
1;
__END__
=pod
=encoding UTF-8
=head1 NAME
B::Hooks::OP::Check - Wrap OP check callbacks
=head1 VERSION
version 0.22
=head1 SYNOPSIS
# include "hook_op_check.h"
STATIC OP *my_const_check_op (pTHX_ OP *op, void *user_data) {
/* ... */
return op;
}
STATIC hook_op_check_id my_hook_id = 0;
void
setup ()
CODE:
my_hook_id = hook_op_check (OP_CONST, my_const_check_op, NULL);
void
teardown ()
CODE:
hook_op_check_remove (OP_CONST, my_hook_id);
=head1 DESCRIPTION
This module provides a C API for XS modules to hook into the callbacks of
C<PL_check>.
L<ExtUtils::Depends> is used to export all functions for other XS modules to
use. Include the following in your Makefile.PL:
my $pkg = ExtUtils::Depends->new('Your::XSModule', 'B::Hooks::OP::Check');
WriteMakefile(
... # your normal makefile flags
$pkg->get_makefile_vars,
);
Your XS module can now include C<hook_op_check.h>.
=for stopwords cb
=head1 TYPES
=head2 typedef OP *(*hook_op_check_cb) (pTHX_ OP *, void *);
Type that callbacks need to implement.
=head2 typedef UV hook_op_check_id
Type to identify a callback.
=head1 FUNCTIONS
=head2 hook_op_check_id hook_op_check (opcode type, hook_op_check_cb cb, void *user_data)
Register the callback C<cb> to be called after the C<PL_check> function for
opcodes of the given C<type>. C<user_data> will be passed to the callback as
the last argument. Returns an id that can be used to remove the callback later
on.
=head2 void *hook_op_check_remove (opcode type, hook_op_check_id id)
Remove the callback identified by C<id>. Returns the user_data that the callback had.
=head1 SUPPORT
Bugs may be submitted through L<the RT bug tracker|https://rt.cpan.org/Public/Dist/Display.html?Name=B-Hooks-OP-Check>
(or L<bug-B-Hooks-OP-Check@rt.cpan.org|mailto:bug-B-Hooks-OP-Check@rt.cpan.org>).
=head1 AUTHOR
Florian Ragwitz <rafl@debian.org>
=head1 CONTRIBUTORS
=for stopwords Karen Etheridge Zefram Alexandr Ciornii
=over 4
=item *
Karen Etheridge <ether@cpan.org>
=item *
Zefram <zefram@fysh.org>
=item *
Alexandr Ciornii <alexchorny@gmail.com>
=back
=head1 COPYRIGHT AND LICENCE
This software is copyright (c) 2008 by Florian Ragwitz.
This is free software; you can redistribute it and/or modify it under
the same terms as the Perl 5 programming language system itself.
=cut

View File

@@ -0,0 +1,35 @@
package B::Hooks::OP::Check::Install::Files;
$self = {
'deps' => [],
'inc' => '',
'libs' => '',
'typemaps' => []
};
@deps = @{ $self->{deps} };
@typemaps = @{ $self->{typemaps} };
$libs = $self->{libs};
$inc = $self->{inc};
$CORE = undef;
foreach (@INC) {
if ( -f $_ . "/B/Hooks/OP/Check/Install/Files.pm") {
$CORE = $_ . "/B/Hooks/OP/Check/Install/";
last;
}
}
sub deps { @{ $self->{deps} }; }
sub Inline {
my ($class, $lang) = @_;
if ($lang ne 'C') {
warn "Warning: Inline hints not available for $lang language
";
return;
}
+{ map { (uc($_) => $self->{$_}) } qw(inc libs typemaps) };
}
1;

View File

@@ -0,0 +1,16 @@
#ifndef __HOOK_OP_CHECK_H__
#define __HOOK_OP_CHECK_H__
#include "perl.h"
START_EXTERN_C
typedef UV hook_op_check_id;
typedef OP *(*hook_op_check_cb) (pTHX_ OP *, void *);
hook_op_check_id hook_op_check (opcode type, hook_op_check_cb cb, void *user_data);
void *hook_op_check_remove (opcode type, hook_op_check_id id);
END_EXTERN_C
#endif