@@ -87,63 +87,88 @@ parse_keyword_arg_i(VALUE key, VALUE value, VALUE self)
87
87
return ST_CONTINUE ;
88
88
}
89
89
90
+ static VALUE
91
+ normalize_argument_types (const char * name ,
92
+ VALUE arg_types ,
93
+ bool * is_variadic )
94
+ {
95
+ VALUE normalized_arg_types ;
96
+ int i ;
97
+ int n_arg_types ;
98
+ * is_variadic = false;
99
+
100
+ Check_Type (arg_types , T_ARRAY );
101
+ n_arg_types = RARRAY_LENINT (arg_types );
102
+ Check_Max_Args (name , n_arg_types );
103
+
104
+ normalized_arg_types = rb_ary_new_capa (n_arg_types );
105
+ for (i = 0 ; i < n_arg_types ; i ++ ) {
106
+ VALUE arg_type = RARRAY_AREF (arg_types , i );
107
+ int c_arg_type = NUM2INT (arg_type );
108
+ if (c_arg_type == TYPE_VARIADIC ) {
109
+ if (i != n_arg_types - 1 ) {
110
+ rb_raise (rb_eArgError ,
111
+ "Fiddle::TYPE_VARIADIC must be the last argument type: "
112
+ "%" PRIsVALUE ,
113
+ arg_types );
114
+ }
115
+ * is_variadic = true;
116
+ break ;
117
+ }
118
+ else {
119
+ (void )INT2FFI_TYPE (c_arg_type ); /* raise */
120
+ }
121
+ rb_ary_push (normalized_arg_types , INT2FIX (c_arg_type ));
122
+ }
123
+
124
+ /* freeze to prevent inconsistency at calling #to_int later */
125
+ OBJ_FREEZE (normalized_arg_types );
F438
126
+ return normalized_arg_types ;
127
+ }
128
+
90
129
static VALUE
91
130
initialize (int argc , VALUE argv [], VALUE self )
92
131
{
93
132
ffi_cif * cif ;
94
- ffi_type * * arg_types , * rtype ;
95
- ffi_status result ;
96
- VALUE ptr , args , ret_type , abi , kwds ;
97
- int i , len ;
98
- int nabi ;
133
+ VALUE ptr , arg_types , ret_type , abi , kwds ;
134
+ int c_ret_type ;
135
+ bool is_variadic = false;
136
+ ffi_abi c_ffi_abi ;
99
137
void * cfunc ;
100
138
101
- rb_scan_args (argc , argv , "31:" , & ptr , & args , & ret_type , & abi , & kwds );
139
+ rb_scan_args (argc , argv , "31:" , & ptr , & arg_types , & ret_type , & abi , & kwds );
102
140
rb_iv_set (self , "@closure" , ptr );
103
141
104
142
ptr = rb_Integer (ptr );
105
143
cfunc = NUM2PTR (ptr );
106
144
PTR2NUM (cfunc );
107
- nabi = NIL_P (abi ) ? FFI_DEFAULT_ABI : NUM2INT (abi );
108
- abi = INT2FIX (nabi );
109
- i = NUM2INT (ret_type );
110
- rtype = INT2FFI_TYPE (i );
111
- ret_type = INT2FIX (i );
112
-
113
- Check_Type (args , T_ARRAY );
114
- len = RARRAY_LENINT (args );
115
- Check_Max_Args ("args" , len );
116
- /* freeze to prevent inconsistency at calling #to_int later */
117
- args = rb_ary_subseq (args , 0 , len );
118
- for (i = 0 ; i < RARRAY_LEN (args ); i ++ ) {
119
- VALUE a = RARRAY_AREF (args , i );
120
- int type = NUM2INT (a );
121
- (void )INT2FFI_TYPE (type ); /* raise */
122
- if (INT2FIX (type ) != a ) rb_ary_store (args , i , INT2FIX (type ));
145
+ c_ffi_abi = NIL_P (abi ) ? FFI_DEFAULT_ABI : NUM2INT (abi );
146
+ abi = INT2FIX (c_ffi_abi );
147
+ c_ret_type = NUM2INT (ret_type );
148
+ (void )INT2FFI_TYPE (c_ret_type ); /* raise */
149
+ ret_type = INT2FIX (c_ret_type );
150
+
151
+ arg_types = normalize_argument_types ("argument types" ,
152
+ arg_types ,
153
+ & is_variadic );
154
+ #ifndef HAVE_FFI_PREP_CIF_VAR
155
+ if (is_variadic ) {
156
+ rb_raise (rb_eNotImpError ,
157
+ "ffi_prep_cif_var() is required in libffi "
158
+ "for variadic arguments" );
123
159
}
124
- OBJ_FREEZE ( args );
160
+ #endif
125
161
126
162
rb_iv_set (self , "@ptr" , ptr );
127
- rb_iv_set (self , "@args " , args );
163
+ rb_iv_set (self , "@argument_types " , arg_types );
128
164
rb_iv_set (self , "@return_type" , ret_type );
129
165
rb_iv_set (self , "@abi" , abi );
166
+ rb_iv_set (self , "@is_variadic" , is_variadic ? Qtrue : Qfalse );
130
167
131
168
if (!NIL_P (kwds )) rb_hash_foreach (kwds , parse_keyword_arg_i , self );
132
169
133
170
TypedData_Get_Struct (self , ffi_cif , & function_data_type , cif );
134
-
135
- arg_types = xcalloc (len + 1 , sizeof (ffi_type * ));
136
-
137
- for (i = 0 ; i < RARRAY_LEN (args ); i ++ ) {
138
- int type = NUM2INT (RARRAY_AREF (args , i ));
139
- arg_types [i ] = INT2FFI_TYPE (type );
140
- }
141
- arg_types [len ] = NULL ;
142
-
143
- result = ffi_prep_cif (cif , nabi , len , rtype , arg_types );
144
-
145
- if (result )
146
- rb_raise (rb_eRuntimeError , "error creating CIF %d" , result );
171
+ cif -> arg_types = NULL ;
147
172
148
173
return self ;
149
174
}
@@ -170,44 +195,144 @@ function_call(int argc, VALUE argv[], VALUE self)
170
195
{
171
196
struct nogvl_ffi_call_args args = { 0 };
172
197
fiddle_generic * generic_args ;
173
- VALUE cfunc , types , cPointer ;
198
+ VALUE cfunc ;
199
+ VALUE abi ;
200
+ VALUE arg_types ;
201
+ VALUE cPointer ;
202
+ VALUE is_variadic ;
203
+ int n_arg_types ;
204
+ int n_fixed_args = 0 ;
205
+ int n_call_args = 0 ;
174
206
int i ;
207
+ int i_call ;
175
208
VALUE alloc_buffer = 0 ;
176
209
177
210
cfunc = rb_iv_get (self , "@ptr" );
178
- types = rb_iv_get (self , "@args" );
211
+ abi = rb_iv_get (self , "@abi" );
212
+ arg_types = rb_iv_get (self , "@argument_types" );
179
213
cPointer = rb_const_get (mFiddle , rb_intern ("Pointer" ));
180
-
181
- Check_Max_Args ("number of arguments" , argc );
182
- if (argc != (i = RARRAY_LENINT (types ))) {
183
- rb_error_arity (argc , i , i );
214
+ is_variadic = rb_iv_get (self , "@is_variadic" );
215
+
216
+ n_arg_types = RARRAY_LENINT (arg_types );
217
+ n_fixed_args = n_arg_types ;
218
+ if (RTEST (is_variadic )) {
219
+ if (argc < n_arg_types ) {
220
+ rb_error_arity (argc , n_arg_types , UNLIMITED_ARGUMENTS );
221
+ }
222
+ if (((argc - n_arg_types ) % 2 ) != 0 ) {
223
+ rb_raise (rb_eArgError ,
224
+ "variadic arguments must be type and value pairs: "
225
+ "%" PRIsVALUE ,
226
+ rb_ary_new_from_values (argc , argv ));
227
+ }
228
+ n_call_args = n_arg_types + ((argc - n_arg_types ) / 2 );
229
+ }
230
+ else {
231
+ if (argc != n_arg_types ) {
232
+ rb_error_arity (argc , n_arg_types , n_arg_types );
233
+ }
234
+ n_call_args = n_arg_types ;
184
235
}
236
+ Check_Max_Args ("the number of arguments" , n_call_args );
185
237
186
238
TypedData_Get_Struct (self , ffi_cif , & function_data_type , args .cif );
187
239
240
+ if (is_variadic && args .cif -> arg_types ) {
241
+ xfree (args .cif -> arg_types );
242
+ args .cif -> arg_types = NULL ;
243
+ }
244
+
245
+ if (!args .cif -> arg_types ) {
246
+ VALUE fixed_arg_types = arg_types ;
247
+ VALUE return_type ;
248
+ int c_return_type ;
249
+ ffi_type * ffi_return_type ;
250
+ ffi_type * * ffi_arg_types ;
251
+ ffi_status result ;
252
+
253
+ arg_types = rb_ary_dup (fixed_arg_types );
254
+ for (i = n_fixed_args ; i < argc ; i += 2 ) {
255
+ VALUE arg_type = argv [i ];
256
+ int c_arg_type = NUM2INT (arg_type );
257
+ (void )INT2FFI_TYPE (c_arg_type ); /* raise */
258
+ rb_ary_push (arg_types , INT2FIX (c_arg_type ));
259
+ }
260
+
261
+ return_type = rb_iv_get (self , "@return_type" );
262
+ c_return_type = FIX2INT (return_type );
263
+ ffi_return_type = INT2FFI_TYPE (c_return_type );
264
+
265
+ ffi_arg_types = xcalloc (n_call_args + 1 , sizeof (ffi_type * ));
266
+ for (i_call = 0 ; i_call < n_call_args ; i_call ++ ) {
267
+ VALUE arg_type ;
268
+ int c_arg_type ;
269
+ arg_type = RARRAY_AREF (arg_types , i_call );
270
+ c_arg_type = FIX2INT (arg_type );
271
+ ffi_arg_types [i_call ] = INT2FFI_TYPE (c_arg_type );
272
+ }
273
+ ffi_arg_types [i_call ] = NULL ;
274
+
275
+ if (is_variadic ) {
276
+ #ifdef HAVE_FFI_PREP_CIF_VAR
277
+ result = ffi_prep_cif_var (args .cif ,
278
+ FIX2INT (abi ),
279
+ n_fixed_args ,
280
+ n_call_args ,
281
+ ffi_return_type ,
282
+ ffi_arg_types );
283
+ #else
284
+ /* This code is never used because ffi_prep_cif_var()
285
+ * availability check is done in #initialize. */
286
+ result = FFI_BAD_TYPEDEF ;
287
+ #endif
288
+ }
289
+ else {
290
+ result = ffi_prep_cif (args .cif ,
291
+ FIX2INT (abi ),
292
+ n_call_args ,
293
+ ffi_return_type ,
294
+ ffi_arg_types );
295
+ }
296
+ if (result != FFI_OK ) {
297
+ xfree (ffi_arg_types );
298
+ args .cif -> arg_types = NULL ;
299
+ rb_raise (rb_eRuntimeError , "error creating CIF %d" , result );
300
+ }
301
+ }
302
+
188
303
generic_args = ALLOCV (alloc_buffer ,
189
- (size_t )(argc + 1 ) * sizeof (void * ) + (size_t )argc * sizeof (fiddle_generic ));
304
+ sizeof (fiddle_generic ) * n_call_args +
305
+ sizeof (void * ) * (n_call_args + 1 ));
190
306
args .values = (void * * )((char * )generic_args +
191
- (size_t )argc * sizeof (fiddle_generic ));
192
-
193
- for (i = 0 ; i < argc ; i ++ ) {
194
- VALUE type = RARRAY_AREF (types , i );
195
- VALUE src = argv [i ];
196
- int argtype = FIX2INT (type );
197
-
198
- if (argtype == TYPE_VOIDP ) {
199
- if (NIL_P (src )) {
200
- src = INT2FIX (0 );
201
- } else if (cPointer != CLASS_OF (src )) {
202
- src = rb_funcall (cPointer , rb_intern ("[]" ), 1 , src );
203
- }
204
- src = rb_Integer (src );
205
- }
206
-
207
- VALUE2GENERIC (argtype , src , & generic_args [i ]);
208
- args .values [i ] = (void * )& generic_args [i ];
307
+ sizeof (fiddle_generic ) * n_call_args );
308
+
309
+ for (i = 0 , i_call = 0 ;
310
+ i < argc && i_call < n_call_args ;
311
+ i ++ , i_call ++ ) {
312
+ VALUE arg_type ;
313
+ int c_arg_type ;
314
+ VALUE src ;
315
+ arg_type = RARRAY_AREF (arg_types , i_call );
316
+ c_arg_type = FIX2INT (arg_type );
317
+ if (i >= n_fixed_args ) {
318
+ i ++ ;
319
+ }
320
+ src = argv [i ];
321
+
322
+ if (c_arg_type == TYPE_VOIDP ) {
323
+ if (NIL_P (src )) {
324
+ src = INT2FIX (0 );
325
+ }
326
+ else if (cPointer != CLASS_OF (src )) {
327
+ src = rb_funcall (cPointer , rb_intern ("[]" ), 1 , src );
328
+ }
329
+ src = rb_Integer (src );
330
+ }
331
+
332
+ VALUE2GENERIC (c_arg_type , src , & generic_args [i_call ]);
333
+ args .values [i_call ] = (void * )& generic_args [i_call ];
209
334
}
210
- args .values [argc ] = NULL ;
335
+ args .values [i_call ] = NULL ;
211
336
args .fn = (void (* )(void ))NUM2PTR (cfunc );
212
337
213
338
(void )rb_thread_call_without_gvl (nogvl_ffi_call , & args , 0 , 0 );
0 commit comments