mirror of
https://github.com/fluencelabs/asmble
synced 2025-04-25 14:52:21 +00:00
Remove emscripten runtime originally for issue #7
This commit is contained in:
parent
2dddd90d2f
commit
7229ee6eb6
3
.gitignore
vendored
3
.gitignore
vendored
@ -11,9 +11,6 @@
|
|||||||
/compiler/bin
|
/compiler/bin
|
||||||
/compiler/build
|
/compiler/build
|
||||||
/compiler/out
|
/compiler/out
|
||||||
/emscripten-runtime/bin
|
|
||||||
/emscripten-runtime/build
|
|
||||||
/emscripten-runtime/out
|
|
||||||
/annotations/bin
|
/annotations/bin
|
||||||
/annotations/build
|
/annotations/build
|
||||||
/annotations/out
|
/annotations/out
|
||||||
|
@ -25,12 +25,6 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
project(':emscripten-runtime') {
|
|
||||||
dependencies {
|
|
||||||
compile project(':annotations')
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
project(':compiler') {
|
project(':compiler') {
|
||||||
apply plugin: 'kotlin'
|
apply plugin: 'kotlin'
|
||||||
apply plugin: 'application'
|
apply plugin: 'application'
|
||||||
@ -42,8 +36,7 @@ project(':compiler') {
|
|||||||
distZip.archiveName = 'asmble.zip'
|
distZip.archiveName = 'asmble.zip'
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
compile project(':emscripten-runtime')
|
compile project(':annotations')
|
||||||
|
|
||||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||||
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"
|
||||||
compile "org.ow2.asm:asm-tree:$asm_version"
|
compile "org.ow2.asm:asm-tree:$asm_version"
|
||||||
|
@ -1,21 +0,0 @@
|
|||||||
package asmble.io
|
|
||||||
|
|
||||||
open class Emscripten {
|
|
||||||
|
|
||||||
fun metadataFromWast(wast: String) =
|
|
||||||
wast.lastIndexOf(";; METADATA:").takeIf { it != -1 }?.let { metaIndex ->
|
|
||||||
wast.indexOfAny(listOf("\n", "\"staticBump\": "), metaIndex).
|
|
||||||
takeIf { it != -1 && wast[it] != '\n' }?.
|
|
||||||
let { bumpIndex ->
|
|
||||||
wast.indexOfAny(charArrayOf('\n', ','), bumpIndex).takeIf { it != -1 }?.let { commaIndex ->
|
|
||||||
wast.substring(bumpIndex + 14, commaIndex).trim().toIntOrNull()?.let { staticBump ->
|
|
||||||
Metadata(staticBump)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class Metadata(val staticBump: Int)
|
|
||||||
|
|
||||||
companion object : Emscripten()
|
|
||||||
}
|
|
@ -2,7 +2,6 @@ package asmble
|
|||||||
|
|
||||||
import asmble.ast.SExpr
|
import asmble.ast.SExpr
|
||||||
import asmble.ast.Script
|
import asmble.ast.Script
|
||||||
import asmble.io.Emscripten
|
|
||||||
import asmble.io.SExprToAst
|
import asmble.io.SExprToAst
|
||||||
import asmble.io.StrToSExpr
|
import asmble.io.StrToSExpr
|
||||||
|
|
||||||
@ -13,7 +12,6 @@ open class BaseTestUnit(val name: String, val wast: String, val expectedOutput:
|
|||||||
open val shouldFail get() = false
|
open val shouldFail get() = false
|
||||||
open val skipRunReason: String? get() = null
|
open val skipRunReason: String? get() = null
|
||||||
open val defaultMaxMemPages get() = 1
|
open val defaultMaxMemPages get() = 1
|
||||||
open val emscriptenMetadata by lazy { Emscripten.metadataFromWast(wast) }
|
|
||||||
open val parseResult: StrToSExpr.ParseResult.Success by lazy {
|
open val parseResult: StrToSExpr.ParseResult.Success by lazy {
|
||||||
StrToSExpr.parse(wast).let {
|
StrToSExpr.parse(wast).let {
|
||||||
when (it) {
|
when (it) {
|
||||||
|
@ -9,7 +9,6 @@ import asmble.io.ByteWriter
|
|||||||
import asmble.io.SExprToStr
|
import asmble.io.SExprToStr
|
||||||
import org.junit.Assume
|
import org.junit.Assume
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import run.jvm.emscripten.Env
|
|
||||||
import java.io.ByteArrayOutputStream
|
import java.io.ByteArrayOutputStream
|
||||||
import java.io.OutputStreamWriter
|
import java.io.OutputStreamWriter
|
||||||
import java.io.PrintWriter
|
import java.io.PrintWriter
|
||||||
@ -44,16 +43,6 @@ abstract class TestRunner<out T : BaseTestUnit>(val unit: T) : TestBase() {
|
|||||||
includeBinaryInCompiledClass = true
|
includeBinaryInCompiledClass = true
|
||||||
).withHarnessRegistered(PrintWriter(OutputStreamWriter(out, Charsets.UTF_8), true))
|
).withHarnessRegistered(PrintWriter(OutputStreamWriter(out, Charsets.UTF_8), true))
|
||||||
|
|
||||||
// If there's a staticBump, we are an emscripten mod and we need to include the env
|
|
||||||
var emEnv: Env? = null
|
|
||||||
unit.emscriptenMetadata?.also {
|
|
||||||
emEnv = Env(it.staticBump, out, "unknown-program")
|
|
||||||
val mods = Env.subModules.fold(listOf(Module.Native(emEnv!!))) { mods, subMod ->
|
|
||||||
mods + Module.Native(subMod.apply(emEnv))
|
|
||||||
}
|
|
||||||
scriptContext = scriptContext.withModuleRegistered("env", Module.Composite(mods))
|
|
||||||
}
|
|
||||||
|
|
||||||
// This will fail assertions as necessary
|
// This will fail assertions as necessary
|
||||||
scriptContext = unit.script.commands.fold(scriptContext) { scriptContext, cmd ->
|
scriptContext = unit.script.commands.fold(scriptContext) { scriptContext, cmd ->
|
||||||
try {
|
try {
|
||||||
@ -65,21 +54,6 @@ abstract class TestRunner<out T : BaseTestUnit>(val unit: T) : TestBase() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If there is a main, we run it w/ no args because emscripten doesn't set it as the start func
|
|
||||||
scriptContext.modules.lastOrNull()?.also { lastMod ->
|
|
||||||
lastMod.cls.methods.find { it.name == "main" && it.returnType == Int::class.java }?.let { mainMethod ->
|
|
||||||
if (mainMethod.parameterTypes.isEmpty())
|
|
||||||
mainMethod.invoke(lastMod.instance(scriptContext))
|
|
||||||
else if (mainMethod.parameterTypes.asList() == listOf(Int::class.java, Int::class.java))
|
|
||||||
mainMethod.invoke(lastMod.instance(scriptContext), emEnv?.argc ?: 0, emEnv?.argv ?: 0)
|
|
||||||
else
|
|
||||||
error("Unrecognized main method params for $mainMethod")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// If there was an emscripten env, we have to run the exit callbacks
|
|
||||||
emEnv?.also { it.runAtExitCallbacks(scriptContext.modules.last().instance(scriptContext)) }
|
|
||||||
|
|
||||||
// Check the output
|
// Check the output
|
||||||
unit.expectedOutput?.let {
|
unit.expectedOutput?.let {
|
||||||
// Sadly, sometimes the expected output is trimmed in Emscripten tests
|
// Sadly, sometimes the expected output is trimmed in Emscripten tests
|
||||||
|
@ -1,19 +0,0 @@
|
|||||||
package asmble.run.jvm.emscripten
|
|
||||||
|
|
||||||
import asmble.run.jvm.TestRunner
|
|
||||||
import org.junit.BeforeClass
|
|
||||||
import org.junit.runner.RunWith
|
|
||||||
import org.junit.runners.Parameterized
|
|
||||||
|
|
||||||
@RunWith(Parameterized::class)
|
|
||||||
class EmscriptenTest(unit: EmscriptenTestUnit) : TestRunner<EmscriptenTestUnit>(unit) {
|
|
||||||
companion object {
|
|
||||||
var failureReason: Throwable? = null
|
|
||||||
|
|
||||||
@JvmStatic @BeforeClass
|
|
||||||
fun setup() { failureReason?.also { throw it } }
|
|
||||||
|
|
||||||
@JvmStatic @Parameterized.Parameters(name = "{0}")
|
|
||||||
fun data() = try { EmscriptenTestUnit.allUnits } catch (t: Throwable) { failureReason = t; listOf(null) }
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,98 +0,0 @@
|
|||||||
package asmble.run.jvm.emscripten
|
|
||||||
|
|
||||||
import asmble.BaseTestUnit
|
|
||||||
import asmble.TestBase
|
|
||||||
import org.junit.Assert
|
|
||||||
import org.junit.AssumptionViolatedException
|
|
||||||
import java.io.File
|
|
||||||
import java.nio.file.Files
|
|
||||||
import java.nio.file.Path
|
|
||||||
import java.nio.file.Paths
|
|
||||||
import java.util.concurrent.TimeUnit
|
|
||||||
import java.util.stream.Collectors
|
|
||||||
|
|
||||||
class EmscriptenTestUnit(
|
|
||||||
name: String,
|
|
||||||
wast: String,
|
|
||||||
expectedOutput: String
|
|
||||||
) : BaseTestUnit(name, wast, expectedOutput) {
|
|
||||||
companion object {
|
|
||||||
val knownGoodNames = listOf(
|
|
||||||
"core/test_addr_of_stacked",
|
|
||||||
// TODO: this fails for me even in the browser on windows
|
|
||||||
// "core/test_alloca",
|
|
||||||
"core/test_alloca_stack",
|
|
||||||
"core/test_array2",
|
|
||||||
"core/test_array2b",
|
|
||||||
// TODO: use of undeclared identifier 'true'
|
|
||||||
// "core/test_assert",
|
|
||||||
// TODO: I'm running the callbacks, but nothing happening
|
|
||||||
// "core/test_atexit",
|
|
||||||
"core/test_atomic",
|
|
||||||
// TODO: lots of special calls, wait for emscripten-wasm to finish out
|
|
||||||
// "core/test_atomic_cxx",
|
|
||||||
"core/test_atoX",
|
|
||||||
// TODO: must use 'struct' tag to refer to type 'Struct'
|
|
||||||
// "core/test_bigarray",
|
|
||||||
// TODO: must use 'struct' tag to refer to type 'bitty'
|
|
||||||
// "core/test_bitfields"
|
|
||||||
"core/test_bsearch"
|
|
||||||
// TODO: unknown type name '_LIBCPP_BEGIN_NAMESPACE_STD'
|
|
||||||
// "core/test_bswap64"
|
|
||||||
// TODO: the rest...maybe if emscripten is cleaned up
|
|
||||||
)
|
|
||||||
|
|
||||||
val allUnits by lazy { loadUnits() }
|
|
||||||
|
|
||||||
fun loadUnits(): List<EmscriptenTestUnit> {
|
|
||||||
val wasmInstall = Paths.get(
|
|
||||||
System.getenv("WASM_INSTALL") ?: throw AssumptionViolatedException("WASM_INSTALL not set")
|
|
||||||
)
|
|
||||||
val testBase = wasmInstall.resolve("emscripten/tests")
|
|
||||||
fun Path.unitNameFromCFile() =
|
|
||||||
testBase.relativize(this).toString().substringBeforeLast(".c").replace('\\', '/')
|
|
||||||
// Obtain C files we know work
|
|
||||||
val goodCFiles = Files.walk(testBase).
|
|
||||||
filter { knownGoodNames.contains(it.unitNameFromCFile()) }.
|
|
||||||
collect(Collectors.toList())
|
|
||||||
// Go over each one and create a test unit
|
|
||||||
val tempDir = createTempDir("emscriptenout")
|
|
||||||
val isWindows = System.getProperty("os.name").contains("windows", true)
|
|
||||||
val emccCommand =
|
|
||||||
if (isWindows) arrayOf("cmd", "/c", wasmInstall.resolve("emscripten/emcc.bat").toString())
|
|
||||||
else arrayOf(wasmInstall.resolve("emscripten/emcc").toString())
|
|
||||||
try {
|
|
||||||
return goodCFiles.map { cFile ->
|
|
||||||
try {
|
|
||||||
// Run emcc on the cFile
|
|
||||||
val nameSansExt = cFile.fileName.toString().substringBeforeLast(".c")
|
|
||||||
val cmdArgs = emccCommand + cFile.toString() +
|
|
||||||
arrayOf("-s", "WASM=1", "-o", "$nameSansExt.html")
|
|
||||||
TestBase.logger.debug { "Running ${cmdArgs.joinToString(" ")}" }
|
|
||||||
val proc = ProcessBuilder(*cmdArgs).
|
|
||||||
directory(tempDir).
|
|
||||||
redirectErrorStream(true).
|
|
||||||
also { it.environment() += "BINARYEN" to wasmInstall.toString() }.
|
|
||||||
start()
|
|
||||||
proc.inputStream.bufferedReader().forEachLine { TestBase.logger.debug { "[OUT] $it" } }
|
|
||||||
Assert.assertTrue("Timeout", proc.waitFor(10, TimeUnit.SECONDS))
|
|
||||||
Assert.assertEquals(0, proc.exitValue())
|
|
||||||
var outFile = cFile.resolveSibling("$nameSansExt.out")
|
|
||||||
if (Files.notExists(outFile)) {
|
|
||||||
outFile = cFile.resolveSibling("$nameSansExt.txt")
|
|
||||||
require(Files.exists(outFile)) { "Cannot find out file for $cFile" }
|
|
||||||
}
|
|
||||||
EmscriptenTestUnit(
|
|
||||||
name = cFile.unitNameFromCFile(),
|
|
||||||
wast = File(tempDir, "$nameSansExt.wast").readText(),
|
|
||||||
expectedOutput = outFile.toFile().readText()
|
|
||||||
)
|
|
||||||
} catch (e: Exception) { throw Exception("Unable to compile $cFile", e) }
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
try { tempDir.deleteRecursively() }
|
|
||||||
catch (e: Exception) { TestBase.logger.warn { "Unable to delete temp dir: $e" } }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1 +0,0 @@
|
|||||||
Hello, world!
|
|
@ -1,4 +0,0 @@
|
|||||||
#include <stdio.h>
|
|
||||||
int main(int argc, char ** argv) {
|
|
||||||
printf("Hello, world!\n");
|
|
||||||
}
|
|
File diff suppressed because it is too large
Load Diff
@ -1,50 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
import asmble.annotation.WasmExport;
|
|
||||||
|
|
||||||
public class Common {
|
|
||||||
private final Env env;
|
|
||||||
|
|
||||||
public Common(Env env) {
|
|
||||||
this.env = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void abort() {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__assert_fail")
|
|
||||||
public void assertFail(int conditionPtr, int filenamePtr, int line, int funcPtr) {
|
|
||||||
throw new AssertionError("Assertion failed: " + env.mem.getCString(conditionPtr) + ", at " +
|
|
||||||
env.mem.getCString(filenamePtr) + ":" + line + ", func " + env.mem.getCString(funcPtr));
|
|
||||||
}
|
|
||||||
|
|
||||||
public int atexit(int funcPtr) {
|
|
||||||
env.addCallback(funcPtr, null);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int atexit(int funcPtr, int arg) {
|
|
||||||
env.addCallback(funcPtr, arg);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__cxa_call_unexpected")
|
|
||||||
public void callUnexpected(int ex) {
|
|
||||||
throw new EmscriptenException("Unexpected: " + ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__lock")
|
|
||||||
public void lock(int arg) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
public int sbrk(int increment) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__unlock")
|
|
||||||
public void unlock(int arg) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,19 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
public class EmscriptenException extends RuntimeException {
|
|
||||||
|
|
||||||
public EmscriptenException() {
|
|
||||||
}
|
|
||||||
|
|
||||||
public EmscriptenException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EmscriptenException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public EmscriptenException(Throwable cause) {
|
|
||||||
super(cause);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,94 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.lang.invoke.MethodHandle;
|
|
||||||
import java.lang.invoke.MethodHandles;
|
|
||||||
import java.lang.invoke.MethodType;
|
|
||||||
import java.lang.reflect.Field;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.function.Function;
|
|
||||||
|
|
||||||
public class Env {
|
|
||||||
|
|
||||||
public static final List<Function<Env, Object>> subModules = Arrays.asList(
|
|
||||||
Common::new,
|
|
||||||
Syscall::new
|
|
||||||
);
|
|
||||||
|
|
||||||
final Mem mem;
|
|
||||||
final OutputStream out;
|
|
||||||
final int argc;
|
|
||||||
final int argv;
|
|
||||||
private final List<AtExitCallback> atExitCallbacks = new ArrayList<>();
|
|
||||||
|
|
||||||
public Env(int staticBump, OutputStream out, String programName, String... args) {
|
|
||||||
this(new Mem(staticBump), out, programName, args);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Env(Mem mem, OutputStream out, String programName, String... args) {
|
|
||||||
this.mem = mem;
|
|
||||||
this.out = out;
|
|
||||||
// We need to add the args which is an int array
|
|
||||||
argc = args.length + 1;
|
|
||||||
int[] argv = new int[argc];
|
|
||||||
argv[0] = mem.putCString(programName);
|
|
||||||
for (int i = 0; i < args.length; i++) {
|
|
||||||
argv[i + 1] = mem.putCString(args[i]);
|
|
||||||
}
|
|
||||||
this.argv = mem.putIntArray(argv);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ByteBuffer getMemory() {
|
|
||||||
return mem.buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getArgc() {
|
|
||||||
return argc;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getArgv() {
|
|
||||||
return argv;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void addCallback(int funcPtr, Integer arg) {
|
|
||||||
atExitCallbacks.add(new AtExitCallback(funcPtr, arg));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void runAtExitCallbacks(Object moduleInst) throws Throwable {
|
|
||||||
MethodHandle noArg = null;
|
|
||||||
MethodHandle withArg = null;
|
|
||||||
for (int i = atExitCallbacks.size() - 1; i >= 0; i--) {
|
|
||||||
AtExitCallback cb = atExitCallbacks.get(i);
|
|
||||||
if (cb.arg == null) {
|
|
||||||
Field table = moduleInst.getClass().getDeclaredField("table");
|
|
||||||
table.setAccessible(true);
|
|
||||||
MethodHandle[] h = (MethodHandle[]) MethodHandles.lookup().unreflectGetter(table).invoke(moduleInst);
|
|
||||||
h[cb.funcPtr].invoke();
|
|
||||||
if (noArg == null) {
|
|
||||||
noArg = MethodHandles.lookup().bind(moduleInst,
|
|
||||||
"dynCall_v", MethodType.methodType(Void.TYPE, Integer.TYPE));
|
|
||||||
}
|
|
||||||
noArg.invokeExact(cb.funcPtr);
|
|
||||||
} else {
|
|
||||||
if (withArg == null) {
|
|
||||||
withArg = MethodHandles.lookup().bind(moduleInst,
|
|
||||||
"dynCall_vi", MethodType.methodType(Void.TYPE, Integer.TYPE, Integer.TYPE));
|
|
||||||
}
|
|
||||||
withArg.invokeExact(cb.funcPtr, cb.arg.intValue());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class AtExitCallback {
|
|
||||||
public final int funcPtr;
|
|
||||||
public final Integer arg;
|
|
||||||
|
|
||||||
public AtExitCallback(int funcPtr, Integer arg) {
|
|
||||||
this.funcPtr = funcPtr;
|
|
||||||
this.arg = arg;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,165 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
public enum Errno {
|
|
||||||
EPERM(1),
|
|
||||||
ENOENT(2),
|
|
||||||
ESRCH(3),
|
|
||||||
EINTR(4),
|
|
||||||
EIO(5),
|
|
||||||
ENXIO(6),
|
|
||||||
E2BIG(7),
|
|
||||||
ENOEXEC(8),
|
|
||||||
EBADF(9),
|
|
||||||
ECHILD(10),
|
|
||||||
EAGAIN(11),
|
|
||||||
ENOMEM(12),
|
|
||||||
EACCES(13),
|
|
||||||
EFAULT(14),
|
|
||||||
ENOTBLK(15),
|
|
||||||
EBUSY(16),
|
|
||||||
EEXIST(17),
|
|
||||||
EXDEV(18),
|
|
||||||
ENODEV(19),
|
|
||||||
ENOTDIR(20),
|
|
||||||
EISDIR(21),
|
|
||||||
EINVAL(22),
|
|
||||||
ENFILE(23),
|
|
||||||
EMFILE(24),
|
|
||||||
ENOTTY(25),
|
|
||||||
ETXTBSY(26),
|
|
||||||
EFBIG(27),
|
|
||||||
ENOSPC(28),
|
|
||||||
ESPIPE(29),
|
|
||||||
EROFS(30),
|
|
||||||
EMLINK(31),
|
|
||||||
EPIPE(32),
|
|
||||||
EDOM(33),
|
|
||||||
ERANGE(34),
|
|
||||||
EDEADLK(35),
|
|
||||||
ENAMETOOLONG(36),
|
|
||||||
ENOLCK(37),
|
|
||||||
ENOSYS(38),
|
|
||||||
ENOTEMPTY(39),
|
|
||||||
ELOOP(40),
|
|
||||||
EWOULDBLOCK(EAGAIN.number),
|
|
||||||
ENOMSG(42),
|
|
||||||
EIDRM(43),
|
|
||||||
ECHRNG(44),
|
|
||||||
EL2NSYNC(45),
|
|
||||||
EL3HLT(46),
|
|
||||||
EL3RST(47),
|
|
||||||
ELNRNG(48),
|
|
||||||
EUNATCH(49),
|
|
||||||
ENOCSI(50),
|
|
||||||
EL2HLT(51),
|
|
||||||
EBADE(52),
|
|
||||||
EBADR(53),
|
|
||||||
EXFULL(54),
|
|
||||||
ENOANO(55),
|
|
||||||
EBADRQC(56),
|
|
||||||
EBADSLT(57),
|
|
||||||
EDEADLOCK(EDEADLK.number),
|
|
||||||
EBFONT(59),
|
|
||||||
ENOSTR(60),
|
|
||||||
ENODATA(61),
|
|
||||||
ETIME(62),
|
|
||||||
ENOSR(63),
|
|
||||||
ENONET(64),
|
|
||||||
ENOPKG(65),
|
|
||||||
EREMOTE(66),
|
|
||||||
ENOLINK(67),
|
|
||||||
EADV(68),
|
|
||||||
ESRMNT(69),
|
|
||||||
ECOMM(70),
|
|
||||||
EPROTO(71),
|
|
||||||
EMULTIHOP(72),
|
|
||||||
EDOTDOT(73),
|
|
||||||
EBADMSG(74),
|
|
||||||
EOVERFLOW(75),
|
|
||||||
ENOTUNIQ(76),
|
|
||||||
EBADFD(77),
|
|
||||||
EREMCHG(78),
|
|
||||||
ELIBACC(79),
|
|
||||||
ELIBBAD(80),
|
|
||||||
ELIBSCN(81),
|
|
||||||
ELIBMAX(82),
|
|
||||||
ELIBEXEC(83),
|
|
||||||
EILSEQ(84),
|
|
||||||
ERESTART(85),
|
|
||||||
ESTRPIPE(86),
|
|
||||||
EUSERS(87),
|
|
||||||
ENOTSOCK(88),
|
|
||||||
EDESTADDRREQ(89),
|
|
||||||
EMSGSIZE(90),
|
|
||||||
EPROTOTYPE(91),
|
|
||||||
ENOPROTOOPT(92),
|
|
||||||
EPROTONOSUPPORT(93),
|
|
||||||
ESOCKTNOSUPPORT(94),
|
|
||||||
EOPNOTSUPP(95),
|
|
||||||
ENOTSUP(EOPNOTSUPP.number),
|
|
||||||
EPFNOSUPPORT(96),
|
|
||||||
EAFNOSUPPORT(97),
|
|
||||||
EADDRINUSE(98),
|
|
||||||
EADDRNOTAVAIL(99),
|
|
||||||
ENETDOWN(100),
|
|
||||||
ENETUNREACH(101),
|
|
||||||
ENETRESET(102),
|
|
||||||
ECONNABORTED(103),
|
|
||||||
ECONNRESET(104),
|
|
||||||
ENOBUFS(105),
|
|
||||||
EISCONN(106),
|
|
||||||
ENOTCONN(107),
|
|
||||||
ESHUTDOWN(108),
|
|
||||||
ETOOMANYREFS(109),
|
|
||||||
ETIMEDOUT(110),
|
|
||||||
ECONNREFUSED(111),
|
|
||||||
EHOSTDOWN(112),
|
|
||||||
EHOSTUNREACH(113),
|
|
||||||
EALREADY(114),
|
|
||||||
EINPROGRESS(115),
|
|
||||||
ESTALE(116),
|
|
||||||
EUCLEAN(117),
|
|
||||||
ENOTNAM(118),
|
|
||||||
ENAVAIL(119),
|
|
||||||
EISNAM(120),
|
|
||||||
EREMOTEIO(121),
|
|
||||||
EDQUOT(122),
|
|
||||||
ENOMEDIUM(123),
|
|
||||||
EMEDIUMTYPE(124),
|
|
||||||
ECANCELED(125),
|
|
||||||
ENOKEY(126),
|
|
||||||
EKEYEXPIRED(127),
|
|
||||||
EKEYREVOKED(128),
|
|
||||||
EKEYREJECTED(129),
|
|
||||||
EOWNERDEAD(130),
|
|
||||||
ENOTRECOVERABLE(131),
|
|
||||||
ERFKILL(132),
|
|
||||||
EHWPOISON(133);
|
|
||||||
|
|
||||||
final int number;
|
|
||||||
|
|
||||||
Errno(int number) {
|
|
||||||
this.number = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void raise() {
|
|
||||||
raise(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void raise(Throwable cause) {
|
|
||||||
throw new ErrnoException(this, cause);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static class ErrnoException extends EmscriptenException {
|
|
||||||
public final Errno errno;
|
|
||||||
|
|
||||||
public ErrnoException(Errno errno) {
|
|
||||||
this(errno, null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public ErrnoException(Errno errno, Throwable cause) {
|
|
||||||
super("Errno: " + errno, cause);
|
|
||||||
this.errno = errno;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,31 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
|
||||||
|
|
||||||
public abstract class FStream {
|
|
||||||
public abstract Tty getTty();
|
|
||||||
|
|
||||||
public abstract void write(byte[] bytes);
|
|
||||||
|
|
||||||
public static class OutputStream extends FStream {
|
|
||||||
private final Tty.OutputStream tty;
|
|
||||||
|
|
||||||
public OutputStream(java.io.OutputStream out) {
|
|
||||||
this.tty = new Tty.OutputStream(out);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Tty.OutputStream getTty() {
|
|
||||||
return tty;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(byte[] bytes) {
|
|
||||||
try {
|
|
||||||
tty.out.write(bytes);
|
|
||||||
} catch (IOException e) {
|
|
||||||
throw new EmscriptenException(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,91 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.nio.ByteOrder;
|
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
|
|
||||||
public class Mem {
|
|
||||||
public static final int TOTAL_STACK = 5242880;
|
|
||||||
public static final int TOTAL_MEMORY = 16777216;
|
|
||||||
|
|
||||||
private static int alignTo16(int num) {
|
|
||||||
return ((int) Math.ceil(num / 16.0)) * 16;
|
|
||||||
}
|
|
||||||
|
|
||||||
final ByteBuffer buf;
|
|
||||||
private int counter = 0;
|
|
||||||
|
|
||||||
public Mem(int staticBump) {
|
|
||||||
this(ByteBuffer.allocateDirect(TOTAL_MEMORY), staticBump);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Mem(ByteBuffer buf, int staticBump) {
|
|
||||||
this.buf = buf.order(ByteOrder.LITTLE_ENDIAN);
|
|
||||||
// Emscripten sets where "stack top" can start in mem at position 1024.
|
|
||||||
// See https://github.com/WebAssembly/binaryen/issues/979
|
|
||||||
int staticTop = 1024 + staticBump + 16;
|
|
||||||
int stackBase = alignTo16(staticTop);
|
|
||||||
int stackTop = stackBase + TOTAL_STACK;
|
|
||||||
buf.putInt(1024, stackTop);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public byte[] getBulk(int index, int len) {
|
|
||||||
byte[] ret = new byte[len];
|
|
||||||
if (len > 0) {
|
|
||||||
ByteBuffer dup = buf.duplicate();
|
|
||||||
dup.position(index);
|
|
||||||
dup.get(ret);
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public byte[] getCStringBytes(int index) {
|
|
||||||
if (index == 0) return new byte[0];
|
|
||||||
// Not really sure the highest performing approach. What we're going to do though is just
|
|
||||||
// find the first index of 0, then get the array.
|
|
||||||
int len = 0;
|
|
||||||
while (buf.get(index + len) != 0) len++;
|
|
||||||
return getBulk(index, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getCString(int index) {
|
|
||||||
byte[] bytes = getCStringBytes(index);
|
|
||||||
if (bytes.length == 0) return "";
|
|
||||||
return new String(getCStringBytes(index), StandardCharsets.ISO_8859_1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public synchronized int putCString(String str) {
|
|
||||||
// For now we'll just trust it doesn't already contain a 0
|
|
||||||
int ret = allocate(str.getBytes(StandardCharsets.ISO_8859_1));
|
|
||||||
allocate((byte) 0);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int putIntArray(int[] arr) {
|
|
||||||
int ret = counter;
|
|
||||||
for (int i = 0; i < arr.length; i++) {
|
|
||||||
buf.putInt(counter, arr[i]);
|
|
||||||
counter += 4;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int allocate(byte b) {
|
|
||||||
int ret = counter;
|
|
||||||
buf.put(counter, b);
|
|
||||||
counter++;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int allocate(byte[] bytes) {
|
|
||||||
int ret = counter;
|
|
||||||
if (bytes.length > 0) {
|
|
||||||
ByteBuffer dup = buf.duplicate();
|
|
||||||
dup.position(counter);
|
|
||||||
dup.put(bytes);
|
|
||||||
counter += bytes.length;
|
|
||||||
}
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,101 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
import asmble.annotation.WasmExport;
|
|
||||||
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import java.util.stream.IntStream;
|
|
||||||
import java.util.stream.Stream;
|
|
||||||
|
|
||||||
public class Syscall {
|
|
||||||
|
|
||||||
private final Map<Integer, FStream> fds;
|
|
||||||
private final Env env;
|
|
||||||
|
|
||||||
public Syscall(Env env) {
|
|
||||||
this.fds = new HashMap<>();
|
|
||||||
fds.put(1, new FStream.OutputStream(env.out));
|
|
||||||
this.env = env;
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__syscall6")
|
|
||||||
public int close(int arg0, int arg1) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__syscall54")
|
|
||||||
public int ioctl(int which, int varargs) {
|
|
||||||
FStream fd = fd(env.getMemory().getInt(varargs));
|
|
||||||
IoctlOp op = IoctlOp.byNumber.get(env.getMemory().getInt(varargs + 4));
|
|
||||||
Objects.requireNonNull(op);
|
|
||||||
switch (op) {
|
|
||||||
case TCGETS:
|
|
||||||
case TCSETS:
|
|
||||||
case TIOCGWINSZ:
|
|
||||||
return fd.getTty() == null ? -Errno.ENOTTY.number : 0;
|
|
||||||
case TIOCGPGRP:
|
|
||||||
if (fd.getTty() == null) return -Errno.ENOTTY.number;
|
|
||||||
env.getMemory().putInt(env.getMemory().getInt(varargs + 8), 0);
|
|
||||||
return 0;
|
|
||||||
case TIOCSPGRP:
|
|
||||||
return fd.getTty() == null ? -Errno.ENOTTY.number : -Errno.EINVAL.number;
|
|
||||||
case FIONREAD:
|
|
||||||
if (fd.getTty() == null) return -Errno.ENOTTY.number;
|
|
||||||
throw new UnsupportedOperationException("TODO");
|
|
||||||
default:
|
|
||||||
throw new EmscriptenException("Unrecognized op: " + op);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__syscall140")
|
|
||||||
public int llseek(int arg0, int arg1) {
|
|
||||||
throw new UnsupportedOperationException();
|
|
||||||
}
|
|
||||||
|
|
||||||
@WasmExport("__syscall146")
|
|
||||||
public int writev(int which, int varargs) {
|
|
||||||
FStream fd = fd(env.getMemory().getInt(varargs));
|
|
||||||
int iov = env.getMemory().getInt(varargs + 4);
|
|
||||||
int iovcnt = env.getMemory().getInt(varargs + 8);
|
|
||||||
return IntStream.range(0, iovcnt).reduce(0, (total, i) -> {
|
|
||||||
int ptr = env.getMemory().getInt(iov + (i * 8));
|
|
||||||
int len = env.getMemory().getInt(iov + (i * 8) + 4);
|
|
||||||
if (len > 0) fd.write(env.mem.getBulk(ptr, len));
|
|
||||||
return total + len;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private FStream fd(int v) {
|
|
||||||
FStream ret = fds.get(v);
|
|
||||||
if (ret == null) Errno.EBADF.raise();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static enum IoctlOp {
|
|
||||||
TCGETS(0x5401),
|
|
||||||
TCSETS(0x5402),
|
|
||||||
TIOCGPGRP(0x540F),
|
|
||||||
TIOCSPGRP(0x5410),
|
|
||||||
FIONREAD(0x541B),
|
|
||||||
TIOCGWINSZ(0x5413);
|
|
||||||
|
|
||||||
static final Map<Integer, IoctlOp> byNumber;
|
|
||||||
|
|
||||||
static {
|
|
||||||
byNumber = Stream.of(values()).collect(Collectors.toMap(IoctlOp::getNumber, Function.identity()));
|
|
||||||
}
|
|
||||||
|
|
||||||
final int number;
|
|
||||||
|
|
||||||
IoctlOp(int number) {
|
|
||||||
this.number = number;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getNumber() {
|
|
||||||
return number;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +0,0 @@
|
|||||||
package run.jvm.emscripten;
|
|
||||||
|
|
||||||
public abstract class Tty {
|
|
||||||
|
|
||||||
public static class OutputStream extends Tty {
|
|
||||||
final java.io.OutputStream out;
|
|
||||||
|
|
||||||
public OutputStream(java.io.OutputStream out) {
|
|
||||||
this.out = out;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,7 +1,6 @@
|
|||||||
rootProject.name = 'asmble'
|
rootProject.name = 'asmble'
|
||||||
include 'annotations',
|
include 'annotations',
|
||||||
'compiler',
|
'compiler',
|
||||||
'emscripten-runtime',
|
|
||||||
'examples:c-simple',
|
'examples:c-simple',
|
||||||
'examples:rust-regex',
|
'examples:rust-regex',
|
||||||
'examples:rust-simple',
|
'examples:rust-simple',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user