@@ -1414,7 +1414,20 @@ jl_generic_fptr_t jl_generate_fptr(jl_method_instance_t *li, const char *F, size
1414
1414
return fptr;
1415
1415
}
1416
1416
1417
- static Function *jl_cfunction_object (jl_function_t *f, jl_value_t *rt, jl_tupletype_t *argt);
1417
+ static Function *jl_cfunction_cache (jl_value_t *ft, jl_value_t *declrt, jl_tupletype_t *argt);
1418
+
1419
+ // Get a pointer to the cache for the C-callable entry point for the given argument types.
1420
+ // here argt does not include the leading function type argument
1421
+ static Function *jl_cfunction_object (jl_value_t *f, jl_value_t *declrt, jl_tupletype_t *argt)
1422
+ {
1423
+ jl_value_t *ft;
1424
+ if (jl_is_type (f))
1425
+ ft = (jl_value_t *)jl_wrap_Type (f);
1426
+ else
1427
+ ft = jl_typeof (f);
1428
+ return jl_cfunction_cache (ft, declrt, argt);
1429
+ }
1430
+
1418
1431
// get the address of a C-callable entry point for a function
1419
1432
extern " C" JL_DLLEXPORT
1420
1433
void *jl_function_ptr (jl_function_t *f, jl_value_t *rt, jl_value_t *argt)
@@ -1443,7 +1456,6 @@ void *jl_function_ptr_by_llvm_name(char *name) {
1443
1456
extern " C" JL_DLLEXPORT
1444
1457
void jl_extern_c (jl_function_t *f, jl_value_t *rt, jl_value_t *argt, char *name)
1445
1458
{
1446
- assert (jl_is_tuple_type (argt));
1447
1459
JL_LOCK (&codegen_lock);
1448
1460
Function *llvmf = jl_cfunction_object (f, rt, (jl_tupletype_t *)argt);
1449
1461
// force eager emission of the function (llvm 3.3 gets confused otherwise and tries to do recursive compilation)
@@ -4168,9 +4180,9 @@ static void emit_cfunc_invalidate(
4168
4180
}
4169
4181
}
4170
4182
4171
- static Function * gen_cfun_wrapper ( const function_sig_t &sig, jl_function_t *ff,
4172
- jl_value_t *jlrettype, jl_tupletype_t *argt ,
4173
- jl_typemap_entry_t *sf, jl_value_t *declrt, jl_tupletype_t *sigt)
4183
+ static Function*
4184
+ gen_cfun_wrapper ( const function_sig_t &sig, jl_value_t *ff ,
4185
+ jl_typemap_entry_t *sf, jl_value_t *declrt, jl_tupletype_t *sigt)
4174
4186
{
4175
4187
// Generate a c-callable wrapper
4176
4188
size_t nargs = sig.nargs ;
@@ -4221,8 +4233,19 @@ static Function *gen_cfun_wrapper(const function_sig_t &sig, jl_function_t *ff,
4221
4233
#endif
4222
4234
Function *cw_proto = function_proto (cw);
4223
4235
// Save the Function object reference
4224
- sf->func .value = jl_box_voidpointer ((void *)cw_proto);
4225
- jl_gc_wb (sf, sf->func .value );
4236
+ {
4237
+ jl_value_t *oldsf = sf->func .value ;
4238
+ size_t i, oldlen = jl_svec_len (oldsf);
4239
+ jl_value_t *newsf = (jl_value_t *)jl_alloc_svec (oldlen + 2 );
4240
+ JL_GC_PUSH1 (&newsf);
4241
+ jl_svecset (newsf, 0 , sig.rt );
4242
+ jl_svecset (newsf, 1 , jl_box_voidpointer ((void *)cw_proto));
4243
+ for (i = 0 ; i < oldlen; i++)
4244
+ jl_svecset (newsf, i + 2 , jl_svecref (oldsf, i));
4245
+ sf->func .value = newsf;
4246
+ jl_gc_wb (sf, sf->func .value );
4247
+ JL_GC_POP ();
4248
+ }
4226
4249
4227
4250
jl_codectx_t ctx (jl_LLVMContext);
4228
4251
ctx.f = cw;
@@ -4266,10 +4289,11 @@ static Function *gen_cfun_wrapper(const function_sig_t &sig, jl_function_t *ff,
4266
4289
Function::arg_iterator AI = cw->arg_begin ();
4267
4290
Value *sretPtr = sig.sret ? &*AI++ : NULL ;
4268
4291
jl_cgval_t *inputargs = (jl_cgval_t *)alloca (sizeof (jl_cgval_t ) * (nargs + 1 ));
4269
- inputargs[0 ] = mark_julia_const (ff); // we need to pass the function object even if (even though) it is a ghost
4292
+ // we need to pass the function object even if (even though) it is a singleton
4293
+ inputargs[0 ] = mark_julia_const (ff);
4270
4294
for (size_t i = 0 ; i < nargs; ++i, ++AI) {
4271
4295
Value *val = &*AI;
4272
- jl_value_t *jargty = jl_nth_slot_type (( jl_value_t *)argt , i);
4296
+ jl_value_t *jargty = jl_svecref (sig. at , i);
4273
4297
// figure out how to unpack this type
4274
4298
jl_cgval_t &inputarg = inputargs[i + 1 ];
4275
4299
if (jl_is_abstract_ref_type (jargty)) {
@@ -4521,90 +4545,112 @@ static Function *gen_cfun_wrapper(const function_sig_t &sig, jl_function_t *ff,
4521
4545
}
4522
4546
4523
4547
const struct jl_typemap_info cfunction_cache = {
4524
- 1 , &jl_voidpointer_type
4548
+ 1 , ( jl_datatype_t **)&jl_array_any_type
4525
4549
};
4526
4550
4527
- // Get the LLVM Function* for the C-callable entry point for a certain function
4528
- // and argument types.
4529
- // here argt does not include the leading function type argument
4530
- static Function *jl_cfunction_object (jl_function_t *ff, jl_value_t *declrt, jl_tupletype_t *argt)
4551
+ jl_array_t *jl_cfunction_list;
4552
+
4553
+ static Function *jl_cfunction_cache (jl_value_t *ft, jl_value_t *declrt, jl_tupletype_t *argt)
4531
4554
{
4532
4555
// Assumes the codegen lock is acquired. The caller is responsible for that.
4556
+ jl_value_t *sigt = NULL ; // dispatch sig: type signature (argt) with Ref{} annotations removed and ft added
4557
+ JL_GC_PUSH2 (&sigt, &ft);
4533
4558
4534
4559
// validate and unpack the arguments
4560
+ JL_TYPECHK (cfunction, type, (jl_value_t *)ft);
4535
4561
JL_TYPECHK (cfunction, type, declrt);
4536
- JL_TYPECHK (cfunction, type, (jl_value_t *)argt);
4537
- if (!jl_is_datatype_singleton ((jl_datatype_t *)jl_typeof (ff)))
4538
- jl_error (" closures are not yet c-callable" );
4562
+ if (!jl_is_tuple_type (argt))
4563
+ jl_type_error (" cfunction" , (jl_value_t *)jl_anytuple_type_type, (jl_value_t *)argt);
4564
+
4565
+ // check the cache structure
4566
+ // this has three levels (for the 3 parameters above)
4567
+ // first split on `ft` using a simple eqtable
4568
+ // then use the typemap to split on argt
4569
+ // and finally, pick declrt from the pair-list
4570
+ union jl_typemap_t cache_l2 = { NULL };
4571
+ // cache_l2.unknown = NULL;
4572
+ jl_typemap_entry_t *cache_l3 = NULL ;
4573
+ if (!jl_cfunction_list) {
4574
+ jl_cfunction_list = jl_alloc_vec_any (16 );
4575
+ }
4576
+ else {
4577
+ cache_l2.unknown = jl_eqtable_get (jl_cfunction_list, ft, NULL );
4578
+ if (cache_l2.unknown ) {
4579
+ cache_l3 = jl_typemap_assoc_by_type (cache_l2, (jl_value_t *)argt, NULL ,
4580
+ /* subtype*/ 0 , /* offs*/ 0 , /* world*/ 1 , /* max_world_mask*/ 0 );
4581
+ if (cache_l3) {
4582
+ jl_svec_t *sf = (jl_svec_t *)cache_l3->func .value ;
4583
+ size_t i, l = jl_svec_len (sf);
4584
+ for (i = 0 ; i < l; i += 2 ) {
4585
+ jl_value_t *ti = jl_svecref (sf, i);
4586
+ if (jl_egal (ti, declrt)) {
4587
+ JL_GC_POP ();
4588
+ return (Function*)jl_unbox_voidpointer (jl_svecref (sf, i + 1 ));
4589
+ }
4590
+ }
4591
+ }
4592
+ }
4593
+ }
4539
4594
4540
- size_t i, nargs = jl_nparams (argt);
4541
- jl_value_t *sigt = NULL ; // type signature with Ref{} annotations removed
4542
- jl_value_t *cfunc_sig = NULL ; // type signature of the call to cfunction (for caching)
4543
- JL_GC_PUSH2 (&sigt, &cfunc_sig);
4544
- sigt = (jl_value_t *)jl_alloc_svec (nargs + 1 );
4545
- cfunc_sig = (jl_value_t *)jl_alloc_svec (nargs + 2 );
4595
+ if (cache_l3 == NULL ) {
4596
+ union jl_typemap_t insert = cache_l2;
4597
+ if (!insert.unknown )
4598
+ insert.unknown = jl_nothing;
4599
+ cache_l3 = jl_typemap_insert (&insert, (jl_value_t *)insert.unknown , (jl_tupletype_t *)argt,
4600
+ NULL , jl_emptysvec, (jl_value_t *)jl_emptysvec, /* offs*/ 0 , &cfunction_cache, 1 , ~(size_t )0 , NULL );
4601
+ if (insert.unknown != cache_l2.unknown )
4602
+ jl_cfunction_list = jl_eqtable_put (jl_cfunction_list, ft, insert.unknown , NULL );
4603
+ }
4604
+
4605
+ // try to avoid needing a trampoline,
4606
+ // if we know that `ft` is some sort of
4607
+ // guaranteed singleton type
4608
+ jl_value_t *ff = NULL ;
4609
+ if (jl_is_datatype (ft))
4610
+ ff = ((jl_datatype_t *)ft)->instance ;
4611
+ if (jl_is_type_type (ft)) {
4612
+ jl_value_t *tp0 = jl_tparam0 (ft);
4613
+ if (jl_is_concrete_type (tp0))
4614
+ ff = tp0;
4615
+ }
4616
+ if (!ff)
4617
+ jl_error (" cfunction: function closures not yet supported" );
4546
4618
4619
+ // compute / validate return type
4547
4620
jl_value_t *crt = declrt;
4548
- jl_svecset (cfunc_sig, nargs + 1 , declrt);
4549
4621
if (jl_is_abstract_ref_type (declrt)) {
4550
4622
declrt = jl_tparam0 (declrt);
4551
4623
if (jl_is_typevar (declrt))
4552
4624
jl_error (" cfunction: return type Ref should have an element type, not Ref{<:T}" );
4553
4625
if (declrt == (jl_value_t *)jl_any_type)
4554
4626
jl_error (" cfunction: return type Ref{Any} is invalid. Use Any or Ptr{Any} instead." );
4555
- if (!jl_is_concrete_type (declrt))
4556
- jl_svecset (cfunc_sig, nargs + 1 , declrt); // Ref{Abstract} is the same calling convention as Abstract
4557
4627
crt = (jl_value_t *)jl_any_type;
4558
4628
}
4629
+ bool toboxed;
4630
+ Type *lcrt = julia_struct_to_llvm (crt, NULL , &toboxed);
4631
+ if (lcrt == NULL )
4632
+ jl_error (" cfunction: return type doesn't correspond to a C type" );
4633
+ else if (toboxed)
4634
+ lcrt = T_prjlvalue;
4559
4635
4560
- if (jl_is_type (ff))
4561
- jl_svecset (sigt, 0 , jl_wrap_Type (ff));
4562
- else
4563
- jl_svecset (sigt, 0 , jl_typeof (ff));
4564
- jl_svecset (cfunc_sig, 0 , jl_svecref (sigt, 0 ));
4636
+ // compute / validate method signature
4637
+ size_t i, nargs = jl_nparams (argt);
4638
+ sigt = (jl_value_t *)jl_alloc_svec (nargs + 1 );
4639
+ jl_svecset (sigt, 0 , ft);
4565
4640
for (i = 0 ; i < nargs; i++) {
4566
4641
jl_value_t *ati = jl_tparam (argt, i);
4567
- jl_svecset (cfunc_sig, i + 1 , ati);
4568
4642
if (jl_is_abstract_ref_type (ati)) {
4569
4643
ati = jl_tparam0 (ati);
4570
4644
if (jl_is_typevar (ati))
4571
4645
jl_error (" cfunction: argument type Ref should have an element type, not Ref{<:T}" );
4572
- if (ati != (jl_value_t *)jl_any_type && !jl_is_concrete_type (ati))
4573
- jl_svecset (cfunc_sig, i + 1 , ati); // Ref{Abstract} is the same calling convention as Abstract
4574
4646
}
4575
4647
if (jl_is_pointer (ati) && jl_is_typevar (jl_tparam0 (ati)))
4576
4648
jl_error (" cfunction: argument type Ptr should have an element type, Ptr{<:T}" );
4577
4649
jl_svecset (sigt, i + 1 , ati);
4578
4650
}
4579
4651
sigt = (jl_value_t *)jl_apply_tuple_type ((jl_svec_t *)sigt);
4580
- cfunc_sig = (jl_value_t *)jl_apply_tuple_type ((jl_svec_t *)cfunc_sig);
4581
-
4582
- // check the cache
4583
- jl_typemap_entry_t *sf = NULL ;
4584
- if (jl_cfunction_list.unknown != jl_nothing) {
4585
- sf = jl_typemap_assoc_by_type (jl_cfunction_list, cfunc_sig, NULL , /* subtype*/ 0 , /* offs*/ 0 , /* world*/ 1 , /* max_world_mask*/ 0 );
4586
- if (sf) {
4587
- jl_value_t *v = sf->func .value ;
4588
- if (v) {
4589
- if (jl_is_svec (v))
4590
- v = jl_svecref (v, 0 );
4591
- Function *f = (Function*)jl_unbox_voidpointer (v);
4592
- JL_GC_POP ();
4593
- return f;
4594
- }
4595
- }
4596
- }
4597
- if (sf == NULL ) {
4598
- sf = jl_typemap_insert (&jl_cfunction_list, (jl_value_t *)jl_cfunction_list.unknown , (jl_tupletype_t *)cfunc_sig,
4599
- NULL , jl_emptysvec, NULL , /* offs*/ 0 , &cfunction_cache, 1 , ~(size_t )0 , NULL );
4600
- }
4601
4652
4602
- bool toboxed;
4603
- Type *lcrt = julia_struct_to_llvm (crt, NULL , &toboxed);
4604
- if (lcrt == NULL )
4605
- jl_error (" cfunction: return type doesn't correspond to a C type" );
4606
- else if (toboxed)
4607
- lcrt = T_prjlvalue;
4653
+ // emit cfunction (trampoline)
4608
4654
jl_value_t *err;
4609
4655
{ // scope block for sig
4610
4656
function_sig_t sig (" cfunction" , lcrt, crt, toboxed,
@@ -4616,7 +4662,7 @@ static Function *jl_cfunction_object(jl_function_t *ff, jl_value_t *declrt, jl_t
4616
4662
err = NULL ;
4617
4663
}
4618
4664
else {
4619
- Function * f = gen_cfun_wrapper (sig, ff, crt, ( jl_tupletype_t *)argt, sf , declrt, (jl_tupletype_t *)sigt);
4665
+ auto f = gen_cfun_wrapper (sig, ff, cache_l3 , declrt, (jl_tupletype_t *)sigt);
4620
4666
JL_GC_POP ();
4621
4667
return f;
4622
4668
}
0 commit comments