File Coverage

xs/Function.xs
Criterion Covered Total %
statement 74 86 86.0
branch 84 226 37.1
condition n/a
subroutine n/a
pod n/a
total 158 312 50.6


line stmt bran cond sub pod time code
1             MODULE = FFI::Platypus PACKAGE = FFI::Platypus::Function::Function
2              
3             ffi_pl_function *
4             new(class, platypus, address, abi, var_fixed_args, return_type, ...)
5             const char *class
6             SV *platypus
7             void *address
8             int abi
9             int var_fixed_args
10             ffi_pl_type *return_type
11             PREINIT:
12             ffi_pl_function *self;
13             int i,n,j;
14             SV* arg;
15             void *buffer;
16             ffi_type *ffi_return_type;
17             ffi_type **ffi_argument_types;
18             ffi_status ffi_status;
19             ffi_abi ffi_abi;
20             int extra_arguments;
21             dMY_CXT;
22             CODE:
23             (void)class;
24             #ifndef FFI_PL_PROBE_VARIADIC
25             if(var_fixed_args != -1)
26             {
27             croak("variadic functions are not supported by some combination of your libffi/compiler/platypus");
28             }
29             #endif
30             #ifndef FFI_PL_PROBE_RECORDVALUE
31             if(return_type->type_code == FFI_PL_TYPE_RECORD_VALUE
32             || return_type->type_code == (FFI_PL_TYPE_RECORD_VALUE|FFI_PL_SHAPE_CUSTOM_PERL))
33             {
34             croak("returning record values is not supported by some combination of your libffi/compiler/platypus");
35             }
36             #endif
37 1221 50         ffi_abi = abi == -1 ? FFI_DEFAULT_ABI : abi;
38              
39 2754 100         for(i=0,extra_arguments=0; i<(items-6); i++)
40             {
41             ffi_pl_type *arg_type;
42 1534           arg = ST(i+6);
43 1534 50         if(!(sv_isobject(arg) && sv_derived_from(arg, "FFI::Platypus::Type")))
    50          
44             {
45 0           croak("non-type parameter passed in as type");
46             }
47 1534 50         arg_type = INT2PTR(ffi_pl_type*, SvIV((SV*) SvRV(arg)));
48 1534 100         if(arg_type->type_code == FFI_PL_TYPE_VOID)
49 1           croak("void not allowed as argument type");
50 1533 100         if((arg_type->type_code & FFI_PL_SHAPE_MASK) == FFI_PL_SHAPE_CUSTOM_PERL)
51 121           extra_arguments += arg_type->extra[0].custom_perl.argument_count;
52             }
53              
54 1220           Newx(buffer, (sizeof(ffi_pl_function) + sizeof(ffi_pl_type*)*(items-6+extra_arguments)), char);
55 1220           self = (ffi_pl_function*)buffer;
56 1220 50         Newx(ffi_argument_types, items-6+extra_arguments, ffi_type*);
57              
58             {
59             HV *hv;
60             SV **sv;
61 1220           hv = (HV*) SvRV(platypus);
62 1220           sv = hv_fetch(hv, "api", 3, 0);
63 1220 50         self->platypus_api = SvIV(*sv);
64             }
65              
66 1220           self->address = address;
67 1220           self->return_type = return_type;
68 1220           ffi_return_type = ffi_pl_type_to_libffi_type(return_type);
69              
70 2752 100         for(i=0,n=0; i<(items-6); i++,n++)
71             {
72 1532           arg = ST(i+6);
73 1532 50         self->argument_types[n] = INT2PTR(ffi_pl_type*, SvIV((SV*) SvRV(arg)));
74 1532           ffi_argument_types[n] = ffi_pl_type_to_libffi_type(self->argument_types[n]);
75              
76 1532 100         if((self->argument_types[n]->type_code & FFI_PL_SHAPE_MASK) == FFI_PL_SHAPE_CUSTOM_PERL
77 121 100         && self->argument_types[n]->extra[0].custom_perl.argument_count > 0)
78             {
79 8 100         for(j=1; j-1 < self->argument_types[n]->extra[0].custom_perl.argument_count; j++)
80             {
81 4           self->argument_types[n+j] = self->argument_types[n];
82 4           ffi_argument_types[n+j] = ffi_pl_type_to_libffi_type(self->argument_types[n]);
83             }
84              
85 4           n += self->argument_types[n]->extra[0].custom_perl.argument_count;
86              
87             }
88              
89 1532 100         if(
90 41 100         (self->argument_types[n]->type_code & (FFI_PL_BASE_MASK|FFI_PL_SIZE_MASK)) == FFI_PL_TYPE_LONG_DOUBLE &&
91 27 100         ((self->argument_types[n]->type_code & FFI_PL_SHAPE_MASK) == FFI_PL_SHAPE_POINTER ||
92 27           (self->argument_types[n]->type_code & FFI_PL_SHAPE_MASK) == FFI_PL_SHAPE_ARRAY)
93             )
94             {
95             /*
96             * For historical reasons, we return longdouble pointer and array as Math::LongDouble
97             * if it is installed, but we need to load it when the function is created, not on
98             * the first call
99             */
100 23 100         if(!MY_CXT.loaded_math_longdouble)
101             {
102 2           require_pv("Math/LongDouble.pm");
103 2 50         if(SvTRUE(ERRSV))
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
104             {
105 2           MY_CXT.loaded_math_longdouble = 2;
106             }
107             else
108             {
109 0           MY_CXT.loaded_math_longdouble = 1;
110             }
111             }
112             }
113             }
114              
115 1220 100         if(
116 1220           (return_type->type_code & (FFI_PL_BASE_MASK|FFI_PL_SIZE_MASK)) == FFI_PL_TYPE_LONG_DOUBLE
117             )
118             {
119             /*
120             * For historical reasons, we return longdouble as Math::LongDouble if it is
121             * installed, but we need to load it when the function is created, not on
122             * the first call
123             */
124 18 100         if(!MY_CXT.loaded_math_longdouble)
125             {
126 2           require_pv("Math/LongDouble.pm");
127 2 50         if(SvTRUE(ERRSV))
    50          
    50          
    50          
    0          
    0          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    50          
    50          
    50          
    50          
    50          
    0          
    0          
    0          
    0          
    50          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
    0          
128             {
129 2           MY_CXT.loaded_math_longdouble = 2;
130             }
131             else
132             {
133 0           MY_CXT.loaded_math_longdouble = 1;
134             }
135             }
136             }
137              
138 1220 100         if(var_fixed_args == -1)
139             {
140 1190           ffi_status = ffi_prep_cif(
141             &self->ffi_cif, /* ffi_cif | */
142             ffi_abi, /* ffi_abi | */
143 1190           items-6+extra_arguments, /* int | argument count */
144             ffi_return_type, /* ffi_type * | return type */
145             ffi_argument_types /* ffi_type ** | argument types */
146             );
147             }
148             else
149             {
150             #ifdef FFI_PL_PROBE_VARIADIC
151 30           ffi_status = ffi_prep_cif_var(
152             &self->ffi_cif, /* ffi_cif | */
153             ffi_abi, /* ffi_abi | */
154             var_fixed_args, /* int | fixed argument count */
155 30           items-6+extra_arguments, /* int | total argument count */
156             ffi_return_type, /* ffi_type * | return type */
157             ffi_argument_types /* ffi_type ** | argument types */
158             );
159             #endif
160             }
161              
162 1220 50         if(ffi_status != FFI_OK)
163             {
164 0           Safefree(self);
165 0           Safefree(ffi_argument_types);
166 0 0         if(ffi_status == FFI_BAD_TYPEDEF)
167 0           croak("bad typedef");
168 0 0         else if(ffi_status == FFI_BAD_ABI)
169 0           croak("bad abi");
170             else
171 0           croak("unknown error with ffi_prep_cif");
172             }
173              
174 1220           self->platypus_sv = SvREFCNT_inc_simple_NN(platypus);
175              
176 1220           RETVAL = self;
177             OUTPUT:
178             RETVAL
179              
180             void
181             call(self, ...)
182             ffi_pl_function *self
183             PREINIT:
184             int i, n, perl_arg_index;
185             SV *arg;
186             ffi_pl_arguments *arguments;
187             void **argument_pointers;
188             dMY_CXT;
189             CODE:
190             #define EXTRA_ARGS 1
191             {
192             #include "ffi_platypus_call.h"
193             }
194              
195             void
196             _attach(self, perl_name, path_name, proto)
197             SV *self
198             const char *perl_name
199             ffi_pl_string path_name
200             ffi_pl_string proto
201             PREINIT:
202             CV* cv;
203             int is_ret_rv;
204             ffi_pl_function *f;
205             CODE:
206 867 50         if(!(sv_isobject(self) && sv_derived_from(self, "FFI::Platypus::Function")))
    50          
207 0           croak("self is not of type FFI::Platypus::Function");
208              
209 867 50         f = INT2PTR(ffi_pl_function*, SvIV((SV*) SvRV(self)));
210 867 100         is_ret_rv = (f->return_type->type_code == FFI_PL_TYPE_RECORD_VALUE) ||
    50          
211 866           (f->return_type->type_code == (FFI_PL_TYPE_RECORD_VALUE | FFI_PL_SHAPE_CUSTOM_PERL));
212              
213 867 50         if(path_name == NULL)
214 0           path_name = "unknown";
215              
216 867 100         if(proto == NULL)
217 751 100         cv = newXS(perl_name, is_ret_rv ? ffi_pl_sub_call_rv : ffi_pl_sub_call, path_name);
218             else
219             {
220             /*
221             * this ifdef is needed for Perl 5.8.8 support.
222             * once we don't need to support 5.8.8 we can
223             * remove this workaround (the ndef'd branch)
224             */
225             #ifdef newXS_flags
226 116 50         cv = newXSproto(perl_name, is_ret_rv ? ffi_pl_sub_call_rv : ffi_pl_sub_call, path_name, proto);
227             #else
228             newXSproto(perl_name, is_ret_rv ? ffi_pl_sub_call_rv : ffi_pl_sub_call, path_name, proto);
229             cv = get_cv(perl_name,0);
230             #endif
231             }
232 867           CvXSUBANY(cv).any_ptr = (void *) f;
233             /*
234             * No coresponding decrement !!
235             * once attached, you can never free the function object, or the FFI::Platypus
236             * it was created from.
237             */
238 867           SvREFCNT_inc_simple_void_NN(self);
239              
240             SV*
241             _sub_ref(self, path_name)
242             SV *self
243             ffi_pl_string path_name
244             PREINIT:
245             CV* cv;
246             SV *ref;
247             int is_ret_rv;
248             ffi_pl_function *f;
249             CODE:
250 24 50         f = INT2PTR(ffi_pl_function*, SvIV((SV*) SvRV(self)));
251              
252 24 100         is_ret_rv = (f->return_type->type_code == FFI_PL_TYPE_RECORD_VALUE) ||
    50          
253 23           (f->return_type->type_code == (FFI_PL_TYPE_RECORD_VALUE | FFI_PL_SHAPE_CUSTOM_PERL));
254              
255 24 100         cv = newXS(NULL, is_ret_rv ? ffi_pl_sub_call_rv : ffi_pl_sub_call, path_name);
256 24 50         CvXSUBANY(cv).any_ptr = (void *) INT2PTR(ffi_pl_function*, SvIV((SV*) SvRV(self)));
257             /*
258             * No coresponding decrement !!
259             * once attached, you can never free the function object, or the FFI::Platypus
260             * it was created from.
261             */
262 24           SvREFCNT_inc_simple_void_NN(self);
263 24           RETVAL = newRV_inc((SV*)cv);
264             OUTPUT:
265             RETVAL
266              
267              
268             void
269             DESTROY(self)
270             ffi_pl_function *self
271             CODE:
272 1220           SvREFCNT_dec(self->platypus_sv);
273 1220 100         if(!PL_dirty)
274             {
275 329           Safefree(self->ffi_cif.arg_types);
276 329           Safefree(self);
277             }
278              
279             MODULE = FFI::Platypus PACKAGE = FFI::Platypus::Function::Wrapper
280              
281             void
282             _set_prototype(proto, code)
283             SV *proto;
284             SV *code;
285             PROTOTYPE: $$
286             PREINIT:
287             SV *cv; /* not CV */
288             CODE:
289 4 50         SvGETMAGIC(code);
    0          
290 4           cv = SvRV(code);
291 4           sv_copypv(cv, proto);