From 224810d0ab846c545eb3cb13bd1c55280c51bcd4 Mon Sep 17 00:00:00 2001
From: Alexey Andreev <konsoletyper@gmail.com>
Date: Tue, 8 Nov 2022 19:44:56 +0100
Subject: [PATCH] Wasm: support file IO and random generator in WASI

---
 .../org/teavm/classlib/java/util/TRandom.java |  3 +
 .../java/org/teavm/backend/wasm/WasmHeap.java | 12 ++-
 .../org/teavm/backend/wasm/WasmTarget.java    |  7 +-
 .../backend/wasm/runtime/WasiBuffer.java      |  7 +-
 .../backend/wasm/runtime/WasiSupport.java     | 42 +++++++---
 .../backend/wasm/runtime/WasmSupport.java     |  3 +
 .../wasm/runtime/fs/WasiVirtualFile.java      |  4 +-
 .../runtime/fs/WasiVirtualFileAccessor.java   | 80 +++++++++----------
 .../teavm/backend/wasm/wasi/IntResult.java    | 22 +++++
 .../teavm/backend/wasm/wasi/SizeResult.java   |  2 +-
 .../org/teavm/backend/wasm/wasi/Wasi.java     | 21 ++++-
 11 files changed, 141 insertions(+), 62 deletions(-)
 create mode 100644 core/src/main/java/org/teavm/backend/wasm/wasi/IntResult.java

diff --git a/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java b/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java
index aeaca755f..30c2401ff 100644
--- a/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java
+++ b/classlib/src/main/java/org/teavm/classlib/java/util/TRandom.java
@@ -18,6 +18,7 @@ package org.teavm.classlib.java.util;
 import java.util.function.DoublePredicate;
 import java.util.function.IntPredicate;
 import java.util.function.LongPredicate;
+import org.teavm.backend.wasm.runtime.WasmSupport;
 import org.teavm.classlib.PlatformDetector;
 import org.teavm.classlib.java.io.TSerializable;
 import org.teavm.classlib.java.lang.TMath;
@@ -144,6 +145,8 @@ public class TRandom extends TObject implements TSerializable {
     public double nextDouble() {
         if (PlatformDetector.isC()) {
             return crand();
+        } else if (PlatformDetector.isWebAssembly()) {
+            return WasmSupport.random();
         } else {
             return random();
         }
diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmHeap.java b/core/src/main/java/org/teavm/backend/wasm/WasmHeap.java
index 82d63fe0d..696c05d13 100644
--- a/core/src/main/java/org/teavm/backend/wasm/WasmHeap.java
+++ b/core/src/main/java/org/teavm/backend/wasm/WasmHeap.java
@@ -26,6 +26,7 @@ public final class WasmHeap {
     public static final int PAGE_SIZE = 65536;
     public static final int DEFAULT_STACK_SIZE = PAGE_SIZE * 4;
     public static final int DEFAULT_REGION_SIZE = 1024;
+    public static final int DEFAULT_BUFFER_SIZE = 512;
 
     public static int minHeapSize;
     public static int maxHeapSize;
@@ -42,6 +43,8 @@ public final class WasmHeap {
     public static Address stackAddress;
     public static Address stack;
     public static int stackSize;
+    public static Address buffer;
+    public static int bufferSize;
 
     private WasmHeap() {
     }
@@ -64,10 +67,13 @@ public final class WasmHeap {
         WasmSupport.initHeapTrace(maxHeap);
     }
 
-    public static void initHeap(Address start, int minHeap, int maxHeap, int stackSize) {
+    public static void initHeap(Address start, int minHeap, int maxHeap, int stackSize, int bufferSize) {
         initHeapTrace(maxHeap);
-        stackAddress = start;
-        stack = start;
+        buffer = start;
+        buffer = WasmRuntime.align(start, 16);
+        WasmHeap.bufferSize = bufferSize;
+        stack = WasmRuntime.align(buffer.add(bufferSize), 16);
+        stackAddress = stack;
         heapAddress = WasmRuntime.align(stackAddress.add(stackSize), 16);
         memoryLimit = WasmRuntime.align(start, PAGE_SIZE);
         minHeapSize = minHeap;
diff --git a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java
index 31e498624..fe6fbb76a 100644
--- a/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java
+++ b/core/src/main/java/org/teavm/backend/wasm/WasmTarget.java
@@ -175,7 +175,7 @@ import org.teavm.vm.spi.TeaVMHostExtension;
 
 public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
     private static final MethodReference INIT_HEAP_REF = new MethodReference(WasmHeap.class, "initHeap",
-            Address.class, int.class, int.class, int.class, void.class);
+            Address.class, int.class, int.class, int.class, int.class, void.class);
     private static final MethodReference RESIZE_HEAP_REF = new MethodReference(WasmHeap.class, "resizeHeap",
             int.class, void.class);
     private static final Set<MethodReference> VIRTUAL_METHODS = new HashSet<>(Arrays.asList(
@@ -621,7 +621,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
 
         initFunction.getBody().add(new WasmCall(names.forMethod(INIT_HEAP_REF),
                 new WasmInt32Constant(heapAddress), new WasmInt32Constant(minHeapSize),
-                new WasmInt32Constant(maxHeapSize), new WasmInt32Constant(WasmHeap.DEFAULT_STACK_SIZE)));
+                new WasmInt32Constant(maxHeapSize), new WasmInt32Constant(WasmHeap.DEFAULT_STACK_SIZE),
+                new WasmInt32Constant(WasmHeap.DEFAULT_BUFFER_SIZE)));
 
         for (Class<?> javaCls : new Class<?>[] { GC.class }) {
             ClassReader cls = classes.get(javaCls.getName());
@@ -949,6 +950,8 @@ public class WasmTarget implements TeaVMTarget, TeaVMWasmHost {
         int newRegionsCount = WasmHeap.calculateRegionsCount(maxHeapSize, WasmHeap.DEFAULT_REGION_SIZE);
         int newRegionsSize = WasmHeap.calculateRegionsSize(newRegionsCount);
 
+        address = WasmRuntime.align(address, 16);
+        address = WasmRuntime.align(address + WasmHeap.DEFAULT_BUFFER_SIZE, 16);
         address = WasmRuntime.align(address + WasmHeap.DEFAULT_STACK_SIZE, 16);
         address = WasmRuntime.align(address + maxHeapSize, 16);
         address = WasmRuntime.align(address + newRegionsSize, 16);
diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiBuffer.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiBuffer.java
index 3591cb429..1c7acb42f 100644
--- a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiBuffer.java
+++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiBuffer.java
@@ -15,19 +15,18 @@
  */
 package org.teavm.backend.wasm.runtime;
 
+import org.teavm.backend.wasm.WasmHeap;
 import org.teavm.interop.Address;
 
 public final class WasiBuffer {
-    private static byte[] argBuffer = new byte[256];
-
     private WasiBuffer() {
     }
 
     public static int getBufferSize() {
-        return argBuffer.length;
+        return WasmHeap.bufferSize;
     }
 
     public static Address getBuffer() {
-        return Address.ofData(argBuffer);
+        return WasmHeap.buffer;
     }
 }
diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java
index 290380794..17cfa61cb 100644
--- a/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java
+++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasiSupport.java
@@ -15,8 +15,10 @@
  */
 package org.teavm.backend.wasm.runtime;
 
+import static org.teavm.backend.wasm.wasi.Wasi.ERRNO_SUCCESS;
 import java.nio.charset.StandardCharsets;
 import org.teavm.backend.wasm.wasi.IOVec;
+import org.teavm.backend.wasm.wasi.IntResult;
 import org.teavm.backend.wasm.wasi.LongResult;
 import org.teavm.backend.wasm.wasi.SizeResult;
 import org.teavm.backend.wasm.wasi.Wasi;
@@ -26,6 +28,9 @@ import org.teavm.interop.Unmanaged;
 
 @Unmanaged
 public class WasiSupport {
+    private static long nextRandom;
+    private static boolean randomInitialized;
+
     private WasiSupport() {
     }
 
@@ -43,7 +48,7 @@ public class WasiSupport {
     public static void putChars(int fd, Address address, int count) {
         Address argsAddress = WasiBuffer.getBuffer();
         IOVec ioVec = argsAddress.toStructure();
-        SizeResult result = argsAddress.add(Structure.sizeOf(IOVec.class)).toStructure();
+        SizeResult result = Address.align(argsAddress.add(Structure.sizeOf(IOVec.class)), 16).toStructure();
         ioVec.buffer = address;
         ioVec.bufferLength = count;
         Wasi.fdWrite(fd, ioVec, 1, result);
@@ -51,8 +56,7 @@ public class WasiSupport {
 
     @Unmanaged
     public static long currentTimeMillis() {
-        Address argsAddress = WasiBuffer.getBuffer();
-        LongResult result = argsAddress.toStructure();
+        LongResult result = WasiBuffer.getBuffer().toStructure();
         Wasi.clockTimeGet(Wasi.CLOCKID_REALTIME, 10, result);
         return result.value;
     }
@@ -103,21 +107,22 @@ public class WasiSupport {
 
     public static String[] getArgs() {
         Address buffer = WasiBuffer.getBuffer();
-        SizeResult sizesReceiver = buffer.toStructure();
-        SizeResult bufferSizeReceiver = buffer.add(Structure.sizeOf(SizeResult.class)).toStructure();
+        IntResult sizesReceiver = buffer.toStructure();
+        IntResult bufferSizeReceiver = Address.align(buffer.add(Structure.sizeOf(IntResult.class)), 16)
+                .toStructure();
         short errno = Wasi.argsSizesGet(sizesReceiver, bufferSizeReceiver);
 
-        if (errno != Wasi.ERRNO_SUCCESS) {
+        if (errno != ERRNO_SUCCESS) {
             throw new RuntimeException("Could not get command line arguments");
         }
-        int argvSize = sizesReceiver.value;
-        int argvBufSize = bufferSizeReceiver.value;
+        int argvSize = (int) sizesReceiver.value;
+        int argvBufSize = (int) bufferSizeReceiver.value;
 
         int[] argvOffsets = new int[argvSize];
         byte[] argvBuffer = new byte[argvBufSize];
         errno = Wasi.argsGet(Address.ofData(argvOffsets), Address.ofData(argvBuffer));
 
-        if (errno != Wasi.ERRNO_SUCCESS) {
+        if (errno != ERRNO_SUCCESS) {
             throw new RuntimeException("Could not get command line arguments");
         }
 
@@ -130,4 +135,23 @@ public class WasiSupport {
 
         return args;
     }
+
+    public static double random() {
+        return (((long) nextRandom(26) << 27) + nextRandom(27)) / (double) (1L << 53);
+    }
+
+    private static int nextRandom(int bits) {
+        if (!randomInitialized) {
+            short errno = Wasi.randomGet(WasiBuffer.getBuffer(), 8);
+
+            if (errno != ERRNO_SUCCESS) {
+                throw new RuntimeException("random_get: " + errno);
+            }
+
+            nextRandom = WasiBuffer.getBuffer().getLong();
+        }
+
+        nextRandom = ((nextRandom * 0x5DEECE66DL) + 0xBL) & ((1L << 48) - 1);
+        return (int) (nextRandom >>> (48 - bits));
+    }
 }
diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java b/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java
index 0fbaaebd3..af77763d9 100644
--- a/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java
+++ b/core/src/main/java/org/teavm/backend/wasm/runtime/WasmSupport.java
@@ -53,4 +53,7 @@ public class WasmSupport {
     public static String[] getArgs() {
         return new String[0];
     }
+
+    @Import(module = "teavmMath", name = "random")
+    public static native double random();
 }
diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFile.java b/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFile.java
index c5d370b28..2362d6d6d 100644
--- a/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFile.java
+++ b/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFile.java
@@ -80,7 +80,7 @@ public class WasiVirtualFile implements VirtualFile {
         if (baseFd < 0) {
             return null;
         }
-        Filestat filestat = Address.align(WasiBuffer.getBuffer(), 8).toStructure();
+        Filestat filestat = WasiBuffer.getBuffer().toStructure();
         int errno;
         if (path != null) {
             byte[] bytes = path.getBytes(StandardCharsets.UTF_8);
@@ -207,7 +207,7 @@ public class WasiVirtualFile implements VirtualFile {
             fdflags |= FDFLAGS_APPEND;
         }
         int fd = open((short) 0, rights, fdflags);
-        return fd >= 0 ? new WasiVirtualFileAccessor(fs, fd) : null;
+        return fd >= 0 ? new WasiVirtualFileAccessor(this, fd) : null;
     }
 
     @Override
diff --git a/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFileAccessor.java b/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFileAccessor.java
index 1df7433ef..9616ca982 100644
--- a/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFileAccessor.java
+++ b/core/src/main/java/org/teavm/backend/wasm/runtime/fs/WasiVirtualFileAccessor.java
@@ -15,88 +15,88 @@
  */
 package org.teavm.backend.wasm.runtime.fs;
 
+import static org.teavm.backend.wasm.wasi.Wasi.ERRNO_SUCCESS;
+import static org.teavm.backend.wasm.wasi.Wasi.WHENCE_CURRENT;
+import static org.teavm.backend.wasm.wasi.Wasi.WHENCE_START;
 import java.io.IOException;
 import org.teavm.backend.wasm.runtime.WasiBuffer;
+import org.teavm.backend.wasm.wasi.IOVec;
+import org.teavm.backend.wasm.wasi.SizeResult;
+import org.teavm.backend.wasm.wasi.Wasi;
 import org.teavm.interop.Address;
+import org.teavm.interop.Structure;
 import org.teavm.runtime.fs.VirtualFileAccessor;
 
 public class WasiVirtualFileAccessor implements VirtualFileAccessor {
-    // Enough room for an I32 plus padding for alignment:
-    private static final byte[] EIGHT_BYTE_BUFFER = new byte[8];
-    // Enough room for an I64 plus padding for alignment:
-    private static final byte[] SIXTEEN_BYTE_BUFFER = new byte[16];
-
-    private WasiFileSystem fs;
+    private WasiVirtualFile file;
     private int fd;
 
-    public WasiVirtualFileAccessor(WasiFileSystem fs, int fd) {
-        this.fs = fs;
+    WasiVirtualFileAccessor(WasiVirtualFile file, int fd) {
+        this.file = file;
         this.fd = fd;
     }
 
     @Override
     public int read(byte[] buffer, int offset, int length) throws IOException {
-        byte[] vecBuffer = SIXTEEN_BYTE_BUFFER;
-        Address vec = WasiBuffer.getBuffer();
-        vec.putInt(Address.ofData(buffer).add(offset).toInt());
-        vec.add(4).putInt(length);
-        byte[] sizeBuffer = EIGHT_BYTE_BUFFER;
-        Address size = Address.align(Address.ofData(sizeBuffer), 4);
-        short errno = Wasi.fdRead(fd, vec, 1, size);
+        Address buf = WasiBuffer.getBuffer();
+        IOVec vec = buf.toStructure();
+        vec.buffer = Address.ofData(buffer).add(offset);
+        vec.bufferLength = length;
+
+        SizeResult sizeResult = Address.align(buf.add(Structure.sizeOf(IOVec.class)), 16).toStructure();
+        short errno = Wasi.fdRead(fd, vec, 1, sizeResult);
 
         if (errno == ERRNO_SUCCESS) {
-            return size.getInt();
+            return (int) sizeResult.value;
         } else {
-            throw new IOException(errnoMessage("fd_read", errno));
+            throw new IOException("fd_read: " + errno);
         }
     }
 
     @Override
     public void write(byte[] buffer, int offset, int length) throws IOException {
-        byte[] vecBuffer = SIXTEEN_BYTE_BUFFER;
-        Address vec = Address.align(Address.ofData(vecBuffer), 4);
-        byte[] sizeBuffer = EIGHT_BYTE_BUFFER;
-        Address size = Address.align(Address.ofData(sizeBuffer), 4);
+        Address buf = WasiBuffer.getBuffer();
+        IOVec vec = buf.toStructure();
+        SizeResult sizeResult = Address.align(buf.add(Structure.sizeOf(IOVec.class)), 16).toStructure();
 
-        int index = 0;
         while (true) {
-            vec.putInt(Address.ofData(buffer).add(offset + index).toInt());
-            vec.add(4).putInt(length - index);
-            short errno = Wasi.fdWrite(fd, vec, 1, size);
+            vec.buffer = Address.ofData(buffer).add(offset);
+            vec.bufferLength = length;
+            short errno = Wasi.fdWrite(fd, vec, 1, sizeResult);
 
             if (errno == ERRNO_SUCCESS) {
-                index += size.getInt();
-                if (index >= length) {
+                int size = (int) sizeResult.value;
+                offset += size;
+                length -= size;
+                if (length <= 0) {
                     return;
                 }
             } else {
-                throw new IOException(errnoMessage("fd_write", errno));
+                throw new IOException("fd_write: " + errno);
             }
         }
     }
 
     @Override
     public int tell() throws IOException {
-        byte[] filesizeBuffer = SIXTEEN_BYTE_BUFFER;
-        Address filesize = Address.align(Address.ofData(filesizeBuffer), 8);
+        SizeResult filesize = WasiBuffer.getBuffer().toStructure();
         short errno = Wasi.fdTell(fd, filesize);
 
         if (errno == ERRNO_SUCCESS) {
-            return (int) filesize.getLong();
+            return (int) filesize.value;
         } else {
-            throw new IOException(errnoMessage("fd_tell", errno));
+            throw new IOException("fd_tell: " + errno);
         }
     }
 
     private long seek(long offset, byte whence) throws IOException {
-        byte[] filesizeBuffer = SIXTEEN_BYTE_BUFFER;
-        Address filesize = Address.align(Address.ofData(filesizeBuffer), 8);
+        SizeResult filesize = WasiBuffer.getBuffer().toStructure();
         short errno = Wasi.fdSeek(fd, offset, whence, filesize);
 
         if (errno == ERRNO_SUCCESS) {
-            return filesize.getLong();
+            return filesize.value;
         } else {
-            throw new IOException(errnoMessage("fd_seek", errno));
+            throw new IOException("fd_seek: " + errno);
         }
     }
 
@@ -112,7 +112,7 @@ public class WasiVirtualFileAccessor implements VirtualFileAccessor {
 
     @Override
     public int size() throws IOException {
-        return (int) new WasiVirtualFile(fd, null).stat().filesize;
+        return (int) file.stat().filesize;
     }
 
     @Override
@@ -120,7 +120,7 @@ public class WasiVirtualFileAccessor implements VirtualFileAccessor {
         short errno = Wasi.fdFilestatSetSize(fd, size);
 
         if (errno != ERRNO_SUCCESS) {
-            throw new IOException(errnoMessage("fd_filestat_set_size", errno));
+            throw new IOException("fd_filestat_set_size" + errno);
         }
     }
 
@@ -133,7 +133,7 @@ public class WasiVirtualFileAccessor implements VirtualFileAccessor {
             short errno = Wasi.fdClose(fd);
 
             if (errno != ERRNO_SUCCESS) {
-                throw new IOException(errnoMessage("fd_close", errno));
+                throw new IOException("fd_close: " + errno);
             }
         }
     }
@@ -143,7 +143,7 @@ public class WasiVirtualFileAccessor implements VirtualFileAccessor {
         short errno = Wasi.fdSync(fd);
 
         if (errno != ERRNO_SUCCESS) {
-            throw new IOException(errnoMessage("fd_sync", errno));
+            throw new IOException("fd_sync: " + errno);
         }
     }
 }
\ No newline at end of file
diff --git a/core/src/main/java/org/teavm/backend/wasm/wasi/IntResult.java b/core/src/main/java/org/teavm/backend/wasm/wasi/IntResult.java
new file mode 100644
index 000000000..aacf0ba55
--- /dev/null
+++ b/core/src/main/java/org/teavm/backend/wasm/wasi/IntResult.java
@@ -0,0 +1,22 @@
+/*
+ *  Copyright 2022 Alexey Andreev.
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package org.teavm.backend.wasm.wasi;
+
+import org.teavm.interop.Structure;
+
+public class IntResult extends Structure {
+    public int value;
+}
diff --git a/core/src/main/java/org/teavm/backend/wasm/wasi/SizeResult.java b/core/src/main/java/org/teavm/backend/wasm/wasi/SizeResult.java
index 31dae0a98..7495075ed 100644
--- a/core/src/main/java/org/teavm/backend/wasm/wasi/SizeResult.java
+++ b/core/src/main/java/org/teavm/backend/wasm/wasi/SizeResult.java
@@ -18,5 +18,5 @@ package org.teavm.backend.wasm.wasi;
 import org.teavm.interop.Structure;
 
 public class SizeResult extends Structure {
-    public int value;
+    public long value;
 }
diff --git a/core/src/main/java/org/teavm/backend/wasm/wasi/Wasi.java b/core/src/main/java/org/teavm/backend/wasm/wasi/Wasi.java
index b181eb6e7..e413e90d9 100644
--- a/core/src/main/java/org/teavm/backend/wasm/wasi/Wasi.java
+++ b/core/src/main/java/org/teavm/backend/wasm/wasi/Wasi.java
@@ -62,14 +62,23 @@ public final class Wasi {
     public static native short clockTimeGet(int clockId, long precision, LongResult result);
 
     @Import(name = "args_sizes_get", module = "wasi_snapshot_preview1")
-    public static native short argsSizesGet(SizeResult argvSize, SizeResult argvBufSize);
+    public static native short argsSizesGet(IntResult argvSize, IntResult argvBufSize);
 
     @Import(name = "args_get", module = "wasi_snapshot_preview1")
     public static native short argsGet(Address argv, Address argvBuf);
 
+    @Import(name = "fd_read", module = "wasi_snapshot_preview1")
+    public static native short fdRead(int fd, IOVec vecArray, int vecArrayLength, SizeResult size);
+
     @Import(name = "fd_write", module = "wasi_snapshot_preview1")
     public static native short fdWrite(int fd, IOVec vectors, int vectorsCont, SizeResult result);
 
+    @Import(name = "fd_tell", module = "wasi_snapshot_preview1")
+    public static native short fdTell(int fd, SizeResult size);
+
+    @Import(name = "fd_seek", module = "wasi_snapshot_preview1")
+    public static native short fdSeek(int fd, long offset, byte whence, SizeResult size);
+
     @Import(name = "fd_prestat_get", module = "wasi_snapshot_preview1")
     public static native short fdPrestatGet(int fd, Prestat prestat);
 
@@ -109,4 +118,14 @@ public final class Wasi {
     @Import(name = "path_filestat_set_times", module = "wasi_snapshot_preview1")
     public static native short pathFilestatSetTimes(int fd, int lookupFlags, Address path, int pathLength,
             long atime, long mtime, short fstflags);
+
+    @Import(name = "fd_filestat_set_size", module = "wasi_snapshot_preview1")
+    public static native short fdFilestatSetSize(int fd, long size);
+
+    @Import(name = "fd_sync", module = "wasi_snapshot_preview1")
+    public static native short fdSync(int fd);
+
+    @Import(name = "random_get", module = "wasi_snapshot_preview1")
+    public static native short randomGet(Address buffer, int bufferLength);
+
 }