diff --git a/.gitignore b/.gitignore index 1af98a5..f9e186c 100644 --- a/.gitignore +++ b/.gitignore @@ -82,3 +82,5 @@ yarn.lock !**/ios/**/default.pbxuser !**/ios/**/default.perspectivev3 !/packages/flutter_tools/test/data/dart_dependencies_test/**/.packages +/graalvm_test/build +/graalvm_test_native_interop/build diff --git a/graalvm_test_native_interop/.gitignore b/graalvm_test_native_interop/.gitignore new file mode 100644 index 0000000..3a85790 --- /dev/null +++ b/graalvm_test_native_interop/.gitignore @@ -0,0 +1,3 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ diff --git a/graalvm_test_native_interop/README.md b/graalvm_test_native_interop/README.md new file mode 100644 index 0000000..38fb7d1 --- /dev/null +++ b/graalvm_test_native_interop/README.md @@ -0,0 +1,53 @@ +# GraalVM Test + +This is a sample command-line application demonstrating how to use Dart's Java Native Interface (JNI) packages +(`jni` and `jnigen`) to interoperate with Java code, specifically the GraalVM Polyglot API. + +The application initializes a Java Virtual Machine (JVM) within a Dart environment, loads the necessary GraalVM JAR +files, and then executes a simple JavaScript snippet using GraalVM's polyglot capabilities. + +## How it Works + +The core logic is in `bin/graalvm_test.dart`. It performs the following steps: + +1. **Spawns a JVM**: It uses `Jni.spawn()` to start a JVM, providing the paths to the required GraalVM JAR files +located in the `mvn_jar` directory. +2. **Creates a Polyglot Context**: It creates a GraalVM `Context` for the JavaScript language. +3. **Executes JavaScript**: It evaluates a JavaScript string that defines a simple function. +4. **Interoperates**: It calls the JavaScript function from Dart, passing a string argument ("World") to it. +The JavaScript code then prints a message to the console. + +The Dart bindings for the GraalVM Polyglot API (`org.graalvm.polyglot.Context` and `org.graalvm.polyglot.Value`) are +generated by `jnigen` based on the configuration in `jnigen.yaml` and the Java source files in `mvn_java`. + +## Requirements + +* Dart SDK +* Java Development Kit (JDK) 17 + +## Setup + +1. **Get dependencies**: + ```bash + dart pub get + ``` + +2. **Generate JNI bindings**: + This project uses `jnigen` to generate the Dart code for Java classes. + Run the following command to generate the necessary files: + ```bash + dart run jni:setup + dart run jnigen:setup + dart run jnigen --config jnigen.yaml + ``` + The underlying graalvm libraries require OpenJDK 17 or higher. + +## Running the Application + +After completing the setup steps, run the application with the following command: + +```bash +dart run bin/graalvm_test.dart +``` + +You should see output from both Dart and the executed JavaScript code in your console. \ No newline at end of file diff --git a/graalvm_test_native_interop/analysis_options.yaml b/graalvm_test_native_interop/analysis_options.yaml new file mode 100644 index 0000000..dee8927 --- /dev/null +++ b/graalvm_test_native_interop/analysis_options.yaml @@ -0,0 +1,30 @@ +# This file configures the static analysis results for your project (errors, +# warnings, and lints). +# +# This enables the 'recommended' set of lints from `package:lints`. +# This set helps identify many issues that may lead to problems when running +# or consuming Dart code, and enforces writing Dart using a single, idiomatic +# style and format. +# +# If you want a smaller set of lints you can change this to specify +# 'package:lints/core.yaml'. These are just the most critical lints +# (the recommended set includes the core lints). +# The core lints are also what is used by pub.dev for scoring packages. + +include: package:lints/recommended.yaml + +# Uncomment the following section to specify additional rules. + +# linter: +# rules: +# - camel_case_types + +# analyzer: +# exclude: +# - path/to/excluded/files/** + +# For more information about the core and recommended set of lints, see +# https://dart.dev/go/core-lints + +# For additional information about configuring this file, see +# https://dart.dev/guides/language/analysis-options diff --git a/graalvm_test_native_interop/bin/graalvm_test.dart b/graalvm_test_native_interop/bin/graalvm_test.dart new file mode 100644 index 0000000..b6293e2 --- /dev/null +++ b/graalvm_test_native_interop/bin/graalvm_test.dart @@ -0,0 +1,35 @@ +import 'package:jni/jni.dart'; +import 'package:path/path.dart'; +import 'package:graalvm_test/graal/org/graalvm/polyglot/_package.dart' as graal; + +void main(List arguments) { + Jni.spawn( + dylibDir: join('build', 'jni_libs'), + classPath: [ + './mvn_jar/collections-24.2.2.jar', + './mvn_jar/icu4j-24.2.2.jar', + './mvn_jar/jniutils-24.2.2.jar', + './mvn_jar/js-language-24.2.2.jar', + './mvn_jar/nativebridge-24.2.2.jar', + './mvn_jar/nativeimage-24.2.2.jar', + './mvn_jar/polyglot-24.2.2.jar', + './mvn_jar/regex-24.2.2.jar', + './mvn_jar/truffle-api-24.2.2.jar', + './mvn_jar/truffle-compiler-24.2.2.jar', + './mvn_jar/truffle-enterprise-24.2.2.jar', + './mvn_jar/truffle-runtime-24.2.2.jar', + './mvn_jar/word-24.2.2.jar', + './mvn_jar/xz-24.2.2.jar' + ], + ); + + var jsCode = "(function myFun(param){console.log('Hello ' + param + ' from JS');})"; + + var langs = JArray.of(JString.type, ["js".toJString()]); + var context = graal.Context.create(langs); + var value = context?.eval$1("js".toJString(), jsCode.toJString()); + print(value); + value?.execute(JArray.of(JString.type, ["World".toJString()])); + return; +} + diff --git a/graalvm_test_native_interop/jnigen.yaml b/graalvm_test_native_interop/jnigen.yaml new file mode 100644 index 0000000..09f367c --- /dev/null +++ b/graalvm_test_native_interop/jnigen.yaml @@ -0,0 +1,12 @@ +output: + dart: + path: lib/graal/ + +classes: + - 'org.graalvm.polyglot.Context' + - 'org.graalvm.polyglot.Value' + +maven_downloads: + jar_only_deps: + - 'org.graalvm.polyglot:polyglot:24.2.1' + - 'org.graalvm.polyglot:js:24.2.2' diff --git a/graalvm_test_native_interop/lib/graalvm_test.dart b/graalvm_test_native_interop/lib/graalvm_test.dart new file mode 100644 index 0000000..f64ad72 --- /dev/null +++ b/graalvm_test_native_interop/lib/graalvm_test.dart @@ -0,0 +1,3 @@ +int calculate() { + return 6 * 7; +} diff --git a/graalvm_test_native_interop/pubspec.yaml b/graalvm_test_native_interop/pubspec.yaml new file mode 100644 index 0000000..816bcbe --- /dev/null +++ b/graalvm_test_native_interop/pubspec.yaml @@ -0,0 +1,17 @@ +name: graalvm_test +description: A sample command-line application. +version: 1.0.0 +# repository: https://github.com/my_org/my_repo + +environment: + sdk: ^3.10.0-36.0.dev + +# Add regular dependencies here. +dependencies: + path: ^1.9.0 + jni: ^0.14.2 + jnigen: ^0.14.2 + +dev_dependencies: + lints: ^6.0.0 + test: ^1.25.6