From 56c2c8d672ae2c065c6d46c3e21465012fc98e2d Mon Sep 17 00:00:00 2001 From: "C.Solovev" Date: Mon, 1 Oct 2018 13:39:08 +0400 Subject: [PATCH 1/5] Fix lateinit error with logger for wasm files --- .../main/kotlin/asmble/cli/ScriptCommand.kt | 20 +++++++++++-------- .../src/main/kotlin/asmble/cli/Translate.kt | 2 +- .../src/main/kotlin/asmble/io/BinaryToAst.kt | 3 +-- 3 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/src/main/kotlin/asmble/cli/ScriptCommand.kt b/compiler/src/main/kotlin/asmble/cli/ScriptCommand.kt index f30a9a5..22715e5 100644 --- a/compiler/src/main/kotlin/asmble/cli/ScriptCommand.kt +++ b/compiler/src/main/kotlin/asmble/cli/ScriptCommand.kt @@ -56,16 +56,20 @@ abstract class ScriptCommand : Command() { // if input file is class file "class" -> ctx.classLoader.addClass(File(inFile).readBytes()).let { ctx } // if input file is wasm file - else -> Translate.also { it.logger = logger }.inToAst(inFile, inFile.substringAfterLast('.')).let { inAst -> - val (mod, name) = (inAst.commands.singleOrNull() as? Script.Cmd.Module) ?: + else -> { + val translateCmd = Translate + translateCmd.logger = this.logger + translateCmd.inToAst(inFile, inFile.substringAfterLast('.')).let { inAst -> + val (mod, name) = (inAst.commands.singleOrNull() as? Script.Cmd.Module) ?: error("Input file must only contain a single module") - val className = name?.javaIdent?.capitalize() ?: + val className = name?.javaIdent?.capitalize() ?: "Temp" + UUID.randomUUID().toString().replace("-", "") - ctx.withCompiledModule(mod, className, name).let { ctx -> - if (name == null && index != args.inFiles.size - 1) - logger.warn { "File '$inFile' not last and has no name so will be unused" } - if (name == null || args.disableAutoRegister) ctx - else ctx.runCommand(Script.Cmd.Register(name, null)) + ctx.withCompiledModule(mod, className, name).let { ctx -> + if (name == null && index != args.inFiles.size - 1) + logger.warn { "File '$inFile' not last and has no name so will be unused" } + if (name == null || args.disableAutoRegister) ctx + else ctx.runCommand(Script.Cmd.Register(name, null)) + } } } } diff --git a/compiler/src/main/kotlin/asmble/cli/Translate.kt b/compiler/src/main/kotlin/asmble/cli/Translate.kt index 146dfe9..c133f4d 100644 --- a/compiler/src/main/kotlin/asmble/cli/Translate.kt +++ b/compiler/src/main/kotlin/asmble/cli/Translate.kt @@ -70,7 +70,7 @@ open class Translate : Command() { } } "wasm" -> - Script(listOf(Script.Cmd.Module(BinaryToAst(logger = logger).toModule( + Script(listOf(Script.Cmd.Module(BinaryToAst(logger = this.logger).toModule( ByteReader.InputStream(inBytes.inputStream())), null))) else -> error("Unknown in format '$inFormat'") } diff --git a/compiler/src/main/kotlin/asmble/io/BinaryToAst.kt b/compiler/src/main/kotlin/asmble/io/BinaryToAst.kt index 67db443..9c70c9d 100644 --- a/compiler/src/main/kotlin/asmble/io/BinaryToAst.kt +++ b/compiler/src/main/kotlin/asmble/io/BinaryToAst.kt @@ -2,12 +2,11 @@ package asmble.io import asmble.ast.Node import asmble.util.* -import java.io.ByteArrayInputStream import java.nio.ByteBuffer open class BinaryToAst( val version: Long = 1L, - val logger: Logger = Logger.Print(Logger.Level.OFF), + val logger: Logger = Logger.Print(Logger.Level.WARN), val includeNameSection: Boolean = true ) : Logger by logger { From 58cf836b76391cd005eadb98d98255885a8dab28 Mon Sep 17 00:00:00 2001 From: "C.Solovev" Date: Mon, 1 Oct 2018 13:40:38 +0400 Subject: [PATCH 2/5] Disable Go and Rust examples and up project version --- build.gradle | 24 ++++++++++++------------ settings.gradle | 4 ++-- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/build.gradle b/build.gradle index a137d53..77e200d 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { allprojects { apply plugin: 'java' group 'com.github.cretz.asmble' - version '0.4.0-fl' + version '0.4.0-fl-fix' repositories { mavenCentral() @@ -143,17 +143,17 @@ project(':examples') { } -project(':examples:go-simple') { - apply plugin: 'application' - ext.wasmCompiledClassName = 'asmble.generated.GoSimple' - dependencies { - compile files('build/wasm-classes') - } - compileJava { - dependsOn compileGoWasm - } - mainClassName = 'asmble.examples.gosimple.Main' -} +//project(':examples:go-simple') { +// apply plugin: 'application' +// ext.wasmCompiledClassName = 'asmble.generated.GoSimple' +// dependencies { +// compile files('build/wasm-classes') +// } +// compileJava { +// dependsOn compileGoWasm +// } +// mainClassName = 'asmble.examples.gosimple.Main' +//} // todo temporary disable Rust regex, because some strings in wasm code exceed the size in 65353 bytes. diff --git a/settings.gradle b/settings.gradle index 3b6175d..951750a 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ rootProject.name = 'asmble' include 'annotations', 'compiler', 'examples:c-simple', - 'examples:go-simple', - 'examples:rust-regex', +// 'examples:go-simple', +// 'examples:rust-regex', // todo will be enabled when the problem with string max size will be solved 'examples:rust-simple', 'examples:rust-string' \ No newline at end of file From 765d8b4dbaa7d41ac41b5dd371fa0f29e3776a68 Mon Sep 17 00:00:00 2001 From: "C.Solovev" Date: Fri, 9 Nov 2018 10:03:44 +0400 Subject: [PATCH 3/5] Possibility to skip examples --- build.gradle | 70 ++++++++++++++++++++++++++++++++----------------- settings.gradle | 1 - 2 files changed, 46 insertions(+), 25 deletions(-) diff --git a/build.gradle b/build.gradle index 989bb5c..9ab9542 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,11 @@ buildscript { allprojects { apply plugin: 'java' group 'com.github.cretz.asmble' - version '0.4.0-fl' + version '0.4.1-fl' + + // skips building and running for the specified examples + ext.skipExamples = ['go-simple', 'rust-regex'] + // todo disabling Rust regex is temporary because some strings in wasm code exceed the size in 65353 bytes. repositories { mavenCentral() @@ -144,6 +148,10 @@ project(':examples') { project(':examples:go-simple') { + if (project.name in skipExamples) { + println("[Note!] Building and runnig for ${project.name} was skipped") + return + } apply plugin: 'application' ext.wasmCompiledClassName = 'asmble.generated.GoSimple' dependencies { @@ -155,32 +163,42 @@ project(':examples:go-simple') { mainClassName = 'asmble.examples.gosimple.Main' } -// todo temporary disable Rust regex, because some strings in wasm code exceed the size in 65353 bytes. + project(':examples:rust-regex') { + apply plugin: 'application' + apply plugin: 'me.champeau.gradle.jmh' + ext.wasmCompiledClassName = 'asmble.generated.RustRegex' + dependencies { + compile files('build/wasm-classes') + testCompile 'junit:junit:4.12' + } + compileJava { + dependsOn compileRustWasm + } + mainClassName = 'asmble.examples.rustregex.Main' -// project(':examples:rust-regex') { -// apply plugin: 'application' -// apply plugin: 'me.champeau.gradle.jmh' -// ext.wasmCompiledClassName = 'asmble.generated.RustRegex' -// dependencies { -// compile files('build/wasm-classes') -// testCompile 'junit:junit:4.12' -// } -// compileJava { -// dependsOn compileRustWasm -// } -// mainClassName = 'asmble.examples.rustregex.Main' -// test { -// testLogging.showStandardStreams = true -// testLogging.events 'PASSED', 'SKIPPED' -// } -// jmh { -// iterations = 5 -// warmupIterations = 5 -// fork = 3 -// } -// } + // the building will run but no test and benchmarks will run + if (project.name in skipExamples) { + println("[Note!] Building and runnig for ${project.name} was skipped") + test.onlyIf { false } // explicit skipping tests + return + } + + test { + testLogging.showStandardStreams = true + testLogging.events 'PASSED', 'SKIPPED' + } + jmh { + iterations = 5 + warmupIterations = 5 + fork = 3 + } + } project(':examples:rust-simple') { + if (project.name in skipExamples) { + println("[Note!] Building and runnig for ${project.name} was skipped") + return + } apply plugin: 'application' ext.wasmCompiledClassName = 'asmble.generated.RustSimple' dependencies { @@ -193,6 +211,10 @@ project(':examples:rust-simple') { } project(':examples:rust-string') { + if (project.name in skipExamples) { + println("[Note!] Building and runnig for ${project.name} was skipped") + return + } apply plugin: 'application' ext.wasmCompiledClassName = 'asmble.generated.RustString' dependencies { diff --git a/settings.gradle b/settings.gradle index 3b6175d..1c8c5ad 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,7 +1,6 @@ rootProject.name = 'asmble' include 'annotations', 'compiler', - 'examples:c-simple', 'examples:go-simple', 'examples:rust-regex', 'examples:rust-simple', From 21b023f1c62c15dc57edf7e43540b287bdd16876 Mon Sep 17 00:00:00 2001 From: "C.Solovev" Date: Fri, 9 Nov 2018 10:18:49 +0400 Subject: [PATCH 4/5] Return C example and skip it by default --- build.gradle | 73 +++++++++++++++++-- examples/c-simple/README.md | 14 ++++ examples/c-simple/src/lib.c | 3 + .../java/asmble/examples/csimple/Main.java | 13 ++++ settings.gradle | 1 + 5 files changed, 96 insertions(+), 8 deletions(-) create mode 100644 examples/c-simple/README.md create mode 100644 examples/c-simple/src/lib.c create mode 100644 examples/c-simple/src/main/java/asmble/examples/csimple/Main.java diff --git a/build.gradle b/build.gradle index 9ab9542..6c32e1e 100644 --- a/build.gradle +++ b/build.gradle @@ -24,7 +24,7 @@ allprojects { version '0.4.1-fl' // skips building and running for the specified examples - ext.skipExamples = ['go-simple', 'rust-regex'] + ext.skipExamples = ['c-simple', 'go-simple', 'rust-regex'] // todo disabling Rust regex is temporary because some strings in wasm code exceed the size in 65353 bytes. repositories { @@ -71,6 +71,38 @@ project(':examples') { dependencies { compileOnly project(':compiler') } + + // C/C++ example helpers + + task cToWasm { + doFirst { + mkdir 'build' + exec { + def cFileName = fileTree(dir: 'src', includes: ['*.c']).files.iterator().next() + commandLine 'clang', '--target=wasm32-unknown-unknown-wasm', '-O3', cFileName, '-c', '-o', 'build/lib.wasm' + } + } + } + + task showCWast(type: JavaExec) { + dependsOn cToWasm + classpath configurations.compileClasspath + main = 'asmble.cli.MainKt' + doFirst { + args 'translate', 'build/lib.wasm' + } + } + + task compileCWasm(type: JavaExec) { + dependsOn cToWasm + classpath configurations.compileClasspath + main = 'asmble.cli.MainKt' + doFirst { + def outFile = 'build/wasm-classes/' + wasmCompiledClassName.replace('.', '/') + '.class' + file(outFile).parentFile.mkdirs() + args 'compile', 'build/lib.wasm', wasmCompiledClassName, '-out', outFile + } + } // Go example helpers @@ -146,10 +178,31 @@ project(':examples') { } } +project(':examples:c-simple') { + if (project.name in skipExamples) { + println("[Note!] Building and runnig for ${project.name} was skipped") + test.onlyIf { false } // explicit skipping tests + compileJava.onlyIf { false } // explicit skipping compile + return + } + + apply plugin: 'application' + ext.wasmCompiledClassName = 'asmble.generated.CSimple' + dependencies { + compile files('build/wasm-classes') + } + + compileJava { + dependsOn compileCWasm + } + mainClassName = 'asmble.examples.csimple.Main' +} project(':examples:go-simple') { if (project.name in skipExamples) { println("[Note!] Building and runnig for ${project.name} was skipped") + test.onlyIf { false } // explicit skipping tests + compileJava.onlyIf { false } // explicit skipping compile return } apply plugin: 'application' @@ -164,6 +217,13 @@ project(':examples:go-simple') { } project(':examples:rust-regex') { + if (project.name in skipExamples) { + println("[Note!] Building and runnig for ${project.name} was skipped") + test.onlyIf { false } // explicit skipping tests + compileJava.onlyIf { false } // explicit skipping compile + compileTestJava.onlyIf { false } // explicit skipping compile + return + } apply plugin: 'application' apply plugin: 'me.champeau.gradle.jmh' ext.wasmCompiledClassName = 'asmble.generated.RustRegex' @@ -176,13 +236,6 @@ project(':examples:go-simple') { } mainClassName = 'asmble.examples.rustregex.Main' - // the building will run but no test and benchmarks will run - if (project.name in skipExamples) { - println("[Note!] Building and runnig for ${project.name} was skipped") - test.onlyIf { false } // explicit skipping tests - return - } - test { testLogging.showStandardStreams = true testLogging.events 'PASSED', 'SKIPPED' @@ -197,6 +250,8 @@ project(':examples:go-simple') { project(':examples:rust-simple') { if (project.name in skipExamples) { println("[Note!] Building and runnig for ${project.name} was skipped") + test.onlyIf { false } // explicit skipping tests + compileJava.onlyIf { false } // explicit skipping compile return } apply plugin: 'application' @@ -213,6 +268,8 @@ project(':examples:rust-simple') { project(':examples:rust-string') { if (project.name in skipExamples) { println("[Note!] Building and runnig for ${project.name} was skipped") + test.onlyIf { false } // explicit skipping tests + compileJava.onlyIf { false } // explicit skipping compile return } apply plugin: 'application' diff --git a/examples/c-simple/README.md b/examples/c-simple/README.md new file mode 100644 index 0000000..b1cd834 --- /dev/null +++ b/examples/c-simple/README.md @@ -0,0 +1,14 @@ +### Example: C Simple + +This shows a simple example of compiling C to WASM and then to the JVM. This is the C version of +[rust-simple](../rust-simple). + +In order to run the C or C++ examples, the latest LLVM binaries must be on the `PATH`, built with the experimental +WebAssembly target. This can be built by passing `-DLLVM_EXPERIMENTAL_TARGETS_TO_BUILD=WebAssembly` to `cmake` when +building WebAssembly. Or it can be downloaded from a nightly build site +([this one](http://gsdview.appspot.com/wasm-llvm/builds/) was used for these examples at the time of writing). + +Everything else is basically the same as [rust-simple](../rust-simple) except with C code and using `clang`. To run +execute the following from the root `asmble` dir: + + gradlew --no-daemon :examples:c-simple:run \ No newline at end of file diff --git a/examples/c-simple/src/lib.c b/examples/c-simple/src/lib.c new file mode 100644 index 0000000..c45f40d --- /dev/null +++ b/examples/c-simple/src/lib.c @@ -0,0 +1,3 @@ +int addOne(int x) { + return x + 1; +} \ No newline at end of file diff --git a/examples/c-simple/src/main/java/asmble/examples/csimple/Main.java b/examples/c-simple/src/main/java/asmble/examples/csimple/Main.java new file mode 100644 index 0000000..a073fb3 --- /dev/null +++ b/examples/c-simple/src/main/java/asmble/examples/csimple/Main.java @@ -0,0 +1,13 @@ +package asmble.examples.csimple; + +import java.lang.invoke.MethodHandle; + +import asmble.generated.CSimple; + +class Main { + public static void main(String[] args) { + // Doesn't need memory or method table + CSimple simple = new CSimple(0, new MethodHandle[0]); + System.out.println("25 + 1 = " + simple.addOne(25)); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index 1c8c5ad..3b6175d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1,6 +1,7 @@ rootProject.name = 'asmble' include 'annotations', 'compiler', + 'examples:c-simple', 'examples:go-simple', 'examples:rust-regex', 'examples:rust-simple', From 2bfa39a3c6a49de13c54fa0abf2f7dc38e9b28d1 Mon Sep 17 00:00:00 2001 From: "C.Solovev" Date: Fri, 9 Nov 2018 10:30:38 +0400 Subject: [PATCH 5/5] Tweaking after merge --- build.gradle | 2 +- settings.gradle | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 03473a0..6c32e1e 100644 --- a/build.gradle +++ b/build.gradle @@ -58,9 +58,9 @@ project(':compiler') { compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version" compile "org.ow2.asm:asm-tree:$asm_version" compile "org.ow2.asm:asm-util:$asm_version" + compile "org.ow2.asm:asm-commons:$asm_version" testCompile 'junit:junit:4.12' testCompile "org.jetbrains.kotlin:kotlin-test-junit:$kotlin_version" - testCompile "org.ow2.asm:asm-debug-all:$asm_version" } publishSettings(project, 'asmble-compiler', 'Asmble WASM Compiler') diff --git a/settings.gradle b/settings.gradle index 951750a..3b6175d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -2,7 +2,7 @@ rootProject.name = 'asmble' include 'annotations', 'compiler', 'examples:c-simple', -// 'examples:go-simple', -// 'examples:rust-regex', // todo will be enabled when the problem with string max size will be solved + 'examples:go-simple', + 'examples:rust-regex', 'examples:rust-simple', 'examples:rust-string' \ No newline at end of file