Going Polyglot with GraalVm

Polyglot ability for GraalVm
Reading Time: 4 minutes

Hi all. In this blog we will see how we can do polyglot implementations with GraalVm. The pre-requisites for this are:

  • Understanding of GraalVm.
  • Knowledge of features GraalVm provides.
  • Local Setup of GraalVm.
  • A bit of java and python(Optional).

So let’s start.

What’s GraalVm?

GraalVm is an Open Source project from Oracle which aims to target the JVM so that many langauges can co-exist in the same application. GraalVm is not JVM, instead it’s a UVM (Universal Virtual Machine). It supports all languages that have a compiler which generates bytecode; this means that anybody working with Java, Scala, etc., can already use GraalVM. Thus all these langauges share the same VM and its capabilities. At the time of writing this post, GraalVm supports both Java 8 and 11 version.

Another key feature of GraalVm is the ability to create native images of our JVM based applications. This makes distributing and installing Java programs easier, eliminating the need for an additional JRE installation.

Furthermore, a native binary has the advantage of starting faster. Why? Because, it has already undergone translation to machine code form before execution (AOT compilation) and does not need a translation at runtime by the JIT compiler. Thus, the performance behavior of native binaries is constant and predictable. Why? Because the code no longer needs optimization at runtime by the JIT compiler in interaction with the profiler. Native binaries also need much less memory because the JVM infrastructure for the JIT compiler does not need to run.

We will talk about the advantages of native images in the next post. In this post let’s see how to run a polyglot service.

Setup GraalVm

Oracle provides two versions of the GraalVm to use, first the community eddition & second the enterprise edition. We’ll be using the community edition in this post. Setting up GraalVm on your local is quite easy. Install it from the official GraalVm site: https://www.graalvm.org/getting-started/#install-graalvm. Download the zip file supported for your OS. Next, do the following:

  • Set the JAVA_HOME in your .bashrc to point to the location where you have extracted the graalvm zip file.
  • Set the PATH variable to point to $JAVA_HOME/bin

We can then run the application using graalVm support, after setting these variables. Setting GraalVM to the PATH and JAVA_HOME environment variables during the installation should be enough to run an application with GraalVM.

Polyglot with GraalVm

As per the official documentation and polyglot reference from GraalVm.org, it states:

"GraalVM allows you to write polyglot applications with a seamless way to pass values from one language to another. With GraalVM there is no copying or marshalling necessary as it is with other polyglot systems. This lets you achieve high performance when language boundaries are crossed. Most of the time there is no additional cost for crossing a language boundary at all."

As a result, with GraalVm’s inherent support for polyglot functionality, developers can focus on the logic itself rather being concerned with what language they should write it in. Let’s see how we can achieve this. Assume that, we are working on a normal java application and suddenly there is a need for some random code in javascrip. To keep things simple lets just try to see how to get an element of the js array in java program. So, here’s an example showing how we can do that…

import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

public class PolyglotJavaAndJs {
public static void main(String[] args) {
Context context = Context.newBuilder().allowIO(true).build();
Value array = context.eval("js", "[1,2,42,4]");
int result = array.getArrayElement(2).asInt();
System.out.println(result);
}
}

I have created a class PolyglotJavaAndJs, in it we have used the polyglot.context and polyglot.vaue components from GraalVm Sdk. With the help of context we can pass in a different language of choice and see it working within our Java application. To run and evaluate the above java application use the following:

Open the terminal and go to the src folder of the application and execute the following
javac PolyglotJavaAndJs.java
java PolyglotJavaAndJs

You will see that the output on the screen is 42.

Let’s move ahead and see how we can continue with Java and Python using Polyglot approach. Let’s try passing values from Java program to Python code to make things interesting.

Polyglot Java to Python

Let suppose we want to calculate the square of a number. However, we want to run the logic for squaring in Python but we want to capture the number from Java app.

So, here’s the scenario where you will pass variables between two different languages in the same application. Let’s go through the below code snippet:

import org.graalvm.polyglot.*;

import java.util.Scanner;

public class PolyglotJavaAndPython {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
System.out.println("Enter the number to calculate its square...");
int input = scanner.nextInt();

Context context = Context.newBuilder().allowIO(true).build();
context.eval("python", "print('Hello From Python')");
// Use the getBindings and putMember methods on the context for passing the value from Java to Python app.
context.getBindings("python").putMember("number", input);
Value result = context.eval("python", "number * number");
System.out.println(result);
}
}

And, here’s the output of the above program:

Execute the statements:
$ javac PolyglotJavaAndPython.java
$ java PolyglotJavaAndPython
Enter the number to calculate its square…
10
Hello From Python
100

Takeaways

Simple right? We created a small convenience java class. In it we are just asking for an input from the user and are responding back with the square of the input. Though, it looks simple there are a few important things to note here:

  • For passing the dynamic input from Java class to your Python app we need a polyglot.Context instance, that has IO ops enabled.
  • We will need to capture the bindings for the target language.
  • The java app then updates this binding providing a dynamic input from the user. For that we use the putMember() method on the bindings.
  • Once the member(s) addition is successful we can access them from the target language code block. We do so by directly using their property name. As a result, of using the putMember() these variables become environment variables for the target language. Consequently, they are now available within the context.

That is all for this blog, I hope you understood the concept of polyglot with GraalVm. The complete code is available here: https://github.com/knoldus/GraalVmPolyglot. For other instructions like how to setup graalVm locally, and how to run this application please refer to the readme.md file in the repo. However, in case you find yourself stuck, feel free to comment here. I will be more than happy to help and resolve your concerns. Until next time, keep learning. 🙂

References:

Knoldus-blog-footer-image

Written by 

Prashant is a Senior Software Consultant having experience more than 5 years, both in service development and client interaction. He is familiar with Object-Oriented Programming Paradigms and has worked with Java and Scala-based technologies and has experience working with the reactive technology stack, following the agile methodology. He's currently involved in creating reactive microservices some of which are already live and running successfully in production, he has also worked upon scaling of these microservices by implementing the best practices of APIGEE-Edge. He is a good team player, and currently managing a team of 4 people. He's always eager to learn new and advance concepts in order to expand his horizon and apply them in project development with his skills. His hobbies include Teaching, Playing Sports, Cooking, watching Sci-Fi movies and traveling with friends.