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 |