Thanks. That makes things clearer.

Den fredag 14 oktober 2016 kl. 14:16:54 UTC+2 skrev Yichao Yu:
>
>
>
> On Fri, Oct 14, 2016 at 7:03 AM, Bart Janssens <ba...@bartjanssens.org 
> <javascript:>> wrote:
>
>> Hi,
>>
>> Replies below, to the best of my understanding of the Julia C interface:
>>
>> On Fri, Oct 14, 2016 at 11:47 AM Gunnar Farnebäck <gun...@lysator.liu.se 
>> <javascript:>> wrote:
>>
>>> Reading through the threads and issues on gc rooting for embedded code, 
>>> as well as the code comments above the JL_GC_PUSH* macros in julia.h, I'm 
>>> still uncertain about how defensive it's necessary to be and best 
>>> practices. I'll structure this into a couple of cases with questions.
>>>
>>> 1. One of the use cases in examples/embedding.c is written:
>>>
>>> jl_function_t *func = jl_get_function(jl_base_module, "sqrt");
>>> jl_value_t* argument = jl_box_float64(2.0);
>>> jl_value_t* ret = jl_call1(func, argument);
>>>
>>> if (jl_is_float64(ret)) {
>>>     double retDouble = jl_unbox_float64(ret);
>>>     printf("sqrt(2.0) in C: %e\n", retDouble);
>>> }
>>>
>>>  
>>>
>> Is this missing gc rooting for argument during the call to jl_call1 or is 
>>> it safe without it?
>>> Would ret need gc rooting to be safe during the calls to jl_is_float64 
>>> and/or jl_unbox_float64?
>>>
>>
>> The jl_call argument must be rooted since func may allocate. I don't 
>> think the operations on ret allocate, but if you're unsure it's better to 
>> root it. Also, as your code evolves you may decide to perform extra 
>> operations on ret and then it's easy to forget the GC rooting at that 
>> point, so I'd root ret here.
>>
>
> jl_call1 (and other jl_call* functions) are special in the sense that it 
> roots it's argument so you don't have to root `argument`
> The ret doesn't have to be rooted if these are all what you are doing with 
> it.
> The only one that should in principle be rooted is actually `func`. 
> However, since it is known to be a global constant you won't get into any 
> trouble without. (If it's a non-const global then you have to)
>  
>
>>  
>>
>>>
>>> 2. 
>>> jl_value_t *a = jl_box_float64(1.0);
>>> jl_value_t *b = jl_box_float64(2.0);
>>> JL_GC_PUSH2(&a, &b);
>>>
>>> Is this unsafe since a is not yet rooted during the second call to 
>>> jl_box_float64 and must instead be written like below?
>>>
>>> jl_value_t *a = 0;
>>> jl_value_t *b = 0;
>>> JL_GC_PUSH2(&a, &b);
>>> a = jl_box_float64(1.0);
>>> b = jl_box_float64(2.0);
>>>
>>> For a single variable it's just fine to do like this though?
>>> jl_value_t *a = jl_box_float64(1.0);
>>> JL_GC_PUSH1(&a);
>>>
>>>
>> Yes, since jl_box will allocate.
>>
>
> This is correct.
>  
>
>>  
>>
>>> 3. Are
>>> jl_function_t *func = jl_get_function(jl_base_module, "println");
>>> jl_value_t *a = 0;
>>> jl_value_t *b = 0;
>>> JL_GC_PUSH2(&a, &b);
>>> a = jl_box_float64(1.0);
>>> b = jl_box_float64(2.0);
>>> jl_call2(func, a, b);
>>> JL_GC_POP();
>>>
>>> and
>>>
>>> jl_function_t *func = jl_get_function(jl_base_module, "println");
>>> jl_value_t **args;
>>> JL_GC_PUSHARGS(args, 2);
>>> args[0] = jl_box_float64(1.0);
>>> args[1] = jl_box_float64(2.0);
>>> jl_call(func, args, 2);
>>> JL_GC_POP();
>>>
>>> equivalent and both safe? Are there any reasons to choose one over the 
>>> other, apart from personal preferences?
>>>
>>
>> They are equivalent, looking at the code for the macro it seems that the 
>> JL_GC_PUSHARGS variant heap-allocates the array of pointers to root, so 
>> that might be slightly slower. I'd only use the JL_GC_PUSHARGS version if 
>> the number of arguments comes from a variable or a parameter or similar.
>>
>
> No JL_GC_PUSHARGS does **NOT** heap allocate the array.
> The difference between the two is pretty small and the performance should 
> be almost not noticeable unless you are doing a lot of things with the 
> boxed variables.
>  
>
>>  
>>
>>>
>>> 4. Can any kind of exception checking be done safely without rooting the 
>>> return value?
>>> jl_value_t *ret = jl_call1(...);
>>> if (jl_exception_occured())
>>>     printf("%s \n", jl_typeof_str(jl_exception_occured()));
>>> else
>>>     d = jl_unbox_float64(ret);
>>>
>>>
> This is currently safe. It's a little close to the edge of what I think we 
> can always guarantee in the future
>  
>
>> 5. What kind of costs, other than increased code size, can be expected 
>>> from overzealous gc rooting?
>>>
>>
>>
> It leaks local variable addresses to global so the compiler cannot reason 
> about their values as well. This is the "difference" I've mentioned above 
> that you won't notice "unless you are doing a lot of things with the boxed 
> variables"
>  
>
>> These I leave for the experts :)
>>  
>>
>>>
>>> 6. Is it always safe not to gc root the function pointer returned from 
>>> jl_get_function?
>>>
>>>
>> A function should be bound to the symbol you use to look it up, so it is 
>> already rooted.
>>
>
> No. It is only safe to not root the value if it is a const global (well, 
> or you know that it never changes) and is not an immutable.
> You can also not root any value if it is a singleton, which happens to be 
> true for most functions.
>  
>
>>
>> Cheers,
>>
>> Bart 
>>
>
>

Reply via email to