Re: [julia-users] GC rooting for embedding: what is safe and unsafe?

2016-10-17 Thread Gunnar Farnebäck
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  > 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 > > 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(, );
>>>
>>> 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 = 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();
>>>
>>>
>> 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 = 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 

Re: [julia-users] GC rooting for embedding: what is safe and unsafe?

2016-10-14 Thread Yichao Yu
On Fri, Oct 14, 2016 at 7:03 AM, Bart Janssens 
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 
> 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(, );
>>
>> 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 = 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();
>>
>>
> 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 = 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
>


Re: [julia-users] GC rooting for embedding: what is safe and unsafe?

2016-10-14 Thread Bart Janssens
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 
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.


>
> 2.
> jl_value_t *a = jl_box_float64(1.0);
> jl_value_t *b = jl_box_float64(2.0);
> JL_GC_PUSH2(, );
>
> 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 = 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();
>
>
Yes, since jl_box will allocate.


> 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 = 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.


>
> 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);
>
> 5. What kind of costs, other than increased code size, can be expected
> from overzealous gc rooting?
>

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.

Cheers,

Bart