On Fri, Nov 6, 2015 at 7:21 AM, Chris Cheetham <chipandrud...@gmail.com> wrote:
> Hi there,
>
> I am currently playing with Julia calls from C. I have made some good
> progress insofar as calling Julia functions, boxing/unboxing etc. What I am
> particularly interested in however is being able to return a type which
> consists of a number of Float64s and being able to get/set their values on
> the C side.
>
> For example
>
> type Example
>         a::Float64
> b::Float64
> c::Float64
> end
>
>
> Unboxing returns a copy of a value, so no means to then set it and
> jl_get_nth_field seems to also do the same.
>
>
> I am able to get a reference to the value using pointer arithmetic by
> getting jl_value_t + 1. I'm assuming the raw jl_value_t pointer is the type
> pointer? and offsetting by 1 is the pointer to the value?
>
> Accessing elements in the type seems possible by further offsetting the
> pointer  jl_value_t + 1 + elementIndex. My question is, is this a safe
> assumption to make? Or is there a better way to be doing this that I haven't
> spotted yet?

Which version of julia are you using, what you describe sounds like
the behavior on 0.3 and things have changed on 0.4 and I would
recommand using 0.4 since its newer and is easier to deal with in C
(unless you have legacy code to deal with of course).

Each object has a tag followed by the data. The tag is a pointer on
both 0.3 and 0.4. The data is a C compatible struct. The type of the
field is what you declared in the julia code except for non-leaftype
(e.g. Any, abstract type, Union) or non pointerfree types
(non-immutable non-bitstype, including every type you declared with
`type` instead of `immutable` or `bitstype`) in which case the field
is a `jl_value_t*` pointer.

The layout in the memory is simply

    [tag][data]

The difference in 0.3 and 0.4 is that on 0.3, a `jl_value_t*` points
to the tag while on 0.4 a `jl_value_t*` points to the data.
(`jl_taggedvalue_t*` points to the tag on 0.4 but you almost never
need to deal with it directly). Note that this apply to both the value
you get from the julia runtime as well as the value you load from the
field in another `jl_value_t*`.

Since the data layout is c compatible, after you've got the pointer to
the data section, you can either compute the C offset directly or
simply cast it to a c structure and access it just like any c
structure.

If you want to write to a `jl_value_t*` field there's additional
consideration because of the generational garbage collector, see the
memory management section of the embedding manual[1], which also have
a very short example of accessing field of a jl_value_t.

For the example you have above, your `jl_value_t + 1` is the pointer
to the data section (since I believe `sizeof(jl_value_t) ==
sizeof(void*)` on 0.3) and the additional offset are the field offset
in a c structure. Note that you can calculate the field offset by
simply adding field index to the jl_value_t pointer because both
Float64 and pointer are 64bit on 64bit architectures, this is not
generally true for other data types or other CPUs so the best way to
do this is to cast the pointer to the struct type and access the
field.

[1] http://julia.readthedocs.org/en/latest/manual/embedding/#memory-management

>
> Thanks,
> Chris
>
>
>

Reply via email to