GraalVM Polyglot: pass arguments from Java to LLVM (C++)

Viewed 249

Following the docs I could run Polyglot application where the start language is Java and the target language is C++, which is in a separated source file.

I wonder how could I pass some arguments from Java to C++.

Code examples

Start Language (Java)

import org.graalvm.polyglot.*;
import java.io.File;
import java.io.IOException;

public class HelloPolyglot {
    public static void main(String[] args) throws IOException {
        File file = new File("polyglot"); // the path to the file
        Source source = Source.newBuilder("llvm", file).build();

        Context polyglot = Context.newBuilder().allowAllAccess(true).build();

        Value cpart = polyglot.eval(source);
        cpart.executeVoid();
    }
}

Target Language (C++)

#include <iostream>
using namespace std;
  
int main(int argc, char** argv){
    cout << "You have entered " << argc
         << " arguments:" << "\n";
  
    for (int i = 0; i < argc; ++i)
        cout << argv[i] << "\n";
  
    return 0;
}

Thank you in advance.

2 Answers

As answered by Schatz on GraalVM Slack Server you can pass arguments to LLVM by:

    String[] arguments = {"Hello", "World"};
    Context polyglot = Context.newBuilder().arguments("llvm", arguments).allowAllAccess(true).build();
    Value cpart = polyglot.eval(source);
    cpart.executeVoid();

Alternatively, you can call functions directly, with

    cpart.readMember("functionName").execute(arguments);

Well, I found your question very interesting and recently faced a lot of issues, and unfortunately, I don't found any detailed guide about this. As i result I will provide a full explanation of how I make it work to call c++ function from java with parameters and return a result.

So let's begin its important to have installed the llvm-toolchain so if you don't simply run:

gu install llvm-toolchain

So assuming the c++ code is the following:

    #include<iostream>
    using namespace std;
    
    // Function to find the sum of integer array
    // extern "C" is required to suppress mangling
    extern "C" int getSumOfArray(int array[], int size) {
        printf("C++ => Find sum of numbers in an array\n");
    
        int i, sum = 0;
        for(i = 0; i < size; i++) {
            sum += array[i];
        }
        return sum;
    }

The magic trick that makes all things work is to feed you java polyglot code with the binary produced file and not the .cpp source because probably it will not work and you will face exceptions like this:

invalid elf header

So to move one simply run the following two commands

    export LLVM_TOOLCHAIN=$(lli --print-toolchain-path)

    $LLVM_TOOLCHAIN/clang++ -shared cpppart.cpp -lpolyglot-mock -o binary

After that, run the following java code: (Note that we don't use any extension it is no needed):

    File file=new File("binary");
    int[] input = new int[] { 4, 2, 8, 5, 20, 1, 40, 13, 23 };
    Context context = Context.newBuilder().allowAllAccess(true).build();
    Source source = Source.newBuilder("llvm", file).build();
    context.eval(source);
    Value cpart = context.getBindings("llvm").getMember("getSumOfArray");;
    int sum = cpart.execute(input, input.length).asInt();
    System.out.println(sum);

Et voila!!!!!! you will receive this message in java output:

116
C++ => Find sum of numbers in an array
Related