1

I have Java code that requires heavy calculations which I would like to forward into C++ using JNI.
My main concern is having all the data serialized in memory, and next to forward the computation to GPU.
Since the data is received in Java, but the main calculations are done using C++, I thought of arranging all the data continuously in a raw array (ByteBuffer or raw bytes from Unsafe), in the same structure as the C++ object.
For example, suppose I have a point with x and y. In C++ the object has a size of 24 bytes. 8 bytes for (I guess) VTable, 8 bytes for x and 8 bytes for y.
So in Java, I would arrange all the data in the same structure and pass the buffer to C++ using JNI, and in C++ cast it to an array of points.

This worked fine, and I am allowing myself to assume that I will always use the same C++ compiler, same JDK, same OS and same HW (at least for testing the feasibility of the solution).

My question is if these assumptions are correct, or there is a better way to pass serialized data between Java and C++ (I must use JNI and not some kind of IPC)?

2
  • JNI/JNA is the only way to invoke a function written in C++. With Unsafe you can allocate a native offheap memory and pass it into the JNI function so in C you simply cast it to void* Commented Feb 18, 2019 at 22:32
  • The main question here is if i can rely on the C++ structure (offset, alignment of the fields, etc.), so I can fill the buffer accordingly, and in the JNI call, just cast it to Point *? Commented Feb 19, 2019 at 6:09

1 Answer 1

1

if I can rely on the C++ structure (offset, alignment of the fields, etc.)

No, unless you know what your compiler on your specific platform will do in that case. It yields undefined behavior.

Aliasing the content of ByteBuffer (aka char *) with Point * to later access its members is not possible in idiomatic C. Take a look at the C Standard N1570 6.5 (p7):

An object shall have its stored value accessed only by an lvalue expression that has one of the following types:88)

— a type compatible with the effective type of the object,

Assuming you know that void * returned by GetDirectBufferAddress is itself returned by a call to malloc(size) or friends (it actually uses malloc) where size_t size = sizeof(struct Point) than you can cast it to Point * initialize its member from native code and later use it. That would be a conforming way (one of).

Sign up to request clarification or add additional context in comments.

2 Comments

What about the opposite way: Allocating an array of Point * in C++ and sending it to Java, and then filling this array, when assuming I know the correct offsets?
@GuyYafe Sure, the Standard allows you to copy the object representation (aka char[sizeof(Point)]) and do with them what you need (assuming you know what this object representation means). But if you modify this object representation and will send it back to native code you probably will get UB (I need to dig in the Standard for normative reference). Anyway volatile modifier (in C, not in Java) is your friend in that case.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.