forked from oracle/graal
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[GR-7627] Update Truffle documentation.
PullRequest: graal/913
- Loading branch information
Showing
24 changed files
with
735 additions
and
1,364 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Graal Standard Development Kit | ||
|
||
The Graal SDK is a collection of APIs for the components of GraalVM. | ||
|
||
* The [`org.graalvm.polyglot`](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html) module contains APIs to embed Graal languages in Java host applications. | ||
* The [`org.graalvm.collections`](http://www.graalvm.org/sdk/javadoc/org/graalvm/collections/package-summary.html) module contains memory efficient common collection data structures used across Graal projects. | ||
* The [`org.graalvm.options`](http://www.graalvm.org/sdk/javadoc/org/graalvm/options/package-summary.html) module contains reusable classes for options. | ||
|
||
## Getting Started | ||
|
||
1. Download GraalVM from [Oracle Technology Network](http://www.oracle.com/technetwork/oracle-labs/program-languages/overview/). | ||
2. Use any of the Java executables in `./bin` or import GraalVM as JDK in your favorite IDE. | ||
3. Use Graal-SDK, the jar is put on the class path for you automatically. | ||
|
||
The Graal-SDK bits are also uploaded to Maven central. | ||
You can use it from your `pom.xml` file as: | ||
|
||
```xml | ||
<dependencies> | ||
<dependency> | ||
<groupId>org.graalvm</groupId> | ||
<artifactId>graal-sdk</artifactId> | ||
<version>0.30</version> | ||
</dependency> | ||
</dependencies> | ||
``` | ||
|
||
Please note that Graal SDK requires GraalVM to run. | ||
|
||
## Tutorials | ||
|
||
* [Tutorial](./docs/PolyglotEmbedding.md) on using the polyglot API to embed Graal languages in Java host applications. | ||
|
||
## Changes | ||
|
||
Important API changes and additions are tracked in the [SDK changelog](./CHANGELOG.md). | ||
|
||
|
||
## License | ||
|
||
[Graal SDK](../sdk) is licensed under the [GPL 2 with Classpath exception](./LICENSE.md). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,331 @@ | ||
# Hello Polyglot World | ||
|
||
The Graal Polyglot SDK lets you embed and run code from guest languages in | ||
JVM-based host applications. | ||
|
||
Throughout this section you learn how to create a host application in Java that | ||
runs on GraalVM and directly calls a guest language. You will learn this using the JavaScript language as an example. | ||
The Javadoc reference for the polyglot API can be found [here](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/package-summary.html). | ||
|
||
Ensure you set up GraalVM before you begin. See [Get Started](../README.md). | ||
|
||
## Compile and Run a Polyglot Application | ||
|
||
Polyglot applications run code written in any programming language that GraalVM | ||
supports. These programming languages are also known as Graal languages. | ||
|
||
Complete the steps in this section to create a sample polyglot | ||
application that runs on GraalVM and demonstrates programming language | ||
interoperability. | ||
|
||
1. Create a `hello-polyglot` project directory. | ||
|
||
2. In your project directory, add a `HelloPolyglot.java` file that includes | ||
the following code: | ||
|
||
```java | ||
public class HelloPolyglot { | ||
public static void main(String[] args) { | ||
System.out.println("Hello Java!"); | ||
Context context = Context.create(); | ||
context.eval("js", "print('Hello JavaScript!');"); | ||
} | ||
} | ||
``` | ||
|
||
In this code: | ||
* `import org.graalvm.polyglot.*` imports the API for the Graal Polyglot SDK. | ||
* `Context` provides an execution environment for guest languag* . | ||
* `eval` evaluates the specified snippet of guest language code. | ||
|
||
3. Run `javac HelloPolyglot.java` to compile `HelloPolyglot.java` with | ||
GraalVM. | ||
|
||
4. Run `java HelloPolyglot` to run the application on GraalVM. | ||
|
||
You now have a polyglot application that consists of a Java host application | ||
and guest language code that run on GraalVM. You can use this application with | ||
other code examples to demonstrate more advanced capabilities of the | ||
Graal Polyglot SDK. | ||
|
||
To use other code examples in this section, you simply need to do the following: | ||
|
||
1. Add the code snippet to the main method of `HelloPolyglot.java`. | ||
|
||
2. Compile and run your polyglot application. | ||
|
||
## Define Guest Language Functions as Java Values | ||
Polyglot applications let you take values from one programming language and | ||
use them with other languages. | ||
|
||
Use the code example in this section with your polyglot application to show | ||
how the Graal Polyglot SDK can return JavaScript, R, Ruby or Python functions as Java | ||
values. | ||
|
||
```java | ||
Context context = Context.create(); | ||
Value function = context.eval("js", "function(x) x + 1"); | ||
assert function.canExecute(); | ||
int x = function.execute(41).asInt(); | ||
assert x == 42; | ||
``` | ||
|
||
In this code: | ||
- `Value` is a Java value that refers to a function. | ||
- The `eval` call parses the script and returns the Graal language function. | ||
- The first assertion checks that the value returned by the code snippet can be | ||
executed. | ||
- The `execute` call executes the function with the argument `41`. | ||
- The `asInt` call converts the result to a Java `int`. | ||
- The second assertion checks that the Java integer has a value of `42`. | ||
|
||
## Access Graal Languages Directly from Java | ||
Polyglot applications, can readily access most language types and are not | ||
limited to functions. Host languages, such as Java, can directly access guest | ||
language code embedded in the polyglot application. | ||
|
||
Use the code example in this section with your polyglot application to show | ||
how the Graal Polyglot SDK can access numbers, strings, and arrays. | ||
|
||
```java | ||
Context context = Context.create(); | ||
Value result = context.eval("js", "({ " + | ||
"id : 42, " + | ||
"text : '42', " + | ||
"arr : [1,42,3] " + | ||
"})"); | ||
assert result.hasMembers(); | ||
|
||
int id = result.getMember("id").asInt(); | ||
assert id == 42; | ||
|
||
String text = result.getMember("text").asString(); | ||
assert text.equals("42"); | ||
|
||
Value array = result.getMember("arr"); | ||
assert array.hasArrayElements(); | ||
assert array.getArraySize() == 3; | ||
assert array.getArrayElement(1).asInt() == 42; | ||
``` | ||
|
||
In this code: | ||
- `Value result` is an Object that contains three members: a number named `id`, | ||
a string named `text`, and an array named `arr`. | ||
- The first assertion verifies that the return value can contain members, which | ||
indicates that the value is an object-like structure. | ||
- The `id` variable is initialized by reading the member with the name `id` from | ||
the resulting object. The result is then converted to a Java `int` | ||
using `asInt()`. | ||
- The next assert verifies that result has a value of `42`. | ||
- The `text` variable is initialized using the value of the member `text`, | ||
which is also converted to a Java `String` using `asString()`. | ||
- The following assertion verifies the result value is equal to the | ||
Java `String` `"42"`. | ||
- Next the `arr` member that holds an array is read. | ||
- Arrays return `true` for `hasArrayElements`. R array instances can have | ||
members and array elements at the same time. | ||
- The next assertion verifies that the size of the array equals three. The | ||
Graal Polyglot SDK supports big arrays, so the array length is of type `long`. | ||
- Finally we verify that the array element at index `1` equals `42`. Array | ||
indexing with polyglot values is always zero-based, even for languages such as | ||
R where indices start with one. | ||
|
||
## Access Java from Graal Languages | ||
Polyglot applications offer bi-directional access between guest languages and | ||
host languages. As a result, you can pass Java objects to Graal languages. | ||
|
||
Use the code example in this section with your polyglot application to show how | ||
Graal languages can access primitive Java values, objects, arrays, and | ||
functional interfaces. | ||
|
||
**Note:** This code example is supported when running on the Java Virtual | ||
Machine (JVM) only. Running in native image executables is not currently | ||
supported. | ||
|
||
```java | ||
public static class MyClass { | ||
public int id = 42; | ||
public String text = "42"; | ||
public int[] arr = new int[]{1, 42, 3}; | ||
public Callable<Integer> ret42 = () -> 42; | ||
} | ||
|
||
public static void main(String[] args) { | ||
Context context = Context.create(); | ||
context.exportSymbol("javaObj", new MyClass()); | ||
boolean valid = context.eval("js", | ||
"javaObj = Interop.import('javaObj');" + | ||
" javaObj.id == 42" + | ||
" && javaObj.text == '42'" + | ||
" && javaObj.arr[1] == 42" + | ||
" && javaObj.ret42() == 42") | ||
.asBoolean(); | ||
assert valid == true; | ||
} | ||
``` | ||
|
||
In this code: | ||
- The Java class `MyClass` has four public fields `id`, `text`, `arr` and | ||
`ret42`. The fields are initialized with `int`, `String`, `int[]` and | ||
lambda `() -> 42` that always returns an `int` value of `42`. | ||
- The Java class `MyClass` is instantiated and exported with the name `javaObj` | ||
into the polyglot scope, which allows the host and guest languages to exchange | ||
symbols. | ||
- A Graal language script is evaluated that imports the `javaObj` symbol and | ||
assigns it to the local variable which is also named `javaObj`. To avoid | ||
conflicts with variables, every value in the polyglot scope must be explicitly | ||
imported and exported in the top-most scope of the language. | ||
- The next two lines verify the contents of the Java object by comparing it | ||
to the number `42` and the string `'42'`. | ||
- The third verification reads from the second array position and compares it | ||
to the number `42`. Whether arrays are accessed using 0-based or 1-based indices | ||
depends on the Graal language. Independently of the language, the Java array | ||
stored in field `arr` is always accessed using translated 0-based indices. For | ||
example, in the R language, arrays are 1-based so the second array element is | ||
accessible using index `2`. In the JavaScript and Ruby languages, the second | ||
array element is at index `1`. In all language examples, the Java array is read | ||
from using the same index `1`. | ||
- The last line invokes the Java lambda that is contained in the field `ret42` | ||
and compares the result to the `42` number value. | ||
- After the Graal language script executes, validation takes place to ensure | ||
that the script returns a `boolean` value of `true` as a result. | ||
|
||
|
||
## Computed Arrays Using Polyglot Proxies | ||
The Graal Polyglot SDK includes polyglot proxy interfaces that let you | ||
customize Java interoperability by mimicking guest language types, such as | ||
objects, arrays, native objects, or primitives. | ||
|
||
Use the code example in this section with your polyglot application to see how | ||
you can implement arrays that compute their values lazily. | ||
|
||
**Note:** The Graal Polyglot SDK supports polyglot proxies either on the JVM or | ||
in a native image executable. | ||
|
||
```java | ||
static class ComputedArray implements ProxyArray { | ||
public Object get(long index) { | ||
return index * 2; | ||
} | ||
public void set(long index, Value value) { | ||
throw new UnsupportedOperationException(); | ||
} | ||
public long getSize() { | ||
return Long.MAX_VALUE; | ||
} | ||
} | ||
|
||
public static void main(String[] args) { | ||
Context context = Context.create(); | ||
context.exportSymbol("arr", new ComputedArray()); | ||
long result = context.eval("js", | ||
"arr = Interop.import('arr');" + | ||
"arr[1] + arr[1000000000]") | ||
.asLong(); | ||
assert result == 2000000002L; | ||
} | ||
``` | ||
|
||
In this code: | ||
- The Java class `ComputedArray` implements the proxy interface `ProxyArray` so | ||
that Graal languages treat instances of the Java class like arrays. | ||
- `ComputedArray` array overrides the method `get` and computes the value | ||
using an arithmetic expression. | ||
- The array proxy does not support write access. For this reason, it throws | ||
an `UnsupportedOperationException` in the implementation of `set`. | ||
- The implementation for `getSize` returns `Long.MAX_VALUE` for its length. | ||
- The main method creates a new polyglot execution context. | ||
- A new instance of the `ComputedArray` class is then exported using the name `arr`. | ||
- The guest language script imports the `arr` symbol, which returns the | ||
exported proxy. | ||
- The second element and the `1000000000`th element is accessed, summed up, and | ||
then returned. Note that array indices from 1-based languages such as R are | ||
converted to 0-based indices for proxy arrays. | ||
- The result of the language script is returned as a long value and verified. | ||
|
||
For more information about the polyglot proxy interfaces, see the | ||
[Polyglot API JavaDoc](http://www.graalvm.org/sdk/javadoc/org/graalvm/polyglot/proxy/package-summary.html). | ||
|
||
|
||
## Reliable Timeouts for Malicious Code | ||
If your polyglot application runs untrusted code from a third-party source, the | ||
Graal Polyglot SDK lets you reliably cancel guest language execution after a | ||
timeout interval to protect against malicious code. | ||
|
||
**Note:** A similar security feature for memory allocation is planned for a | ||
future version of the Graal Polyglot SDK. | ||
|
||
Use the code example in this section with your polyglot application to see how | ||
malicious code can be reliably cancelled. | ||
|
||
```java | ||
Context context = Context.create(); | ||
context.initialize("js"); | ||
|
||
Timer timer = new Timer(true); | ||
timer.schedule(new TimerTask() { | ||
@Override | ||
public void run() { | ||
context.close(true); | ||
} | ||
}, 1000); | ||
|
||
try { | ||
String maliciousCode = "while(true);"; | ||
context.eval("js", maliciousCode); | ||
assert false; | ||
} catch (PolyglotException e) { | ||
assert e.isCancelled(); | ||
} | ||
``` | ||
|
||
In this code: | ||
- The first line of code creates a new context for any language. | ||
- The second line of code ensures the language is initialized. This prevents | ||
the execution from being cancelled during context initialization. | ||
- A new `java.util.Timer` instance is created. | ||
- To close the context, a new `TimerTask` is scheduled to run after one | ||
second. The `true` parameter to `close` indicates that the execution should be | ||
cancelled if it is currently running. | ||
- Malicious code, an infinite while loop, is evaluated. The malicious code will | ||
never complete. For this reason, the timer task closes and cancels the | ||
execution. This scenario causes a `PolyglotException` to be thrown. | ||
- Finally, in the exception catch block, the exception is verified as | ||
originating from a cancel event. | ||
|
||
|
||
## Build a Shell for Many Languages | ||
With just a few lines of code, the Graal Polyglot API lets you build | ||
applications that integrate with any Graal language that is available by | ||
default with GraalVM. | ||
|
||
This shell implementation is agnostic to any particular Graal language. | ||
|
||
```java | ||
BufferedReader input = new BufferedReader(new InputStreamReader(System.in)); | ||
PrintStream output = System.out; | ||
Context context = Context.create(); | ||
Set<String> languages = context.getEngine().getLanguages().keySet(); | ||
output.println("Shell for " + languages + ":"); | ||
String language = languages.iterator().next(); | ||
for (;;) { | ||
try { | ||
output.print(language + "> "); | ||
String line = input.readLine(); | ||
if (line == null) { | ||
break; | ||
} else if (languages.contains(line)) { | ||
language = line; | ||
continue; | ||
} | ||
Source source = Source.newBuilder(language, line, "<shell>") | ||
.interactive(true).buildLiteral(); | ||
context.eval(source); | ||
} catch (PolyglotException t) { | ||
if(t.isExit()) { | ||
break; | ||
} | ||
t.printStackTrace(); | ||
} | ||
} | ||
``` |
Oops, something went wrong.