B::Hoo...tation(3pm)

πŸ’– NAME πŸ’–

B::Hooks::OP::Annotation β€” annotate and delegate hooked OPs πŸŽ€

okay so bestie, if you're out here hijacking OP op_ppaddr functions in XS and you need a way to hand things back to whoever was there before you? this is literally the module. it's giving "polite takeover" energy. πŸ‘‘


✨ SYNOPSIS ✨

#include "hook_op_check.h"
#include "hook_op_annotation.h"

STATIC OPAnnotationGroup MYMODULE_ANNOTATIONS;

STATIC void mymodule_mydata_free(pTHX_ void *mydata) {
    // ...
}

STATIC OP * mymodule_check_entersub(pTHX_ OP *op, void *unused) {
    MyData * mydata;

    mydata = mymodule_get_mydata(); /* metadata to be associated with this OP */
    op_annotate(MYMODULE_ANNOTATIONS, op, mydata, mymodule_mydata_free);
    op->op_ppaddr = mymodule_entersub;

    return op;
}

STATIC OP * mymodule_entersub(pTHX) {
    OPAnnotation * annotation;
    MyData * mydata;
    OP *op = PL_op;

    annotation = op_annotation_get(MYMODULE_ANNOTATIONS, op);
    mydata = (MyData *)annotation->data;

    // ...

    if (ok) {
        return NORMAL;
    } else if (mymodule_stop_hooking(op)) { /* restore the previous op_ppaddr */
        op->op_ppaddr = annotation->op_ppaddr;
        op_annotation_delete(MYMODULE_ANNOTATIONS, op);
        return op->op_ppaddr(aTHX);
    } else {
        return annotation->op_ppaddr(aTHX); /* delegate to the previous op_ppaddr */
    }
}

MODULE = mymodule PACKAGE = mymodule

BOOT:
    MYMODULE_ANNOTATIONS = op_annotation_group_new();

void
END()
    CODE:
        op_annotation_group_free(aTHX_ MYMODULE_ANNOTATIONS);

void
setup()
    CODE:
        mymodule_hook_op_entersub_id = hook_op_check(
            OP_ENTERSUB,
            mymodule_check_entersub,
            NULL
        );

void
teardown()
    CODE:
        hook_op_check_remove(OP_ENTERSUB, mymodule_hook_op_entersub_id);

🌸 DESCRIPTION 🌸

So here's the tea β˜•: this module gives XS code that hijacks OP op_ppaddr functions a whole system for delegating to (or restoring) the previous functions β€” no matter whether perl itself or some other module put them there. Lowkey essential. Typically you'd use this alongside B::Hooks::OP::Check.

B::Hooks::OP::Annotation hands its types and functions over to your XS code via ExtUtils::Depends. So if your module wants these exports in its XS, you should use B::OP::Hooks::Annotation in the Perl module that loads the XS, and drop something like this into your Makefile.PL:

use ExtUtils::MakeMaker;
use ExtUtils::Depends;

our %XS_PREREQUISITES = (
    'B::Hooks::OP::Annotation' => '0.44',
    'B::Hooks::OP::Check'      => '0.15',
);

our %XS_DEPENDENCIES = ExtUtils::Depends->new(
    'Your::XS::Module',
     keys(%XS_PREREQUISITES)
)->get_makefile_vars();

WriteMakefile(
    NAME          => 'Your::XS::Module',
    VERSION_FROM  => 'lib/Your/XS/Module.pm',
    PREREQ_PM => {
        'B::Hooks::EndOfScope' => '0.07',
        %XS_PREREQUISITES
    },
    ($ExtUtils::MakeMaker::VERSION >= 6.46 ?
        (META_MERGE => {
            configure_requires => {
                'ExtUtils::Depends' => '0.301',
                %XS_PREREQUISITES
            }})
        : ()
    ),
    %XS_DEPENDENCIES,
    # ...
);

πŸ¦‹ TYPES πŸ¦‹

OPAnnotation

This struct is the little stash of metadata tied to one specific OP β€” so like, the data itself, a destructor for that data, and the op_ppaddr function that was set at the moment the annotation got created by op_annotate or op_annotation_new. πŸ’…

  • op_ppaddr β€” the OP's previous op_ppaddr function (of type OPAnnotationPPAddr)
  • data β€” a void * to metadata that should be associated with the OP
  • dtor β€” a function (of type OPAnnotationDtor) used to free the metadata

All of these fields are read/write, meaning you can still change them after the annotation has been created. no lock-in bestie 🫢

OPAnnotationGroup

Annotations live in groups, periodt. You can make as many groups as you want, and each one manages all of the annotations that belong to it.

You can boot an annotation out of the group and free it by calling op_annotation_delete, and you can nuke the group plus every member in it by calling op_annotation_group_free. πŸ’€

OPAnnotationPPAddr

This typedef matches the type of perl's op_ppaddr functions, i.e.

typedef  OP *(*OPAnnotationPPAddr)(pTHX);

OPAnnotationDtor

This is the typedef for the destructor used to free the metadata associated with the OP.

typedef void (*OPAnnotationDtor)(pTHX_ void *data);

🌈 FUNCTIONS 🌈

op_annotation_new

This function creates and returns a brand new OP annotation. ✨

It takes an OPAnnotationGroup, an OP, a pointer to the metadata to be associated with the OP, and a destructor for that data. The data can be NULL and the destructor can be NULL if no cleanup is required.

If an annotation has already been assigned for the OP, then it gets replaced by the new annotation, and the old annotation is freed β€” which triggers the destruction of its data (if supplied) by its destructor (if supplied).

OPAnnotation * op_annotation_new(
    OPAnnotationGroup group,
    OP *op,
    void *data,
    OPAnnotationDtor dtor
);

op_annotate

This one is a void version of op_annotation_new, for when you don't actually need the new annotation back. still iconic tho

void op_annotate(
    OPAnnotationGroup group,
    OP *op,
    void *data,
    OPAnnotationDtor dtor
);

op_annotation_get

This retrieves the annotation associated with the supplied OP. If no annotation has been assigned for that OP, it raises a fatal exception. so like, know before you go πŸ™ˆ

OPAnnotation * op_annotation_get(OPAnnotationGroup group, OP *op);

op_annotation_delete

This removes the specified annotation from the group and frees its memory. If a destructor was supplied, it's called on the value in the data field (if supplied).

void op_annotation_delete(pTHX_ OPAnnotationGroup group, OP *op);

op_annotation_group_new

This function creates a new annotation group. fresh start energy 🌱

OPAnnotationGroup op_annotation_group_new(void);

op_annotation_group_free

This function destroys the annotations in an annotation group and frees the memory allocated for the group.

void op_annotation_group_free(pTHX_ OPAnnotationGroup group);

πŸ‘‘ EXPORT πŸ‘‘

None by default.


⭐ VERSION ⭐

0.44


πŸ”₯ SEE ALSO πŸ”₯

  • B::Hooks::OP::Check
  • B::Hooks::OP::PPAddr

πŸŽ€ AUTHOR πŸŽ€

chocolateboy <chocolate@cpan.org>


Copyright (c) 2009-2011 chocolateboy

This module is free software.

You may distribute this code under the same terms as Perl itself.


k that's the whole page bestie, go forth and annotate responsibly πŸ’–βœ¨πŸ¦‹

perl v5.42.3 · 2026-08-19 · mwah, slay, bye 🫢🌸

πŸ“¦ where this page comes from