[graalvm-users] c++ bytecode from java

Roland Schatz roland.schatz at oracle.com
Tue Jan 26 09:46:41 PST 2021


Hi,

The interop support for C++ is currently work in progress, some things 
work already, others not yet.
Some of the C++ interop features are behind a flag, try passing 
"--llvm.C++Interop".

Calling constructors and non-virtual methods should work already.
There is a WIP PR for virtual method calls: 
https://github.com/oracle/graal/pull/2932

C++ interop is a very recent feature and doesn't have many users yet, so 
there might be bugs.

Some more comments inline below...

On 1/25/21 10:48 PM, Darrell Schiebel wrote:
> Hello,
>
> I'm trying to understand the capabilities and limitations of using C++ 
> libraries from Java. One of the more complete examples I could find 
> was the:
>
>  *
>
>     CxxMethodsTest.java/methodsTest.cpp
>
> test from the GraalVM distribution. I removed the unit test framework, 
> but I find that there are some operations which fail (in Java):
>
>  1. retrieving a class: testLibrary.getMember("Point")
>
That should already work. You should be able to use to create instances 
of "Point" (with `point.newInstance(...)`).
It might be that this needs the "--llvm.C++Interop" flag though.

>  1. retrieving a class method: squaredEuclideanDistance =
>     testLibrary.getMember("squaredEuclideanDistance")
>
That doesn't work since "squaredEuclideanDistance" is not a global 
function. If you have an instance of "Point", you should be able to 
`point.getMember("squaredEuclideanDistance")` and execute the result, or 
just use `point.invokeMember("squaredEuclideanDistance", ...)` to 
directly invoke methods.

>  1. invoking a class member: testLibrary.invokeMember("setY", point2, 8)
>
Same thing. This needs to be `point2.invokeMember("setY", 8)`.

> I am using GraalVM 21.0.0, and I compiled the C++ like:
>
>  *
>
>     clang++ -std=c++11 -shared -o methodsTest.so methodsTest.cpp
>     -lgraalvm-llvm
>
> I suppose maybe the testing framework may compile the C++ source code 
> differently. Any idea where I've gone astray?

Is that "clang++" from the toolchain we ship with GraalVM? If yes, then 
that's the correct way to build.

If no: If you want to use interop (both C++ or C), you need to compile 
with debug info enabled. Also note that we currently only support libc++ 
(the one from the LLVM project), not libstdc++ (the one from GCC, which 
is the default on most Linux systems).

You can get the path to our toolchain using "lli --print-toolchain-path" 
(you might have to install it using "gu install llvm-toolchain", it's an 
optional component since you don't need it at runtime). The "clang++" 
from there automatically sets the correct flags. You can use "-v" to see 
what exactly it does.



> I think they may compile without name mangling or perhaps they compile 
> the cpp file on the fly... I don't know exactly what happens behind 
> the scenes with:
>
>  *
>
>     testLibrary = loadTestBitcodeValue("methodsTest.cpp")
>
That's just some path manipulation to locate .so file for that test, 
which is somewhere under mxbuild in a directory called 
"methodsTest.cpp.dir". It doesn't do any compilation, that is done using 
mx and make.

> My modified methodsTest.cpp file is down below.
>
> It seems like these are the key points:
>
>   * pointers should be used to pass/return objects (no mapping from
>     List<T> to std::list<T> for example)
>
Correct, currently we don't support by-value arguments in interop 
(except primitives of course). Everything must be pointers. Not sure 
about C++ references, they should work in principle, since in bitcode 
they are also just pointers. But I've never tried to be honest.

>   * mangled names do not work (unless the mangled name is used for
>     lookup, of course)
>
With the "--llvm.C++Interop" flag that should work. We read the 
unmangled names from the debug info.
This probably only works if there is no name conflict with the unmangled 
name, i.e. no overloading.

>   * class based inherited methods work (using an object pointer)
>   * looking up methods and supplying the object and args does not work
>     (e.g. squareEuclideanDistance above)
>   * retrieving object constructor as a function (e.g.
>     getMember("Point") above)
>
> Does this seem right? I've looked at the examples I could find on the 
> GraalVM.org website but are there any bigger examples of Java/C++ 
> integration via GraalVM?
Since this is a work in progress feature, we don't have any published 
examples for C++ yet.

Most of our users are only using C-based interfaces, even if the actual 
implementation behind the interface is in C++. That is of course a 
workaround you can use right now, but not a nice one.
We'll probably publish more examples once we reach a more complete state 
of our C++ interop implementation.


As I wrote in the beginning, all of this is pretty new, so not 
everything might work out of the box. You're welcome to play around with 
it, and if you get stuck, feel free to ask questions or report issues!


- Roland

>
> thanks for any advice,
> Darrell
>
> /*
>  * Copyright (c) 2020, Oracle and/or its affiliates.
>  *
>  * All rights reserved.
>  *
>  * Redistribution and use in source and binary forms, with or without 
> modification, are
>  * permitted provided that the following conditions are met:
>  *
>  * 1. Redistributions of source code must retain the above copyright 
> notice, this list of
>  * conditions and the following disclaimer.
>  *
>  * 2. Redistributions in binary form must reproduce the above 
> copyright notice, this list of
>  * conditions and the following disclaimer in the documentation and/or 
> other materials provided
>  * with the distribution.
>  *
>  * 3. Neither the name of the copyright holder nor the names of its 
> contributors may be used to
>  * endorse or promote products derived from this software without 
> specific prior written
>  * permission.
>  *
>  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 
> "AS IS" AND ANY EXPRESS
>  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
> WARRANTIES OF
>  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
> DISCLAIMED. IN NO EVENT SHALL THE
>  * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, 
> INDIRECT, INCIDENTAL, SPECIAL,
>  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 
> PROCUREMENT OF SUBSTITUTE
>  * GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
> INTERRUPTION) HOWEVER CAUSED
>  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 
> LIABILITY, OR TORT (INCLUDING
>  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 
> SOFTWARE, EVEN IF ADVISED
>  * OF THE POSSIBILITY OF SUCH DAMAGE.
>  */
> #include <graalvm/llvm/polyglot.h>
> #include <stdlib.h>
> #include <math.h>
>
> #define EXTERN extern "C"
>
> class Point {
> protected:
>     int x;
>     int y;
>
> public:
>     Point();
>     int getX();
>     int getY();
>     void setX(int val);
>     void setY(int val);
>     double squaredEuclideanDistance(Point *other);
> };
>
> POLYGLOT_DECLARE_TYPE(Point)
>
> class XtendPoint : public Point {
> private:
>     int z;
>
> public:
>     XtendPoint();
>     int getZ();
>     void setZ(int val);
>     int getZ(int constant);
>     int getX();
> };
>
> POLYGLOT_DECLARE_TYPE(XtendPoint)
>
> //class methods
>
> Point::Point() {
>     x = 0;
>     y = 0;
> }
>
> int Point::getX() {
>     return x;
> }
>
> int Point::getY() {
>     return y;
> }
>
> void Point::setX(int val) {
>     x = val;
> }
>
> void Point::setY(int val) {
>     y = val;
> }
>
> double Point::squaredEuclideanDistance(Point *other) {
>     double dX = (double) (x - other->x);
>     double dY = (double) (y - other->y);
>     return dX * dX + dY * dY;
> }
>
> XtendPoint::XtendPoint() {
>     z = 0;
> }
>
> int XtendPoint::getZ() {
>     return z;
> }
>
> void XtendPoint::setZ(int dZ) {
>     z = dZ;
> }
>
> int XtendPoint::getZ(int constantOffset) {
>     return z + constantOffset;
> }
>
> int XtendPoint::getX() {
>     return x * 2;
> }
>
> //functions
> EXTERN void *allocNativePoint() {
>     Point *ret = (Point *) malloc(sizeof(*ret));
>     return polyglot_from_Point(ret);
> }
>
> EXTERN void *allocNativeXtendPoint() {
>     XtendPoint *ret = (XtendPoint *) malloc(sizeof(*ret));
>     return polyglot_from_XtendPoint(ret);
> }
>
> EXTERN void swap(Point *p, Point *q) {
>     Point tmp = *q;
>     *q = *p;
>     *p = tmp;
> }
>
> EXTERN void freeNativePoint(Point *p) {
>     free(p);
> }
>
> EXTERN void freeNativeXtendPoint(XtendPoint *p) {
>     free(p);
> }
>
>
> _______________________________________________
> GraalVM-Users mailing list
> GraalVM-Users at oss.oracle.com
> https://oss.oracle.com/mailman/listinfo/graalvm-users


-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://oss.oracle.com/pipermail/graalvm-users/attachments/20210126/a54990c2/attachment-0001.html 


More information about the GraalVM-Users mailing list