From ff7c88bf6cf6043c088ace2b50e71fc848210e84 Mon Sep 17 00:00:00 2001 From: Chad Retz Date: Tue, 28 Nov 2017 17:00:38 -0600 Subject: [PATCH] First Rust example for issue #9 --- .gitignore | 3 + build.gradle | 63 +++++++++++++++++++ .../main/kotlin/asmble/compile/jvm/Linker.kt | 2 +- examples/rust-simple/.cargo/config | 2 + examples/rust-simple/Cargo.toml | 6 ++ examples/rust-simple/README.md | 24 +++++++ examples/rust-simple/src/lib.rs | 4 ++ .../java/asmble/examples/rustsimple/Main.java | 14 +++++ settings.gradle | 5 +- 9 files changed, 121 insertions(+), 2 deletions(-) create mode 100644 examples/rust-simple/.cargo/config create mode 100644 examples/rust-simple/Cargo.toml create mode 100644 examples/rust-simple/README.md create mode 100644 examples/rust-simple/src/lib.rs create mode 100644 examples/rust-simple/src/main/java/asmble/examples/rustsimple/Main.java diff --git a/.gitignore b/.gitignore index 7cfc389..f2a45eb 100644 --- a/.gitignore +++ b/.gitignore @@ -10,3 +10,6 @@ /emscripten-runtime/out /annotations/build /annotations/out +/examples/rust-simple/Cargo.lock +/examples/rust-simple/build +/examples/rust-simple/target diff --git a/build.gradle b/build.gradle index eb692a5..aefe7ca 100644 --- a/build.gradle +++ b/build.gradle @@ -7,9 +7,13 @@ buildscript { repositories { mavenCentral() + maven { + url "https://plugins.gradle.org/m2/" + } } dependencies { classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version" + classpath 'me.champeau.gradle:jmh-gradle-plugin:0.4.4' } } @@ -49,3 +53,62 @@ project(':compiler') { testCompile "org.ow2.asm:asm-debug-all:$asm_version" } } + +project(':examples') { + subprojects { + dependencies { + compileOnly project(':compiler') + } + + task rustToWasm(type: Exec) { + commandLine 'cargo', 'build', '--release' + } + + ext.wasmFileName = { -> + def wasmFiles = fileTree(dir: 'target/wasm32-unknown-unknown/release', includes: ['*.wasm']).files + if (wasmFiles.size() != 1) throw new GradleException('Expected single WASM file, got ' + wasmFiles.size()) + return wasmFiles.iterator().next() + } + + task wasmFile() { + dependsOn rustToWasm + doFirst { + println 'File: ' + wasmFileName() + } + } + + task showWast(type: JavaExec) { + dependsOn rustToWasm + classpath configurations.compileClasspath + main = 'asmble.cli.MainKt' + doFirst { + args 'translate', wasmFileName() + } + } + + task compileWasm(type: JavaExec) { + dependsOn rustToWasm + classpath configurations.compileClasspath + main = 'asmble.cli.MainKt' + doFirst { + // args 'help', 'compile' + def outFile = 'build/wasm-classes/' + wasmCompiledClassName.replace('.', '/') + '.class' + file(outFile).parentFile.mkdirs() + args 'compile', wasmFileName(), wasmCompiledClassName, '-out', outFile + } + } + } +} + +project(':examples:rust-simple') { + apply plugin: 'application' + ext.wasmCompiledClassName = 'asmble.generated.RustSimple' + dependencies { + compile files('build/wasm-classes') + } + compileJava { + dependsOn compileWasm + } + + mainClassName = 'asmble.examples.rustsimple.Main' +} \ No newline at end of file diff --git a/compiler/src/main/kotlin/asmble/compile/jvm/Linker.kt b/compiler/src/main/kotlin/asmble/compile/jvm/Linker.kt index 681c529..5e74461 100644 --- a/compiler/src/main/kotlin/asmble/compile/jvm/Linker.kt +++ b/compiler/src/main/kotlin/asmble/compile/jvm/Linker.kt @@ -79,7 +79,7 @@ open class Linker { params = params.map(ModuleClass::ref), ret = mod.ref ) - // The stack here on our is for building params to constructor... + // The stack here on out is for building params to constructor... // The constructor we'll use is: // * Mem-class based constructor if it's an import diff --git a/examples/rust-simple/.cargo/config b/examples/rust-simple/.cargo/config new file mode 100644 index 0000000..435ed75 --- /dev/null +++ b/examples/rust-simple/.cargo/config @@ -0,0 +1,2 @@ +[build] +target = "wasm32-unknown-unknown" \ No newline at end of file diff --git a/examples/rust-simple/Cargo.toml b/examples/rust-simple/Cargo.toml new file mode 100644 index 0000000..6762097 --- /dev/null +++ b/examples/rust-simple/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "rust_simple" +version = "0.1.0" + +[lib] +crate-type = ["cdylib"] \ No newline at end of file diff --git a/examples/rust-simple/README.md b/examples/rust-simple/README.md new file mode 100644 index 0000000..3de9691 --- /dev/null +++ b/examples/rust-simple/README.md @@ -0,0 +1,24 @@ +### Example: Rust Simple + +This shows a simple example of compiling Rust to WASM and then to the JVM. + +The [root build script](../../build.gradle) actually has the build commands to build it. But basically it runs +`cargo build --release` on this directory which compiles `add_one` from [lib.rs](src/lib.rs) into +`target/wasm32-unknown-unknown/release/rust_simple.wasm`. Then the build script takes that wasm file and compiles it +to `asmble.generated.RustSimple` in `build/wasm-classes`. The class is used by +[Main.java](src/main/java/asmble/examples/rustsimple/Main.java). It is instantiated with a set of memory and then +`add_one` is invoked with `25` to return `26`. + +To run it yourself, run the following from the root `asmble` dir (assuming you have built the Gradle wrapper described +in the root README's "Building and Testing" section): + + ./gradlew --no-daemon :examples:rust-simple:run + +Yes, this does include Rust's std lib, but it's not that big of a deal. The actual method executed for `add_one` looks +like this decompiled: + +```java + private int $func0(final int n) { + return n + 1; + } +``` \ No newline at end of file diff --git a/examples/rust-simple/src/lib.rs b/examples/rust-simple/src/lib.rs new file mode 100644 index 0000000..da5a569 --- /dev/null +++ b/examples/rust-simple/src/lib.rs @@ -0,0 +1,4 @@ +#[no_mangle] +pub extern "C" fn add_one(x: i32) -> i32 { + x + 1 +} \ No newline at end of file diff --git a/examples/rust-simple/src/main/java/asmble/examples/rustsimple/Main.java b/examples/rust-simple/src/main/java/asmble/examples/rustsimple/Main.java new file mode 100644 index 0000000..7255bef --- /dev/null +++ b/examples/rust-simple/src/main/java/asmble/examples/rustsimple/Main.java @@ -0,0 +1,14 @@ +package asmble.examples.rustsimple; + +import asmble.generated.RustSimple; + +class Main { + // 20 pages is good for now + private static final int PAGE_SIZE = 65536; + private static final int MAX_MEMORY = 20 * PAGE_SIZE; + + public static void main(String[] args) { + RustSimple simple = new RustSimple(MAX_MEMORY); + System.out.println("25 + 1 = " + simple.add_one(25)); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 17cdd58..163d42b 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,2 +1,5 @@ rootProject.name = 'asmble' -include 'annotations', 'compiler', 'emscripten-runtime' \ No newline at end of file +include 'annotations', + 'compiler', + 'emscripten-runtime', + 'examples:rust-simple' \ No newline at end of file