Introduction

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.

Often developers have to make uncomfortable compromises that require them to rewrite their software in other languages. For example:

  • “That library is not available in my language. I need to rewrite it.”
  • “That language would be the perfect fit for my problem, but we cannot run it in our environment.”
  • “That problem is already solved in my language, but the language is too slow.”

With GraalVM we aim to allow developers to freely choose the right language for the task at hand without making compromises.Throughout this section you learn how to combine multiple languages using our polyglot APIs.

Running Polyglot Applications

The following examples are designed to get you started with a basic polyglot application.Select a section for your Start Language and then select a tab for the Target Language.

Ensure you set up GraalVM and export the GraalVM home directory as the $GRAALVM_HOME before you begin. See Get Started.

Note that these examples work in all scenarios:

  • On JVM, by passing —polyglot —jvm.
  • On native launchers with —polyglot (e.g., js —polyglot).Note that it might be required to rebuild images to access languages installed with gu.
  • With native image executables (e.g., native-image —language:js).

For native launchers and native image executables using Java as the Target Languageand accessing other classes than Java arrays, it is required to recompile the image and providea reflection configuration file.

Requirement: to start an application with LLVM as a Target Language, make sure to precompile polyglot.c file provided below.

Start from JavaScript / Node.js

Create a file polyglot.js:

Polyglot Reference - 图1

  1. // BEGIN-SNIPPET
  2. var array = Polyglot.eval("R", "c(1,2,42,4)")
  3. console.log(array[2]);
  4. // END-SNIPPET

Polyglot Reference - 图2

  1. // BEGIN-SNIPPET
  2. var array = Polyglot.eval("ruby", "[1,2,42,4]")
  3. console.log(array[2]);
  4. // END-SNIPPET

Polyglot Reference - 图3

  1. // BEGIN-SNIPPET
  2. var array = Polyglot.eval("python", "[1,2,42,4]")
  3. console.log(array[2]);
  4. // END-SNIPPET

Polyglot Reference - 图4

  1. // BEGIN-SNIPPET
  2. var array = new (Java.type("int[]"))(4);
  3. array[2] = 42;
  4. console.log(array[2])
  5. // END-SNIPPET

Polyglot Reference - 图5

  1. // BEGIN-SNIPPET
  2. var cpart = Polyglot.evalFile("llvm", "polyglot.bc");
  3. cpart.main()
  4. // END-SNIPPET

Run:

  1. $ js --polyglot --jvm polyglot.js
  2. 42
  3. $ node --polyglot --jvm polyglot.js
  4. 42

Start Language R

Create a file polyglot.R:

Polyglot Reference - 图6

  1. # BEGIN-SNIPPET
  2. array <- eval.polyglot("js", "[1,2,42,4]")
  3. print(array[3L])
  4. # END-SNIPPET

Polyglot Reference - 图7

  1. # BEGIN-SNIPPET
  2. array <- eval.polyglot("ruby", "[1,2,42,4]")
  3. print(array[3L])
  4. # END-SNIPPET

Polyglot Reference - 图8

  1. # BEGIN-SNIPPET
  2. array <- eval.polyglot("python", "[1,2,42,4]")
  3. print(array[3L])
  4. # END-SNIPPET

Polyglot Reference - 图9

  1. # BEGIN-SNIPPET
  2. array <- new("int[]", 4)
  3. array[3L] <- 42
  4. print(array[3L])
  5. # END-SNIPPET

Polyglot Reference - 图10

  1. # BEGIN-SNIPPET
  2. cpart <- eval.polyglot("llvm", path="polyglot.bc")
  3. cpart$main()
  4. # END-SNIPPET

Run:

  1. $ Rscript --polyglot --jvm polyglot.R
  2. [1] 42

Start Language Ruby:

Create a file polyglot.rb:

Polyglot Reference - 图11

  1. # BEGIN-SNIPPET
  2. array = Polyglot.eval('js', '[1,2,42,4]')
  3. puts array[2]
  4. # END-SNIPPET

Polyglot Reference - 图12

  1. # BEGIN-SNIPPET
  2. array = Polyglot.eval('R', 'c(1L,2L,42L,4L)')
  3. puts array[2]
  4. # END-SNIPPET

Polyglot Reference - 图13

  1. # BEGIN-SNIPPET
  2. array = Polyglot.eval('python', '[1,2,42,4]')
  3. puts array[2]
  4. # END-SNIPPET

Polyglot Reference - 图14

  1. # BEGIN-SNIPPET
  2. array = Java.type('int[]').new(4)
  3. array[2] = 42
  4. print(array[2])
  5. # END-SNIPPET

Polyglot Reference - 图15

  1. # BEGIN-SNIPPET
  2. cpart = Polyglot.eval_file('llvm', 'polyglot.bc')
  3. cpart.main()
  4. # END-SNIPPET

Run:

  1. $ ruby --polyglot --jvm polyglot.rb
  2. 42

Start Language Python:

Create a file polyglot.py:

Polyglot Reference - 图16

  1. # BEGIN-SNIPPET
  2. import polyglot
  3. array = polyglot.eval(language="js", string="[1,2,42,4]")
  4. print(array[2])
  5. # END-SNIPPET

Polyglot Reference - 图17

  1. # BEGIN-SNIPPET
  2. import polyglot
  3. array = polyglot.eval(language="R", string="c(1L,2L,42L,4L)")
  4. print(array[2])
  5. # END-SNIPPET

Polyglot Reference - 图18

  1. # BEGIN-SNIPPET
  2. import polyglot
  3. array = polyglot.eval(language="ruby", string="[1,2,42,4]")
  4. print(array[2])
  5. # END-SNIPPET

Polyglot Reference - 图19

  1. # BEGIN-SNIPPET
  2. import java
  3. array = java.type("int[]")(4)
  4. array[2] = 42
  5. print(array[2])
  6. # END-SNIPPET

Polyglot Reference - 图20

  1. # BEGIN-SNIPPET
  2. import polyglot
  3. cpart = polyglot.eval(language="llvm", path="polyglot.bc")
  4. cpart.main()
  5. # END-SNIPPET

Run:

  1. $ graalpython --polyglot --jvm polyglot.py
  2. 42

Start Language Java:

Create a file Polyglot.java:

Polyglot Reference - 图21

  1. // BEGIN-SNIPPET
  2. import org.graalvm.polyglot.*;
  3. class Polyglot {
  4. public static void main(String[] args) {
  5. Context polyglot = Context.create();
  6. Value array = polyglot.eval("js", "[1,2,42,4]");
  7. int result = array.getArrayElement(2).asInt();
  8. System.out.println(result);
  9. }
  10. }
  11. // END-SNIPPET

Polyglot Reference - 图22

  1. // BEGIN-SNIPPET
  2. import org.graalvm.polyglot.*;
  3. class Polyglot {
  4. public static void main(String[] args) {
  5. Context polyglot = Context.newBuilder().
  6. allowAllAccess(true).build();
  7. Value array = polyglot.eval("R", "c(1,2,42,4)");
  8. int result = array.getArrayElement(2).asInt();
  9. System.out.println(result);
  10. }
  11. }
  12. // END-SNIPPET

Polyglot Reference - 图23

  1. // BEGIN-SNIPPET
  2. import org.graalvm.polyglot.*;
  3. class Polyglot {
  4. public static void main(String[] args) {
  5. Context polyglot = Context.newBuilder().
  6. allowAllAccess(true).build();
  7. Value array = polyglot.eval("ruby", "[1,2,42,4]");
  8. int result = array.getArrayElement(2).asInt();
  9. System.out.println(result);
  10. }
  11. }
  12. // END-SNIPPET

Polyglot Reference - 图24

  1. // BEGIN-SNIPPET
  2. import org.graalvm.polyglot.*;
  3. class Polyglot {
  4. public static void main(String[] args) {
  5. Context context = Context.newBuilder().allowIO(true).build();
  6. Value array = context.eval("python", "[1,2,42,4]");
  7. int result = array.getArrayElement(2).asInt();
  8. System.out.println(result);
  9. }
  10. }
  11. // END-SNIPPET

Polyglot Reference - 图25

  1. // BEGIN-SNIPPET
  2. import java.io.*;
  3. import org.graalvm.polyglot.*;
  4. class Polyglot {
  5. public static void main(String[] args) throws IOException {
  6. Context polyglot = Context.newBuilder().
  7. allowAllAccess(true).build();
  8. File file = new File("polyglot.bc");
  9. Source source = Source.newBuilder("llvm", file).build();
  10. Value cpart = polyglot.eval(source);
  11. cpart.getMember("main").execute();
  12. }
  13. }
  14. // END-SNIPPET

Run:

  1. $ javac Polyglot.java
  2. $ java Polyglot
  3. 42

Start Language C:

Note: This requires clang to be installed.

Create a file polyglot.c:

Polyglot Reference - 图26

  1. // BEGIN-SNIPPET
  2. #include <stdio.h>
  3. #include <polyglot.h>
  4. int main() {
  5. void *array = polyglot_eval("js", "[1,2,42,4]");
  6. int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
  7. printf("%d\n", element);
  8. return element;
  9. }
  10. // END-SNIPPET

Polyglot Reference - 图27

  1. // BEGIN-SNIPPET
  2. #include <stdio.h>
  3. #include <polyglot.h>
  4. int main() {
  5. void *array = polyglot_eval("R", "c(1,2,42,4)");
  6. int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
  7. printf("%d\n", element);
  8. return element;
  9. }
  10. // END-SNIPPET

Polyglot Reference - 图28

  1. // BEGIN-SNIPPET
  2. #include <stdio.h>
  3. #include <polyglot.h>
  4. int main() {
  5. void *array = polyglot_eval("ruby", "[1,2,42,4]");
  6. int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
  7. printf("%d\n", element);
  8. return element;
  9. }
  10. // END-SNIPPET

Polyglot Reference - 图29

  1. // BEGIN-SNIPPET
  2. #include <stdio.h>
  3. #include <polyglot.h>
  4. int main() {
  5. void *array = polyglot_eval("python", "[1,2,42,4]");
  6. int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
  7. printf("%d\n", element);
  8. return element;
  9. }
  10. // END-SNIPPET

Polyglot Reference - 图30

  1. // BEGIN-SNIPPET
  2. #include <stdio.h>
  3. #include <polyglot.h>
  4. int main() {
  5. void *arrayType = polyglot_java_type("int[]");
  6. void *array = polyglot_new_instance(arrayType, 4);
  7. polyglot_set_array_element(array, 2, 42);
  8. int element = polyglot_as_i32(polyglot_get_array_element(array, 2));
  9. printf("%d\n", element);
  10. return element;
  11. }
  12. // END-SNIPPET

Run:

  1. $ clang -g -O1 -c -emit-llvm -I$GRAALVM_HOME/jre/languages/llvm/include polyglot.c
  2. $ lli --polyglot --jvm polyglot.bc
  3. 42

How Does Polyglot Work

In order to provide foreign polyglot values in the languages implemented with theTruffle Language Implementation Framework,we have developed the so-called polyglot interoperability protocol. Thisinteroperability protocol consists of a set of standardized messages that everylanguage implements and uses for foreign polyglot values. The protocol allowsGraalVM to support interoperability between any combination of languages withoutrequiring them to know of each other. We plan to gradually improve the protocolto support more and more features over time.

For further details, we recommend reading:

Running Polyglot Applications

With polyglot applications it is often impossible to decide what the primarylanguage of an application is. Therefore, we have added an experimental newlauncher called polyglot to GraalVM. For the moment, this launcher runs codefor JavaScript, Ruby, and R without requiring the selection of a primarylanguage. The polyglot launcher does not require the —polyglot option, it isenabled by default.

This is how you can run a polyglot application by using the examples from above:

  1. $ polyglot --jvm polyglot.js polyglot.R polyglot.rb

We have also included a basic experimental shell for multiple languages calledthe Polyglot Shell. It is useful to quickly test to test the interactivity oflanguages implemented with the Truffle Language Implementation framework.This is how you can start it:

  1. $ polyglot --jvm --shell
  2. GraalVM MultiLanguage Shell 19.3.0.2
  3. Copyright (c) 2013-2019, Oracle and/or its affiliates
  4. JavaScript version 19.3.0.2
  5. Python version 3.7.4
  6. R version 3.6.1
  7. Ruby version 2.6.2
  8. Usage:
  9. Use Ctrl+L to switch language and Ctrl+D to exit.
  10. Enter -usage to get a list of available commands.
  11. js>

Warning: The polyglot launcher and the Polyglot Shell are experimental features in GraalVM.

Polyglot Options

You can configure language engine for better throughput or startup.

  • —engine.Mode=default: Configures the execution mode of the engine. The execution mode automatically tunes the polyglot engine towards latency or throughput.
    • throughput: To collect the maximum amount of profiling information and compile using the maximum number of optimizations. This mode results in slower application startup but better throughput. This mode uses the compiler configuration community or enterprise if not specified otherwise.
    • default: To use a balanced engine configuration. This mode uses the compiler configuration community or enterprise if not specified otherwise.
    • latency: To collect only minimal profiling information and compile as fast as possible with less optimal generated code. This mode results in faster application startup but less optimal throughput. This mode uses the compiler configuration economy if not specified otherwise.

Polyglot Options for Language Launchers

We have extended every language launcher with a set of so called polyglotoptions. Polyglot options allow users of any language launcher to access theoptions of other languages supported by GraalVM (implemented with the TruffleLanguage Implementation Framework).The format is: —<languageID>.<property>=<value>.For example the R launcher also supports the —js.atomics=true JavaScript option.

Allowed values for the languageID are:

  • js options for JavaScript.
  • python options for Python.
  • r options for R.
  • ruby options for Ruby.
  • llvm options for LLVM.

Use —help:languages to find out which options are available.

Options for polyglot tools work in the same way with the following format: —<toolID>.<property>=<value>.

Allowed values for <toolID> are:

  • inspect allows debugging with Chrome DevTools.
  • cpusampler collects data about CPU usage.
  • cputracer captures trace information about CPU usage.
  • memtracer captures trace information about memory usage.

Use —help:tools to find out which options are available.

Passing Options Programmatically

Options can also be passed programmatically using the Java polyglot API.

Create a file called OptionsTest.java:

  1. import org.graalvm.polyglot.*;
  2. class OptionsTest {
  3. public static void main(String[] args) {
  4. Context polyglot = Context.newBuilder().allowExperimentalOptions(true)
  5. .option("js.shared-array-buffer", "true")
  6. .build();
  7. // the use of shared array buffer requires
  8. // the 'js.shared-array-buffer' option to be 'true'
  9. polyglot.eval("js", "new SharedArrayBuffer(1024)");
  10. }
  11. }

Run:

  1. $ javac OptionsTest.java
  2. $ java OptionsTest

Please note that tool options can be passed in the same way.Options cannot be modified after the context was created.

Passing Options using JVM Arguments

Every polyglot option can also be passed as a Java system property.Each available option translates to a system property with the polyglot. prefix.For example: -Dpolyglot.js.strict=true sets the default value for a strict interpretation for all JavaScript code that runs in the JVM.Options that were set programmatically take precedence over Java system properties.For languages the following format can be used: -Dpolyglot.<languageID>.<property>=<value> and for tools it is: -Dpolyglot.<toolID>.<property>=<value>.

Create a file called SystemPropertiesTest.java:

  1. import org.graalvm.polyglot.*;
  2. class SystemPropertiesTest {
  3. public static void main(String[] args) {
  4. Context polyglot = Context.newBuilder().allowExperimentalOptions(true).build();
  5. // the use of shared array buffer requires
  6. // the 'js.shared-array-buffer' option to be 'true'
  7. polyglot.eval("js", "new SharedArrayBuffer(1024)");
  8. }
  9. }

Run:

  1. $ javac SystemPropertiesTest.java
  2. $ java -Dpolyglot.js.strict=true SystemPropertiesTest

Note: System properties are read once when the polyglot context is created. Subsequent changes have no effect.