File Coverage

blib/lib/B/Hooks/OP/Annotation.pm
Criterion Covered Total %
statement 13 13 100.0
branch n/a
condition n/a
subroutine 5 5 100.0
pod 1 1 100.0
total 19 19 100.0


line stmt bran cond sub pod time code
1             package B::Hooks::OP::Annotation;
2              
3 1     1   28291 use 5.008000;
  1         4  
  1         39  
4              
5 1     1   6 use strict;
  1         2  
  1         31  
6 1     1   5 use warnings;
  1         6  
  1         39  
7              
8 1     1   5 use base qw(DynaLoader);
  1         1  
  1         181  
9              
10             our $VERSION = '0.44';
11              
12 1     1 1 256 sub dl_load_flags { 0x01 }
13              
14             __PACKAGE__->bootstrap($VERSION);
15              
16             1;
17              
18             __END__
19              
20             =head1 NAME
21              
22             B::Hooks::OP::Annotation - annotate and delegate hooked OPs
23              
24             =head1 SYNOPSIS
25              
26             #include "hook_op_check.h"
27             #include "hook_op_annotation.h"
28              
29             STATIC OPAnnotationGroup MYMODULE_ANNOTATIONS;
30              
31             STATIC void mymodule_mydata_free(pTHX_ void *mydata) {
32             // ...
33             }
34              
35             STATIC OP * mymodule_check_entersub(pTHX_ OP *op, void *unused) {
36             MyData * mydata;
37              
38             mydata = mymodule_get_mydata(); /* metadata to be associated with this OP */
39             op_annotate(MYMODULE_ANNOTATIONS, op, mydata, mymodule_mydata_free);
40             op->op_ppaddr = mymodule_entersub;
41              
42             return op;
43             }
44              
45             STATIC OP * mymodule_entersub(pTHX) {
46             OPAnnotation * annotation;
47             MyData * mydata;
48             OP *op = PL_op;
49              
50             annotation = op_annotation_get(MYMODULE_ANNOTATIONS, op);
51             mydata = (MyData *)annotation->data;
52              
53             // ...
54              
55             if (ok) {
56             return NORMAL;
57             } else if (mymodule_stop_hooking(op)) { /* restore the previous op_ppaddr */
58             op->op_ppaddr = annotation->op_ppaddr;
59             op_annotation_delete(MYMODULE_ANNOTATIONS, op);
60             return op->op_ppaddr(aTHX);
61             } else {
62             return annotation->op_ppaddr(aTHX); /* delegate to the previous op_ppaddr */
63             }
64             }
65              
66             MODULE = mymodule PACKAGE = mymodule
67              
68             BOOT:
69             MYMODULE_ANNOTATIONS = op_annotation_group_new();
70              
71             void
72             END()
73             CODE:
74             op_annotation_group_free(aTHX_ MYMODULE_ANNOTATIONS);
75              
76             void
77             setup()
78             CODE:
79             mymodule_hook_op_entersub_id = hook_op_check(
80             OP_ENTERSUB,
81             mymodule_check_entersub,
82             NULL
83             );
84              
85             void
86             teardown()
87             CODE:
88             hook_op_check_remove(OP_ENTERSUB, mymodule_hook_op_entersub_id);
89              
90             =head1 DESCRIPTION
91              
92             This module provides a way for XS code that hijacks OP C<op_ppaddr> functions to delegate to (or restore) the previous
93             functions, whether assigned by perl or by another module. Typically this should be used in conjunction with
94             L<B::Hooks::OP::Check|B::Hooks::OP::Check>.
95              
96             C<B::Hooks::OP::Annotation> makes its types and functions available to XS code by means of
97             L<ExtUtils::Depends|ExtUtils::Depends>. Modules that wish to use these exports in their XS code should
98             C<use B::OP::Hooks::Annotation> in the Perl module that loads the XS, and include something like the
99             following in their Makefile.PL:
100              
101             use ExtUtils::MakeMaker;
102             use ExtUtils::Depends;
103              
104             our %XS_PREREQUISITES = (
105             'B::Hooks::OP::Annotation' => '0.44',
106             'B::Hooks::OP::Check' => '0.15',
107             );
108              
109             our %XS_DEPENDENCIES = ExtUtils::Depends->new(
110             'Your::XS::Module',
111             keys(%XS_PREREQUISITES)
112             )->get_makefile_vars();
113              
114             WriteMakefile(
115             NAME => 'Your::XS::Module',
116             VERSION_FROM => 'lib/Your/XS/Module.pm',
117             PREREQ_PM => {
118             'B::Hooks::EndOfScope' => '0.07',
119             %XS_PREREQUISITES
120             },
121             ($ExtUtils::MakeMaker::VERSION >= 6.46 ?
122             (META_MERGE => {
123             configure_requires => {
124             'ExtUtils::Depends' => '0.301',
125             %XS_PREREQUISITES
126             }})
127             : ()
128             ),
129             %XS_DEPENDENCIES,
130             # ...
131             );
132              
133             =head2 TYPES
134              
135             =head3 OPAnnotation
136              
137             This struct contains the metadata associated with a particular OP i.e. the data itself, a destructor
138             for that data, and the C<op_ppaddr> function that was defined when the annotation was created
139             by L<"op_annotate"> or L<"op_annotation_new">.
140              
141             =over
142              
143             =item * C<op_ppaddr>, the OP's previous C<op_ppaddr> function (of type L<"OPAnnotationPPAddr">)
144              
145             =item * C<data>, a C<void *> to metadata that should be associated with the OP
146              
147             =item * C<dtor>, a function (of type L<"OPAnnotationDtor">) used to free the metadata
148              
149             =back
150              
151             The fields are all read/write and can be modified after the annotation has been created.
152              
153             =head3 OPAnnotationGroup
154              
155             Annotations are stored in groups. Multiple groups can be created, and each one manages
156             all of the annotations associated with it.
157              
158             Annotations can be removed from the group and freed by calling L<"op_annotation_delete">,
159             and the group and all its members can be destroyed by calling L<"op_annotation_group_free">.
160              
161             =head3 OPAnnotationPPAddr
162              
163             This typedef corresponds to the type of perl's C<op_ppaddr> functions i.e.
164              
165             typedef OP *(*OPAnnotationPPAddr)(pTHX);
166              
167             =head3 OPAnnotationDtor
168              
169             This is the typedef for the destructor used to free the metadata associated with the OP.
170              
171             typedef void (*OPAnnotationDtor)(pTHX_ void *data);
172              
173             =head2 FUNCTIONS
174              
175             =head3 op_annotation_new
176              
177             This function creates and returns a new OP annotation.
178              
179             It takes an L<"OPAnnotationGroup">, an OP, a pointer to the metadata to be associated with the OP,
180             and a destructor for that data. The data can be NULL and the destructor can be NULL if no cleanup is required.
181              
182             If an annotation has already been assigned for the OP, then it is replaced by the new annotation, and the
183             old annotation is freed, triggering the destruction of its data (if supplied) by its
184             destructor (if supplied).
185              
186             OPAnnotation * op_annotation_new(
187             OPAnnotationGroup group,
188             OP *op,
189             void *data,
190             OPAnnotationDtor dtor
191             );
192              
193             =head3 op_annotate
194              
195             This function is a void version of L<"op_annotation_new"> for cases where the new annotation is
196             not needed.
197              
198             void op_annotate(
199             OPAnnotationGroup group,
200             OP *op,
201             void *data,
202             OPAnnotationDtor dtor
203             );
204              
205             =head3 op_annotation_get
206              
207             This retrieves the annotation associated with the supplied OP. If an annotation has not been
208             assigned for the OP, it raises a fatal exception.
209              
210             OPAnnotation * op_annotation_get(OPAnnotationGroup group, OP *op);
211              
212             =head3 op_annotation_delete
213              
214             This removes the specified annotation from the group and frees its memory. If a destructor was supplied,
215             it is called on the value in the C<data> field (if supplied).
216              
217             void op_annotation_delete(pTHX_ OPAnnotationGroup group, OP *op);
218              
219             =head3 op_annotation_group_new
220              
221             This function creates a new annotation group.
222              
223             OPAnnotationGroup op_annotation_group_new(void);
224              
225             =head3 op_annotation_group_free
226              
227             This function destroys the annotations in an annotation group and frees the memory allocated for the group.
228              
229             void op_annotation_group_free(pTHX_ OPAnnotationGroup group);
230              
231             =head1 EXPORT
232              
233             None by default.
234              
235             =head1 VERSION
236              
237             0.44
238              
239             =head1 SEE ALSO
240              
241             =over
242              
243             =item * L<B::Hooks::OP::Check|B::Hooks::OP::Check>
244              
245             =item * L<B::Hooks::OP::PPAddr|B::Hooks::OP::PPAddr>
246              
247             =back
248              
249             =head1 AUTHOR
250              
251             chocolateboy <chocolate@cpan.org>
252              
253             =head1 COPYRIGHT AND LICENSE
254              
255             Copyright (c) 2009-2011 chocolateboy
256              
257             This module is free software.
258              
259             You may distribute this code under the same terms as Perl itself.
260              
261             =cut