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>
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(&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.


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


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

Reply via email to