mirror of
https://github.com/fluencelabs/asmble
synced 2025-07-16 06:31:57 +00:00
Initial work to support emscripten runtime for issue #7
This commit is contained in:
@@ -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);
|
||||
}
|
||||
}
|
72
emscripten-runtime/src/main/java/run/jvm/emscripten/Env.java
Normal file
72
emscripten-runtime/src/main/java/run/jvm/emscripten/Env.java
Normal 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();
|
||||
}
|
||||
}
|
165
emscripten-runtime/src/main/java/run/jvm/emscripten/Errno.java
Normal file
165
emscripten-runtime/src/main/java/run/jvm/emscripten/Errno.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
101
emscripten-runtime/src/main/java/run/jvm/emscripten/Syscall.java
Normal file
101
emscripten-runtime/src/main/java/run/jvm/emscripten/Syscall.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
12
emscripten-runtime/src/main/java/run/jvm/emscripten/Tty.java
Normal file
12
emscripten-runtime/src/main/java/run/jvm/emscripten/Tty.java
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user