Initial work to support emscripten runtime for issue #7

This commit is contained in:
Chad Retz
2017-04-26 15:35:34 -05:00
parent d94b5ce898
commit b4140c8189
31 changed files with 523 additions and 369 deletions

View File

@@ -0,0 +1,19 @@
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);
}
}

View File

@@ -0,0 +1,72 @@
package run.jvm.emscripten;
import asmble.annotation.WasmName;
import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
public class Env {
public static final int TOTAL_STACK = 5242880;
public static final int TOTAL_MEMORY = 16777216;
public static final List<Function<Env, Object>> subModules = Arrays.asList(
Syscall::new
);
private static int alignTo16(int num) {
return ((int) Math.ceil(num / 16.0)) * 16;
}
private final ByteBuffer memory;
private final int staticBump;
final OutputStream out;
public Env(int staticBump, OutputStream out) {
this(ByteBuffer.allocateDirect(TOTAL_MEMORY), staticBump, out);
}
public Env(ByteBuffer memory, int staticBump, OutputStream out) {
this.memory = memory.order(ByteOrder.LITTLE_ENDIAN);
this.staticBump = staticBump;
this.out = out;
// Emscripten sets where "stack top" can start in mem at position 1024.
// See https://github.com/WebAssembly/binaryen/issues/979
int stackBase = alignTo16(staticBump + 1024 + 16);
int stackTop = stackBase + TOTAL_STACK;
memory.putInt(1024, stackTop);
}
public ByteBuffer getMemory() {
return memory;
}
public byte[] getMemoryBulk(int index, int len) {
byte[] ret = new byte[len];
ByteBuffer dup = memory.duplicate();
dup.position(index);
dup.get(ret);
return ret;
}
public void abort() {
throw new UnsupportedOperationException();
}
@WasmName("__lock")
public void lock(int arg) {
throw new UnsupportedOperationException();
}
public int sbrk(int increment) {
throw new UnsupportedOperationException();
}
@WasmName("__unlock")
public void unlock(int arg) {
throw new UnsupportedOperationException();
}
}

View File

@@ -0,0 +1,165 @@
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;
}
}
}

View File

@@ -0,0 +1,31 @@
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);
}
}
}
}

View File

@@ -0,0 +1,101 @@
package run.jvm.emscripten;
import asmble.annotation.WasmName;
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;
}
@WasmName("__syscall6")
public int close(int arg0, int arg1) {
throw new UnsupportedOperationException();
}
@WasmName("__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);
}
}
@WasmName("__syscall140")
public int llseek(int arg0, int arg1) {
throw new UnsupportedOperationException();
}
//
@WasmName("__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.getMemoryBulk(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;
}
}
}

View File

@@ -0,0 +1,12 @@
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;
}
}
}