authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-11-15 17:40:04-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-12-06 12:15:04-07:00
log39fd77bc163f0d7fc7408cbb4e48f960b4739448
treef32d6bbf639cf5840e72bb4a5ed6f5c56dc6165f
parentef447c3ecac4211a0a03f487e84acc61160d7ede

interpret the WASI blob to produce zig2.c and compiler_rt.c

* synchronize zig1.c from zig-wasi external project * change the way argv works to avoid absolute paths * autodetect isatty * compiler_rt: disable some functions when object format is C * add missing flag from config.zig.in The next problem is that compiling compiler_rt.c with gcc gives "conflicting types" errors for `__eqhf2` and friends.

4 files changed, 491 insertions(+), 235 deletions(-)

CMakeLists.txt+7-17
......@@ -702,29 +702,24 @@ if(MSVC)
702702 set(ZIG2_COMPILE_FLAGS "/std:c99")
703703 set(ZIG2_LINK_FLAGS "/STACK:16777216")
704704else()
705 #set(ZIG1_COMPILE_FLAGS "-std=c99 -O2 -march=native")
706 set(ZIG1_COMPILE_FLAGS "-std=c99 -march=native")
705 set(ZIG1_COMPILE_FLAGS "-std=c99 -O2 -march=native")
707706 set(ZIG2_COMPILE_FLAGS "-std=c99 -O2 -march=native")
708707 set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000")
709708endif()
710709
711710add_executable(zig1 ${STAGE1_SOURCES})
712711set_target_properties(zig1 PROPERTIES COMPILE_FLAGS ${ZIG1_COMPILE_FLAGS})
713#target_include_directories(zig1 PUBLIC "${CMAKE_SOURCE_DIR}/lib")
714712target_link_libraries(zig1 LINK_PUBLIC m)
715713
716714
717715set(ZIG2_C_SOURCE "${CMAKE_BINARY_DIR}/zig2.c")
718716set(BUILD_ZIG2_ARGS
719717 "${CMAKE_SOURCE_DIR}/lib"
720 "${CMAKE_BINARY_DIR}/zig1-cache"
718 "${CMAKE_BINARY_DIR}"
719 zig2
721720 "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm"
722721 build-exe src/main.zig -ofmt=c -lc
723 --name zig2
724 --pkg-begin build_options "${ZIG_CONFIG_ZIG_OUT}"
725 --pkg-end
726722 -target x86_64-linux-musl # TODO: autodetect in zig1.c
727 --color on # TODO: autodetect in zig1.c
728723 -OReleaseFast
729724)
730725
......@@ -739,12 +734,11 @@ add_custom_command(
739734set(ZIG_COMPILER_RT_C_SOURCE "${CMAKE_BINARY_DIR}/compiler_rt.c")
740735set(BUILD_COMPILER_RT_ARGS
741736 "${CMAKE_SOURCE_DIR}/lib"
742 "${CMAKE_BINARY_DIR}/zig1-cache"
737 "${CMAKE_BINARY_DIR}"
738 compiler_rt
743739 "${CMAKE_SOURCE_DIR}/stage1/zig1.wasm"
744740 build-obj lib/compiler_rt.zig -ofmt=c
745 --name compiler_rt
746741 -target x86_64-linux-musl # TODO: autodetect in zig1.c
747 --color on # TODO: autodetect in zig1.c
748742 -OReleaseFast
749743)
750744
......@@ -757,13 +751,9 @@ add_custom_command(
757751)
758752
759753
760add_executable(zig2 ${ZIG2_C_SOURCE})
754add_executable(zig2 ${ZIG2_C_SOURCE} ${ZIG_COMPILER_RT_C_SOURCE})
761755set_target_properties(zig2 PROPERTIES
762756 COMPILE_FLAGS ${ZIG2_COMPILE_FLAGS}
763757 LINK_FLAGS ${ZIG2_LINK_FLAGS}
764758)
765
766
767
768
769
759target_include_directories(zig2 PUBLIC "${CMAKE_SOURCE_DIR}/lib")
lib/compiler_rt.zig+14-12
......@@ -3,13 +3,6 @@ const builtin = @import("builtin");
33pub const panic = @import("compiler_rt/common.zig").panic;
44
55comptime {
6 _ = @import("compiler_rt/atomics.zig");
7
8 // macOS has these functions inside libSystem.
9 if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) {
10 _ = @import("compiler_rt/aarch64_outline_atomics.zig");
11 }
12
136 _ = @import("compiler_rt/addf3.zig");
147 _ = @import("compiler_rt/addhf3.zig");
158 _ = @import("compiler_rt/addsf3.zig");
......@@ -216,9 +209,18 @@ comptime {
216209 _ = @import("compiler_rt/aullrem.zig");
217210 _ = @import("compiler_rt/clear_cache.zig");
218211
219 _ = @import("compiler_rt/memcpy.zig");
220 _ = @import("compiler_rt/memset.zig");
221 _ = @import("compiler_rt/memmove.zig");
222 _ = @import("compiler_rt/memcmp.zig");
223 _ = @import("compiler_rt/bcmp.zig");
212 if (@import("builtin").object_format != .c) {
213 _ = @import("compiler_rt/atomics.zig");
214
215 // macOS has these functions inside libSystem.
216 if (builtin.cpu.arch.isAARCH64() and !builtin.os.tag.isDarwin()) {
217 _ = @import("compiler_rt/aarch64_outline_atomics.zig");
218 }
219
220 _ = @import("compiler_rt/memcpy.zig");
221 _ = @import("compiler_rt/memset.zig");
222 _ = @import("compiler_rt/memmove.zig");
223 _ = @import("compiler_rt/memcmp.zig");
224 _ = @import("compiler_rt/bcmp.zig");
225 }
224226}
stage1/config.zig.in+1
......@@ -11,3 +11,4 @@ pub const value_tracing = false;
1111pub const have_stage1 = false;
1212pub const skip_non_native = false;
1313pub const only_c = true;
14pub const force_gpa = false;
stage1/zig1.c+469-206
......@@ -10,11 +10,16 @@
1010#include <stdlib.h>
1111#include <string.h>
1212
13#include <fcntl.h>
1314#include <sys/mman.h>
1415#include <sys/stat.h>
15#include <fcntl.h>
16#include <time.h>
1617#include <unistd.h>
1718
19#ifdef __linux__
20#include <sys/random.h>
21#endif
22
1823enum wasi_errno_t {
1924 WASI_ESUCCESS = 0,
2025 WASI_E2BIG = 1,
......@@ -131,15 +136,12 @@ static uint64_t rotr64(uint64_t n, unsigned c) {
131136static void *arena_alloc(size_t n) {
132137 void *ptr = malloc(n);
133138 if (!ptr) panic("out of memory");
139#ifndef NDEBUG
140 memset(ptr, 0xaa, n); // to match the zig version
141#endif
134142 return ptr;
135143}
136144
137static void *arena_realloc(void *ptr, size_t new_n) {
138 void *new_ptr = realloc(ptr, new_n);
139 if (!new_ptr) panic("out of memory");
140 return new_ptr;
141}
142
143145static int err_wrap(const char *prefix, int rc) {
144146 if (rc == -1) {
145147 perror(prefix);
......@@ -152,7 +154,7 @@ static bool bs_isSet(const uint32_t *bitset, uint32_t index) {
152154 return (bitset[index >> 5] >> (index & 0x1f)) & 1;
153155}
154156static void bs_set(uint32_t *bitset, uint32_t index) {
155 bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f));
157 bitset[index >> 5] |= ((uint32_t)1 << (index & 0x1f));
156158}
157159static void bs_unset(uint32_t *bitset, uint32_t index) {
158160 bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f));
......@@ -213,7 +215,7 @@ static const struct Preopen *find_preopen(int32_t wasi_fd) {
213215 return NULL;
214216}
215217
216static const size_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB
218static const uint32_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB
217219
218220static uint16_t read_u16_le(const char *ptr) {
219221 const uint8_t *u8_ptr = (const uint8_t *)ptr;
......@@ -655,6 +657,7 @@ struct VirtualMachine {
655657 /// Points to one after the last stack item.
656658 uint32_t stack_top;
657659 struct ProgramCounter pc;
660 /// Actual memory usage of the WASI code. The capacity is max_memory.
658661 uint32_t memory_len;
659662 const char *mod_ptr;
660663 uint8_t *opcodes;
......@@ -666,7 +669,7 @@ struct VirtualMachine {
666669 char *memory;
667670 struct Import *imports;
668671 uint32_t imports_len;
669 char **args;
672 const char **args;
670673 uint32_t *table;
671674};
672675
......@@ -678,22 +681,156 @@ static int to_host_fd(int32_t wasi_fd) {
678681
679682static enum wasi_errno_t to_wasi_err(int err) {
680683 switch (err) {
684 case E2BIG: return WASI_E2BIG;
681685 case EACCES: return WASI_EACCES;
686 case EADDRINUSE: return WASI_EADDRINUSE;
687 case EADDRNOTAVAIL: return WASI_EADDRNOTAVAIL;
688 case EAFNOSUPPORT: return WASI_EAFNOSUPPORT;
689 case EAGAIN: return WASI_EAGAIN;
690 case EALREADY: return WASI_EALREADY;
691 case EBADF: return WASI_EBADF;
692 case EBADMSG: return WASI_EBADMSG;
693 case EBUSY: return WASI_EBUSY;
694 case ECANCELED: return WASI_ECANCELED;
695 case ECHILD: return WASI_ECHILD;
696 case ECONNABORTED: return WASI_ECONNABORTED;
697 case ECONNREFUSED: return WASI_ECONNREFUSED;
698 case ECONNRESET: return WASI_ECONNRESET;
699 case EDEADLK: return WASI_EDEADLK;
700 case EDESTADDRREQ: return WASI_EDESTADDRREQ;
701 case EDOM: return WASI_EDOM;
682702 case EDQUOT: return WASI_EDQUOT;
683 case EIO: return WASI_EIO;
703 case EEXIST: return WASI_EEXIST;
704 case EFAULT: return WASI_EFAULT;
684705 case EFBIG: return WASI_EFBIG;
706 case EHOSTUNREACH: return WASI_EHOSTUNREACH;
707 case EIDRM: return WASI_EIDRM;
708 case EILSEQ: return WASI_EILSEQ;
709 case EINPROGRESS: return WASI_EINPROGRESS;
710 case EINTR: return WASI_EINTR;
711 case EINVAL: return WASI_EINVAL;
712 case EIO: return WASI_EIO;
713 case EISCONN: return WASI_EISCONN;
714 case EISDIR: return WASI_EISDIR;
715 case ELOOP: return WASI_ELOOP;
716 case EMFILE: return WASI_EMFILE;
717 case EMLINK: return WASI_EMLINK;
718 case EMSGSIZE: return WASI_EMSGSIZE;
719 case EMULTIHOP: return WASI_EMULTIHOP;
720 case ENAMETOOLONG: return WASI_ENAMETOOLONG;
721 case ENETDOWN: return WASI_ENETDOWN;
722 case ENETRESET: return WASI_ENETRESET;
723 case ENETUNREACH: return WASI_ENETUNREACH;
724 case ENFILE: return WASI_ENFILE;
725 case ENOBUFS: return WASI_ENOBUFS;
726 case ENODEV: return WASI_ENODEV;
727 case ENOENT: return WASI_ENOENT;
728 case ENOEXEC: return WASI_ENOEXEC;
729 case ENOLCK: return WASI_ENOLCK;
730 case ENOLINK: return WASI_ENOLINK;
731 case ENOMEM: return WASI_ENOMEM;
732 case ENOMSG: return WASI_ENOMSG;
733 case ENOPROTOOPT: return WASI_ENOPROTOOPT;
685734 case ENOSPC: return WASI_ENOSPC;
735 case ENOSYS: return WASI_ENOSYS;
736 case ENOTCONN: return WASI_ENOTCONN;
737 case ENOTDIR: return WASI_ENOTDIR;
738 case ENOTEMPTY: return WASI_ENOTEMPTY;
739 case ENOTRECOVERABLE: return WASI_ENOTRECOVERABLE;
740 case ENOTSOCK: return WASI_ENOTSOCK;
741 case EOPNOTSUPP: return WASI_EOPNOTSUPP;
742 case ENOTTY: return WASI_ENOTTY;
743 case ENXIO: return WASI_ENXIO;
744 case EOVERFLOW: return WASI_EOVERFLOW;
745 case EOWNERDEAD: return WASI_EOWNERDEAD;
746 case EPERM: return WASI_EPERM;
686747 case EPIPE: return WASI_EPIPE;
687 case EBADF: return WASI_EBADF;
688 case ENOMEM: return WASI_ENOMEM;
689 case ENOENT: return WASI_ENOENT;
690 case EEXIST: return WASI_EEXIST;
748 case EPROTO: return WASI_EPROTO;
749 case EPROTONOSUPPORT: return WASI_EPROTONOSUPPORT;
750 case EPROTOTYPE: return WASI_EPROTOTYPE;
751 case ERANGE: return WASI_ERANGE;
752 case EROFS: return WASI_EROFS;
753 case ESPIPE: return WASI_ESPIPE;
754 case ESRCH: return WASI_ESRCH;
755 case ESTALE: return WASI_ESTALE;
756 case ETIMEDOUT: return WASI_ETIMEDOUT;
757 case ETXTBSY: return WASI_ETXTBSY;
758 case EXDEV: return WASI_EXDEV;
691759 default:
692760 fprintf(stderr, "unexpected errno: %s\n", strerror(err));
693761 abort();
694762 };
695763}
696764
765enum wasi_filetype_t {
766 wasi_filetype_t_UNKNOWN,
767 wasi_filetype_t_BLOCK_DEVICE,
768 wasi_filetype_t_CHARACTER_DEVICE,
769 wasi_filetype_t_DIRECTORY,
770 wasi_filetype_t_REGULAR_FILE,
771 wasi_filetype_t_SOCKET_DGRAM,
772 wasi_filetype_t_SOCKET_STREAM,
773 wasi_filetype_t_SYMBOLIC_LINK,
774};
775
776static const uint16_t WASI_O_CREAT = 0x0001;
777static const uint16_t WASI_O_DIRECTORY = 0x0002;
778static const uint16_t WASI_O_EXCL = 0x0004;
779static const uint16_t WASI_O_TRUNC = 0x0008;
780
781static const uint16_t WASI_FDFLAG_APPEND = 0x0001;
782static const uint16_t WASI_FDFLAG_DSYNC = 0x0002;
783static const uint16_t WASI_FDFLAG_NONBLOCK = 0x0004;
784static const uint16_t WASI_FDFLAG_SYNC = 0x0010;
785
786static const uint64_t WASI_RIGHT_FD_READ = 0x0000000000000002ull;
787static const uint64_t WASI_RIGHT_FD_WRITE = 0x0000000000000040ull;
788
789static enum wasi_filetype_t to_wasi_filetype(mode_t st_mode) {
790 switch (st_mode & S_IFMT) {
791 case S_IFBLK:
792 return wasi_filetype_t_BLOCK_DEVICE;
793 case S_IFCHR:
794 return wasi_filetype_t_CHARACTER_DEVICE;
795 case S_IFDIR:
796 return wasi_filetype_t_DIRECTORY;
797 case S_IFLNK:
798 return wasi_filetype_t_SYMBOLIC_LINK;
799 case S_IFREG:
800 return wasi_filetype_t_REGULAR_FILE;
801 default:
802 return wasi_filetype_t_UNKNOWN;
803 }
804}
805
806static uint64_t to_wasi_timestamp(struct timespec ts) {
807 return ts.tv_sec * 1000000000ull + ts.tv_nsec;
808}
809
810/// const filestat_t = extern struct {
811/// dev: device_t, u64
812/// ino: inode_t, u64
813/// filetype: filetype_t, u8
814/// nlink: linkcount_t, u64
815/// size: filesize_t, u64
816/// atim: timestamp_t, u64
817/// mtim: timestamp_t, u64
818/// ctim: timestamp_t, u64
819/// };
820static enum wasi_errno_t finish_wasi_stat(struct VirtualMachine *vm,
821 uint32_t buf, struct stat st)
822{
823 write_u64_le(vm->memory + buf + 0x00, 0); // device
824 write_u64_le(vm->memory + buf + 0x08, st.st_ino);
825 write_u64_le(vm->memory + buf + 0x10, to_wasi_filetype(st.st_mode));
826 write_u64_le(vm->memory + buf + 0x18, 1); // nlink
827 write_u64_le(vm->memory + buf + 0x20, st.st_size);
828 write_u64_le(vm->memory + buf + 0x28, to_wasi_timestamp(st.st_atim));
829 write_u64_le(vm->memory + buf + 0x30, to_wasi_timestamp(st.st_mtim));
830 write_u64_le(vm->memory + buf + 0x38, to_wasi_timestamp(st.st_ctim));
831 return WASI_ESUCCESS;
832}
833
697834/// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t;
698835static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm,
699836 uint32_t argc, uint32_t argv_buf_size)
......@@ -713,17 +850,19 @@ static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm,
713850static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm,
714851 uint32_t argv, uint32_t argv_buf)
715852{
716 panic("TODO implement wasi_args_get");
717 //var argv_buf_i: usize = 0;
718 //for (vm->args) |arg, arg_i| {
719 // // Write the arg to the buffer.
720 // const argv_ptr = argv_buf + argv_buf_i;
721 // const arg_len = mem.span(arg).len + 1;
722 // mem.copy(u8, vm->memory[argv_buf + argv_buf_i ..], arg[0..arg_len]);
723 // argv_buf_i += arg_len;
724
725 // write_u32_le(vm->memory[argv + 4 * arg_i ..][0..4], @intCast(u32, argv_ptr));
726 //}
853 uint32_t argv_buf_i = 0;
854 uint32_t arg_i = 0;
855 for (;; arg_i += 1) {
856 const char *arg = vm->args[arg_i];
857 if (!arg) break;
858 // Write the arg to the buffer.
859 uint32_t argv_ptr = argv_buf + argv_buf_i;
860 uint32_t arg_len = strlen(arg) + 1;
861 memcpy(vm->memory + argv_buf + argv_buf_i, arg, arg_len);
862 argv_buf_i += arg_len;
863
864 write_u32_le(vm->memory + argv + 4 * arg_i , argv_ptr);
865 }
727866 return WASI_ESUCCESS;
728867}
729868
......@@ -731,9 +870,15 @@ static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm,
731870static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm,
732871 uint32_t buf, uint32_t buf_len)
733872{
734 panic("TODO implement wasi_random_get");
735 //const host_buf = vm->memory[buf..][0..buf_len];
736 //std.crypto.random.bytes(host_buf);
873#ifdef __linux__
874 if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) {
875 panic("getrandom failed");
876 }
877#else
878 for (uint32_t i = 0; i < buf_len; i += 1) {
879 vm->memory[buf + i] = rand();
880 }
881#endif
737882 return WASI_ESUCCESS;
738883}
739884
......@@ -745,10 +890,10 @@ static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm,
745890static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm,
746891 int32_t fd, uint32_t buf)
747892{
748 panic("TODO implement wasi_fd_prestat_get");
749 //const preopen = findPreopen(fd) orelse return .BADF;
750 //write_u32_le(vm->memory[buf + 0 ..][0..4], 0);
751 //write_u32_le(vm->memory[buf + 4 ..][0..4], @intCast(u32, preopen.name.len));
893 const struct Preopen *preopen = find_preopen(fd);
894 if (!preopen) return WASI_EBADF;
895 write_u32_le(vm->memory + buf + 0, 0);
896 write_u32_le(vm->memory + buf + 4, preopen->name_len);
752897 return WASI_ESUCCESS;
753898}
754899
......@@ -756,19 +901,18 @@ static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm,
756901static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm,
757902 int32_t fd, uint32_t path, uint32_t path_len)
758903{
759 panic("TODO implement wasi_fd_prestat_dir_name");
760 //const preopen = findPreopen(fd) orelse return .BADF;
761 //assert(path_len == preopen.name.len);
762 //mem.copy(u8, vm->memory[path..], preopen.name);
904 const struct Preopen *preopen = find_preopen(fd);
905 if (!preopen) return WASI_EBADF;
906 if (path_len != preopen->name_len)
907 panic("wasi_fd_prestat_dir_name expects correct name_len");
908 memcpy(vm->memory + path, preopen->name, path_len);
763909 return WASI_ESUCCESS;
764910}
765911
766912/// extern fn fd_close(fd: fd_t) errno_t;
767913static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) {
768 panic("TODO implement wasi_fd_close");
769 //_ = vm;
770 //const host_fd = toHostFd(fd);
771 //os.close(host_fd);
914 int host_fd = to_host_fd(fd);
915 close(host_fd);
772916 return WASI_ESUCCESS;
773917}
774918
......@@ -779,20 +923,18 @@ static enum wasi_errno_t wasi_fd_read(
779923 uint32_t iovs_len, // usize
780924 uint32_t nread // *usize
781925) {
782 panic("TODO implement wasi_fd_read");
783 //const host_fd = toHostFd(fd);
784 //var i: u32 = 0;
785 //var total_read: usize = 0;
786 //while (i < iovs_len) : (i += 1) {
787 // uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
788 // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
789 // const buf = vm->memory[ptr..][0..len];
790 // const read = os.read(host_fd, buf) catch |err| return toWasiError(err);
791 // trace_log.debug("read {d} bytes out of {d}", .{ read, buf.len });
792 // total_read += read;
793 // if (read != buf.len) break;
794 //}
795 //write_u32_le(vm->memory[nread..][0..4], @intCast(u32, total_read));
926 int host_fd = to_host_fd(fd);
927 uint32_t i = 0;
928 size_t total_read = 0;
929 for (; i < iovs_len; i += 1) {
930 uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
931 uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
932 ssize_t amt_read = read(host_fd, vm->memory + ptr, len);
933 if (amt_read < 0) return to_wasi_err(errno);
934 total_read += amt_read;
935 if (amt_read != len) break;
936 }
937 write_u32_le(vm->memory + nread, total_read);
796938 return WASI_ESUCCESS;
797939}
798940
......@@ -826,19 +968,18 @@ static enum wasi_errno_t wasi_fd_pwrite(
826968 uint64_t offset, // wasi.filesize_t,
827969 uint32_t written_ptr // *usize
828970) {
829 panic("TODO implement wasi_fd_pwrite");
830 //const host_fd = toHostFd(fd);
831 //var i: u32 = 0;
832 //var written: usize = 0;
833 //while (i < iovs_len) : (i += 1) {
834 // uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
835 // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
836 // const buf = vm->memory[ptr..][0..len];
837 // const w = os.pwrite(host_fd, buf, offset + written) catch |err| return toWasiError(err);
838 // written += w;
839 // if (w != buf.len) break;
840 //}
841 //write_u32_le(vm->memory[written_ptr..][0..4], @intCast(u32, written));
971 int host_fd = to_host_fd(fd);
972 uint32_t i = 0;
973 size_t written = 0;
974 for (; i < iovs_len; i += 1) {
975 uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0);
976 uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4);
977 ssize_t w = pwrite(host_fd, vm->memory + ptr, len, offset + written);
978 if (w < 0) return to_wasi_err(errno);
979 written += w;
980 if (w != len) break;
981 }
982 write_u32_le(vm->memory + written_ptr, written);
842983 return WASI_ESUCCESS;
843984}
844985
......@@ -865,29 +1006,34 @@ static enum wasi_errno_t wasi_path_open(
8651006 uint16_t fs_flags, // wasi.fdflags_t,
8661007 uint32_t fd
8671008) {
868 panic("TODO implement wasi_path_open");
869 //const sub_path = vm->memory[path..][0..path_len];
870 //const host_fd = toHostFd(dirfd);
871 //var flags: u32 = @as(u32, if (oflags & wasi.O.CREAT != 0) os.O.CREAT else 0) |
872 // @as(u32, if (oflags & wasi.O.DIRECTORY != 0) os.O.DIRECTORY else 0) |
873 // @as(u32, if (oflags & wasi.O.EXCL != 0) os.O.EXCL else 0) |
874 // @as(u32, if (oflags & wasi.O.TRUNC != 0) os.O.TRUNC else 0) |
875 // @as(u32, if (fs_flags & wasi.FDFLAG.APPEND != 0) os.O.APPEND else 0) |
876 // @as(u32, if (fs_flags & wasi.FDFLAG.DSYNC != 0) os.O.DSYNC else 0) |
877 // @as(u32, if (fs_flags & wasi.FDFLAG.NONBLOCK != 0) os.O.NONBLOCK else 0) |
878 // @as(u32, if (fs_flags & wasi.FDFLAG.SYNC != 0) os.O.SYNC else 0);
879 //if ((fs_rights_base & wasi.RIGHT.FD_READ != 0) and
880 // (fs_rights_base & wasi.RIGHT.FD_WRITE != 0))
881 //{
882 // flags |= os.O.RDWR;
883 //} else if (fs_rights_base & wasi.RIGHT.FD_WRITE != 0) {
884 // flags |= os.O.WRONLY;
885 //} else if (fs_rights_base & wasi.RIGHT.FD_READ != 0) {
886 // flags |= os.O.RDONLY; // no-op because O_RDONLY is 0
887 //}
888 //const mode = 0o644;
889 //const res_fd = os.openat(host_fd, sub_path, flags, mode) catch |err| return toWasiError(err);
890 //mem.writeIntLittle(i32, vm->memory[fd..][0..4], res_fd);
1009 char sub_path[PATH_MAX];
1010 memcpy(sub_path, vm->memory + path, path_len);
1011 sub_path[path_len] = 0;
1012
1013 int host_fd = to_host_fd(dirfd);
1014 uint32_t flags =
1015 (((oflags & WASI_O_CREAT) != 0) ? O_CREAT : 0) |
1016 (((oflags & WASI_O_DIRECTORY) != 0) ? O_DIRECTORY : 0) |
1017 (((oflags & WASI_O_EXCL) != 0) ? O_EXCL : 0) |
1018 (((oflags & WASI_O_TRUNC) != 0) ? O_TRUNC : 0) |
1019 (((fs_flags & WASI_FDFLAG_APPEND) != 0) ? O_APPEND : 0) |
1020 (((fs_flags & WASI_FDFLAG_DSYNC) != 0) ? O_DSYNC : 0) |
1021 (((fs_flags & WASI_FDFLAG_NONBLOCK) != 0) ? O_NONBLOCK : 0) |
1022 (((fs_flags & WASI_FDFLAG_SYNC) != 0) ? O_SYNC : 0);
1023
1024 if (((fs_rights_base & WASI_RIGHT_FD_READ) != 0) &&
1025 ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0))
1026 {
1027 flags |= O_RDWR;
1028 } else if ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0) {
1029 flags |= O_WRONLY;
1030 } else if ((fs_rights_base & WASI_RIGHT_FD_READ) != 0) {
1031 flags |= O_RDONLY; // no-op because O_RDONLY is 0
1032 }
1033 mode_t mode = 0644;
1034 int res_fd = openat(host_fd, sub_path, flags, mode);
1035 if (res_fd == -1) return to_wasi_err(errno);
1036 write_u32_le(vm->memory + fd, res_fd);
8911037 return WASI_ESUCCESS;
8921038}
8931039
......@@ -899,23 +1045,26 @@ static enum wasi_errno_t wasi_path_filestat_get(
8991045 uint32_t path_len, // usize
9001046 uint32_t buf // *filestat_t
9011047) {
902 panic("TODO implement wasi_path_filestat_get");
903 //const sub_path = vm->memory[path..][0..path_len];
904 //const host_fd = toHostFd(fd);
905 //const dir: fs.Dir = .{ .fd = host_fd };
906 //const stat = dir.statFile(sub_path) catch |err| return toWasiError(err);
907 //return finishWasiStat(vm, buf, stat);
908 return WASI_ESUCCESS;
1048 char sub_path[PATH_MAX];
1049 memcpy(sub_path, vm->memory + path, path_len);
1050 sub_path[path_len] = 0;
1051
1052 int host_fd = to_host_fd(fd);
1053 struct stat st;
1054 if (fstatat(host_fd, sub_path, &st, 0) == -1) return to_wasi_err(errno);
1055 return finish_wasi_stat(vm, buf, st);
9091056}
9101057
9111058/// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t;
912static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, int32_t fd, uint32_t path, uint32_t path_len) {
913 panic("TODO implement wasi_path_create_directory");
914 //const sub_path = vm->memory[path..][0..path_len];
915 //trace_log.debug("wasi_path_create_directory fd={d} path={s}", .{ fd, sub_path });
916 //const host_fd = toHostFd(fd);
917 //const dir: fs.Dir = .{ .fd = host_fd };
918 //dir.makeDir(sub_path) catch |err| return toWasiError(err);
1059static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm,
1060 int32_t wasi_fd, uint32_t path, uint32_t path_len)
1061{
1062 char sub_path[PATH_MAX];
1063 memcpy(sub_path, vm->memory + path, path_len);
1064 sub_path[path_len] = 0;
1065
1066 int host_fd = to_host_fd(wasi_fd);
1067 if (mkdirat(host_fd, sub_path, 0777) == -1) return to_wasi_err(errno);
9191068 return WASI_ESUCCESS;
9201069}
9211070
......@@ -928,35 +1077,33 @@ static enum wasi_errno_t wasi_path_rename(
9281077 uint32_t new_path_ptr, // [*]const u8
9291078 uint32_t new_path_len // usize
9301079) {
931 panic("TODO implement wasi_path_rename");
932 //const old_path = vm->memory[old_path_ptr..][0..old_path_len];
933 //const new_path = vm->memory[new_path_ptr..][0..new_path_len];
934 //trace_log.debug("wasi_path_rename old_fd={d} old_path={s} new_fd={d} new_path={s}", .{
935 // old_fd, old_path, new_fd, new_path,
936 //});
937 //const old_host_fd = toHostFd(old_fd);
938 //const new_host_fd = toHostFd(new_fd);
939 //os.renameat(old_host_fd, old_path, new_host_fd, new_path) catch |err| return toWasiError(err);
1080 char old_path[PATH_MAX];
1081 memcpy(old_path, vm->memory + old_path_ptr, old_path_len);
1082 old_path[old_path_len] = 0;
1083
1084 char new_path[PATH_MAX];
1085 memcpy(new_path, vm->memory + new_path_ptr, new_path_len);
1086 new_path[new_path_len] = 0;
1087
1088 int old_host_fd = to_host_fd(old_fd);
1089 int new_host_fd = to_host_fd(new_fd);
1090 if (renameat(old_host_fd, old_path, new_host_fd, new_path) == -1) return to_wasi_err(errno);
9401091 return WASI_ESUCCESS;
9411092}
9421093
9431094/// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t;
9441095static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) {
945 panic("TODO implement wasi_fd_filestat_get");
946 //const host_fd = toHostFd(fd);
947 //const file = fs.File{ .handle = host_fd };
948 //const stat = file.stat() catch |err| return toWasiError(err);
949 //return finishWasiStat(vm, buf, stat);
950 return WASI_ESUCCESS;
1096 int host_fd = to_host_fd(fd);
1097 struct stat st;
1098 if (fstat(host_fd, &st) == -1) return to_wasi_err(errno);
1099 return finish_wasi_stat(vm, buf, st);
9511100}
9521101
9531102static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm,
9541103 int32_t fd, uint64_t size)
9551104{
956 panic("TODO implement wasi_fd_filestat_set_size");
957 //_ = vm;
958 //const host_fd = toHostFd(fd);
959 //os.ftruncate(host_fd, size) catch |err| return toWasiError(err);
1105 int host_fd = to_host_fd(fd);
1106 if (ftruncate(host_fd, size) == -1) return to_wasi_err(errno);
9601107 return WASI_ESUCCESS;
9611108}
9621109
......@@ -968,14 +1115,13 @@ static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm,
9681115/// fs_rights_inheriting: rights_t, u64
9691116/// };
9701117static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) {
971 panic("TODO implement wasi_fd_fdstat_get");
972 //const host_fd = toHostFd(fd);
973 //const file = fs.File{ .handle = host_fd };
974 //const stat = file.stat() catch |err| return toWasiError(err);
975 //mem.writeIntLittle(u16, vm->memory[buf + 0x00 ..][0..2], @enumToInt(toWasiFileType(stat.kind)));
976 //mem.writeIntLittle(u16, vm->memory[buf + 0x02 ..][0..2], 0); // flags
977 //mem.writeIntLittle(u64, vm->memory[buf + 0x08 ..][0..8], math.maxInt(u64)); // rights_base
978 //mem.writeIntLittle(u64, vm->memory[buf + 0x10 ..][0..8], math.maxInt(u64)); // rights_inheriting
1118 int host_fd = to_host_fd(fd);
1119 struct stat st;
1120 if (fstat(host_fd, &st) == -1) return to_wasi_err(errno);
1121 write_u16_le(vm->memory + buf + 0x00, to_wasi_filetype(st.st_mode));
1122 write_u16_le(vm->memory + buf + 0x02, 0); // flags
1123 write_u64_le(vm->memory + buf + 0x08, UINT64_MAX); // rights_base
1124 write_u64_le(vm->memory + buf + 0x10, UINT64_MAX); // rights_inheriting
9791125 return WASI_ESUCCESS;
9801126}
9811127
......@@ -983,31 +1129,24 @@ static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t f
9831129static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm,
9841130 uint32_t clock_id, uint64_t precision, uint32_t timestamp)
9851131{
986 panic("TODO implement wasi_clock_time_get");
987 ////const host_clock_id = toHostClockId(clock_id);
988 //_ = precision;
989 //_ = clock_id;
990 //const wasi_ts = toWasiTimestamp(std.time.nanoTimestamp());
991 //mem.writeIntLittle(u64, vm->memory[timestamp..][0..8], wasi_ts);
1132 if (clock_id != 1) panic("expected wasi_clock_time_get to use CLOCK_MONOTONIC");
1133 struct timespec ts;
1134 if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return to_wasi_err(errno);
1135 uint64_t wasi_ts = to_wasi_timestamp(ts);
1136 write_u64_le(vm->memory + timestamp, wasi_ts);
9921137 return WASI_ESUCCESS;
9931138}
9941139
9951140///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void;
9961141void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) {
997 panic("TODO implement wasi_debug");
998 //const s = mem.sliceTo(vm->memory[text..], 0);
999 //trace_log.debug("wasi_debug: '{s}' number={d} {x}", .{ s, n, n });
1142 fprintf(stderr, "wasi_debug: '%s' number=%lu %lx\n", vm->memory + text, n, n);
10001143}
10011144
10021145/// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void;
10031146void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) {
1004 panic("TODO implement wasi_debug_slice");
1005 //const s = vm->memory[ptr..][0..len];
1006 //trace_log.debug("wasi_debug_slice: '{s}'", .{s});
1147 fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr);
10071148}
10081149
1009
1010
10111150struct Label {
10121151 enum WasmOp opcode;
10131152 uint32_t stack_depth;
......@@ -1049,6 +1188,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
10491188 static uint32_t stack_types[1 << (12 - 3)];
10501189
10511190 static struct Label labels[1 << 9];
1191#ifndef NDEBUG
1192 memset(labels, 0xaa, sizeof(struct Label) * (1 << 9)); // to match the zig version
1193#endif
10521194 uint32_t label_i = 0;
10531195 labels[label_i].opcode = WasmOp_block;
10541196 labels[label_i].stack_depth = stack_depth;
......@@ -1061,6 +1203,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
10611203 enum WasmPrefixedOp prefixed_opcode;
10621204 if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i);
10631205
1206 //fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand);
1207 //struct ProgramCounter old_pc = *pc;
1208
10641209 uint32_t initial_stack_depth = stack_depth;
10651210 if (unreachable_depth == 0) {
10661211 switch (opcode) {
......@@ -1549,11 +1694,16 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
15491694 label->type_info.param_count = 0;
15501695 label->type_info.param_types = 0;
15511696 label->type_info.result_count = block_type != -0x40;
1552 label->type_info.result_types = 0;
15531697 switch (block_type) {
1554 case -0x40: break;
1555 case -1: case -3: bs_unset(&label->type_info.param_types, 0); break;
1556 case -2: case -4: bs_set(&label->type_info.param_types, 0); break;
1698 case -0x40:
1699 case -1:
1700 case -3:
1701 label->type_info.result_types = 0;
1702 break;
1703 case -2:
1704 case -4:
1705 label->type_info.result_types = UINT32_MAX;
1706 break;
15571707 default: panic("unexpected param type");
15581708 }
15591709 } else {
......@@ -1584,7 +1734,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
15841734 break;
15851735
15861736 case WasmOp_else:
1587 {
1737 if (unreachable_depth <= 1) {
15881738 struct Label *label = &labels[label_i];
15891739 assert(label->opcode == WasmOp_if);
15901740 label->opcode = WasmOp_else;
......@@ -1596,9 +1746,12 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
15961746 break;
15971747
15981748 case 1:
1599 switch ((int)Label_operandType(label, 0)) {
1600 case false: opcodes[pc->opcode] = Op_br_32; break;
1601 case true: opcodes[pc->opcode] = Op_br_64; break;
1749 //fprintf(stderr, "label_i=%u operand_type=%d\n",
1750 // label_i, Label_operandType(label, 0));
1751 if (Label_operandType(label, 0)) {
1752 opcodes[pc->opcode] = Op_br_64;
1753 } else {
1754 opcodes[pc->opcode] = Op_br_32;
16021755 }
16031756 break;
16041757
......@@ -1614,7 +1767,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
16141767 operands[label->extra.else_ref + 0] = pc->opcode;
16151768 operands[label->extra.else_ref + 1] = pc->operand;
16161769 stack_depth = label->stack_depth + label->type_info.param_count;
1617 };
1770 }
16181771 break;
16191772
16201773 case WasmOp_end:
......@@ -1705,7 +1858,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
17051858 }
17061859 break;
17071860
1708 default: panic("unexpected opcode");
1861 default: panic("unreachable");
17091862 }
17101863 pc->opcode += 1;
17111864 operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth;
......@@ -1748,11 +1901,6 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
17481901 label->ref_list = pc->operand + 1;
17491902 pc->operand += 3;
17501903 }
1751
1752 opcodes[pc->opcode] = opcode;
1753 pc->opcode += 1;
1754 operands[pc->operand] = labels_len;
1755 pc->operand += 1;
17561904 }
17571905 break;
17581906
......@@ -1796,7 +1944,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
17961944 break;
17971945
17981946 case WasmOp_return:
1799 {
1947 if (unreachable_depth <= 1) {
18001948 uint32_t operand_count = Label_operandCount(&labels[0]);
18011949 switch (operand_count) {
18021950 case 0:
......@@ -2066,9 +2214,11 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
20662214 break;
20672215
20682216 default:
2069 opcodes[pc->opcode + 0] = Op_wasm;
2070 opcodes[pc->opcode + 1] = opcode;
2071 pc->opcode += 2;
2217 if (unreachable_depth == 0) {
2218 opcodes[pc->opcode + 0] = Op_wasm;
2219 opcodes[pc->opcode + 1] = opcode;
2220 pc->opcode += 2;
2221 }
20722222 break;
20732223
20742224 case WasmOp_prefixed:
......@@ -2125,6 +2275,13 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint
21252275 default:
21262276 break;
21272277 }
2278
2279 //for (uint32_t i = old_pc.opcode; i < pc->opcode; i += 1) {
2280 // fprintf(stderr, "decoded opcode[%u] = %u\n", i, opcodes[i]);
2281 //}
2282 //for (uint32_t i = old_pc.operand; i < pc->operand; i += 1) {
2283 // fprintf(stderr, "decoded operand[%u] = %u\n", i, operands[i]);
2284 //}
21282285 }
21292286}
21302287
......@@ -2184,7 +2341,7 @@ static float vm_pop_f32(struct VirtualMachine *vm) {
21842341}
21852342
21862343static double vm_pop_f64(struct VirtualMachine *vm) {
2187 uint32_t integer = vm_pop_u64(vm);
2344 uint64_t integer = vm_pop_u64(vm);
21882345 double result;
21892346 memcpy(&result, &integer, 8);
21902347 return result;
......@@ -2251,7 +2408,7 @@ static void vm_callImport(struct VirtualMachine *vm, struct Import import) {
22512408 break;
22522409 case ImpName_fd_readdir:
22532410 {
2254 panic("TODO implement fd_readdir");
2411 panic("unexpected call to fd_readdir");
22552412 }
22562413 break;
22572414 case ImpName_fd_write:
......@@ -2422,8 +2579,12 @@ static void vm_call(struct VirtualMachine *vm, uint32_t fn_id) {
24222579 uint32_t fn_idx = fn_id - vm->imports_len;
24232580 struct Function *func = &vm->functions[fn_idx];
24242581
2582 //struct TypeInfo *type_info = &vm->types[func->type_idx];
2583 //fprintf(stderr, "enter fn_id: %u, param_count: %u, result_count: %u, locals_count: %u\n",
2584 // fn_id, type_info->param_count, type_info->result_count, func->locals_count);
2585
24252586 // Push zeroed locals to stack
2426 memset(&vm->stack[vm->stack_top], 0, func->locals_count * sizeof(uint64_t));
2587 memset(vm->stack + vm->stack_top, 0, func->locals_count * sizeof(uint64_t));
24272588 vm->stack_top += func->locals_count;
24282589
24292590 vm_push_u32(vm, vm->pc.opcode);
......@@ -2504,6 +2665,10 @@ static void vm_run(struct VirtualMachine *vm) {
25042665 for (;;) {
25052666 enum Op op = opcodes[pc->opcode];
25062667 pc->opcode += 1;
2668 //if (vm->stack_top > 0) {
2669 // fprintf(stderr, "stack[%u]=%lx pc=%u:%u, op=%u\n",
2670 // vm->stack_top - 1, vm->stack[vm->stack_top - 1], pc->opcode, pc->operand, op);
2671 //}
25072672 switch (op) {
25082673 case Op_unreachable:
25092674 panic("unreachable reached");
......@@ -2738,6 +2903,7 @@ static void vm_run(struct VirtualMachine *vm) {
27382903 case Op_wasm:
27392904 {
27402905 enum WasmOp wasm_op = opcodes[pc->opcode];
2906 //fprintf(stderr, "op2=%x\n", wasm_op);
27412907 pc->opcode += 1;
27422908 switch (wasm_op) {
27432909 case WasmOp_unreachable:
......@@ -2820,7 +2986,7 @@ static void vm_run(struct VirtualMachine *vm) {
28202986 {
28212987 uint32_t offset = operands[pc->operand] + vm_pop_u32(vm);
28222988 pc->operand += 1;
2823 vm_push_u32(vm, vm->memory[offset]);
2989 vm_push_u32(vm, (uint8_t)vm->memory[offset]);
28242990 }
28252991 break;
28262992 case WasmOp_i32_load16_s:
......@@ -2850,7 +3016,7 @@ static void vm_run(struct VirtualMachine *vm) {
28503016 {
28513017 uint32_t offset = operands[pc->operand] + vm_pop_u32(vm);
28523018 pc->operand += 1;
2853 vm_push_u64(vm, vm->memory[offset]);
3019 vm_push_u64(vm, (uint8_t)vm->memory[offset]);
28543020 }
28553021 break;
28563022 case WasmOp_i64_load16_s:
......@@ -2968,7 +3134,7 @@ static void vm_run(struct VirtualMachine *vm) {
29683134 uint32_t page_count = vm_pop_u32(vm);
29693135 uint32_t old_page_count = vm->memory_len / wasm_page_size;
29703136 uint32_t new_len = vm->memory_len + page_count * wasm_page_size;
2971 if (new_len > vm->memory_len) {
3137 if (new_len > max_memory) {
29723138 vm_push_i32(vm, -1);
29733139 } else {
29743140 vm->memory_len = new_len;
......@@ -3294,21 +3460,21 @@ static void vm_run(struct VirtualMachine *vm) {
32943460 {
32953461 uint32_t rhs = vm_pop_u32(vm);
32963462 uint32_t lhs = vm_pop_u32(vm);
3297 vm_push_u32(vm, lhs << rhs);
3463 vm_push_u32(vm, lhs << (rhs & 0x1f));
32983464 }
32993465 break;
33003466 case WasmOp_i32_shr_s:
33013467 {
33023468 uint32_t rhs = vm_pop_u32(vm);
33033469 int32_t lhs = vm_pop_i32(vm);
3304 vm_push_i32(vm, lhs >> rhs);
3470 vm_push_i32(vm, lhs >> (rhs & 0x1f));
33053471 }
33063472 break;
33073473 case WasmOp_i32_shr_u:
33083474 {
33093475 uint32_t rhs = vm_pop_u32(vm);
33103476 uint32_t lhs = vm_pop_u32(vm);
3311 vm_push_u32(vm, lhs >> rhs);
3477 vm_push_u32(vm, lhs >> (rhs & 0x1f));
33123478 }
33133479 break;
33143480 case WasmOp_i32_rotl:
......@@ -3421,35 +3587,35 @@ static void vm_run(struct VirtualMachine *vm) {
34213587 {
34223588 uint64_t rhs = vm_pop_u64(vm);
34233589 uint64_t lhs = vm_pop_u64(vm);
3424 vm_push_u64(vm, lhs << rhs);
3590 vm_push_u64(vm, lhs << (rhs & 0x3f));
34253591 }
34263592 break;
34273593 case WasmOp_i64_shr_s:
34283594 {
34293595 uint64_t rhs = vm_pop_u64(vm);
34303596 int64_t lhs = vm_pop_i64(vm);
3431 vm_push_i64(vm, lhs >> rhs);
3597 vm_push_i64(vm, lhs >> (rhs & 0x3f));
34323598 }
34333599 break;
34343600 case WasmOp_i64_shr_u:
34353601 {
34363602 uint64_t rhs = vm_pop_u64(vm);
34373603 uint64_t lhs = vm_pop_u64(vm);
3438 vm_push_u64(vm, lhs >> rhs);
3604 vm_push_u64(vm, lhs >> (rhs & 0x3f));
34393605 }
34403606 break;
34413607 case WasmOp_i64_rotl:
34423608 {
34433609 uint64_t rhs = vm_pop_u64(vm);
34443610 uint64_t lhs = vm_pop_u64(vm);
3445 vm_push_u64(vm, rotl64(lhs, rhs ));
3611 vm_push_u64(vm, rotl64(lhs, rhs));
34463612 }
34473613 break;
34483614 case WasmOp_i64_rotr:
34493615 {
34503616 uint64_t rhs = vm_pop_u64(vm);
34513617 uint64_t lhs = vm_pop_u64(vm);
3452 vm_push_u64(vm, rotr64(lhs, rhs ));
3618 vm_push_u64(vm, rotr64(lhs, rhs));
34533619 }
34543620 break;
34553621
......@@ -3839,19 +4005,126 @@ static void vm_run(struct VirtualMachine *vm) {
38394005 }
38404006}
38414007
4008static size_t common_prefix(const char *a, const char *b) {
4009 size_t i = 0;
4010 for (; a[i] == b[i]; i += 1) {}
4011 return i;
4012}
4013
38424014int main(int argc, char **argv) {
38434015 char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
38444016
38454017 const char *zig_lib_dir_path = argv[1];
3846 const char *zig_cache_dir_path = argv[2];
3847 const size_t vm_argv_start = 3;
3848 const char *wasm_file = argv[vm_argv_start];
4018 const char *cmake_binary_dir_path = argv[2];
4019 const char *root_name = argv[3];
4020 size_t argv_i = 4;
4021 const char *wasm_file = argv[argv_i];
4022
4023 size_t cwd_path_len = common_prefix(zig_lib_dir_path, cmake_binary_dir_path);
4024 const char *rel_cmake_bin_path = cmake_binary_dir_path + cwd_path_len;
4025 size_t rel_cmake_bin_path_len = strlen(rel_cmake_bin_path);
4026
4027 const char *new_argv[30];
4028 char new_argv_buf[PATH_MAX + 1024];
4029 uint32_t new_argv_i = 0;
4030 uint32_t new_argv_buf_i = 0;
4031
4032 int cache_dir = -1;
4033 {
4034 char cache_dir_buf[PATH_MAX * 2];
4035 size_t i = 0;
4036 size_t cmake_binary_dir_path_len = strlen(cmake_binary_dir_path);
4037
4038 memcpy(cache_dir_buf + i, cmake_binary_dir_path, cmake_binary_dir_path_len);
4039 i += cmake_binary_dir_path_len;
4040
4041 cache_dir_buf[i] = '/';
4042 i += 1;
4043
4044 memcpy(cache_dir_buf + i, "zig1-cache", strlen("zig1-cache"));
4045 i += strlen("zig1-cache");
4046
4047 cache_dir_buf[i] = 0;
4048
4049 mkdir(cache_dir_buf, 0777);
4050 cache_dir = err_wrap("opening cache dir",
4051 open(cache_dir_buf, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH));
4052 }
4053
4054 // Construct a new argv for the WASI code which has absolute paths
4055 // converted to relative paths, and has the target and terminal status
4056 // autodetected.
4057
4058 // wasm file path
4059 new_argv[new_argv_i] = argv[argv_i];
4060 new_argv_i += 1;
4061 argv_i += 1;
4062
4063 for(; argv[argv_i]; argv_i += 1) {
4064 new_argv[new_argv_i] = argv[argv_i];
4065 new_argv_i += 1;
4066 }
4067
4068 {
4069 new_argv[new_argv_i] = "--name";
4070 new_argv_i += 1;
4071
4072 new_argv[new_argv_i] = root_name;
4073 new_argv_i += 1;
4074
4075 char *emit_bin_arg = new_argv_buf + new_argv_buf_i;
4076 memcpy(new_argv_buf + new_argv_buf_i, "-femit-bin=", strlen("-femit-bin="));
4077 new_argv_buf_i += strlen("-femit-bin=");
4078 memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len);
4079 new_argv_buf_i += rel_cmake_bin_path_len;
4080 new_argv_buf[new_argv_buf_i] = '/';
4081 new_argv_buf_i += 1;
4082 memcpy(new_argv_buf + new_argv_buf_i, root_name, strlen(root_name));
4083 new_argv_buf_i += strlen(root_name);
4084 memcpy(new_argv_buf + new_argv_buf_i, ".c", 3);
4085 new_argv_buf_i += 3;
4086
4087 new_argv[new_argv_i] = emit_bin_arg;
4088 new_argv_i += 1;
4089 }
4090
4091 {
4092 new_argv[new_argv_i] = "--pkg-begin";
4093 new_argv_i += 1;
4094
4095 new_argv[new_argv_i] = "build_options";
4096 new_argv_i += 1;
4097
4098 char *build_options_path = new_argv_buf + new_argv_buf_i;
4099 memcpy(new_argv_buf + new_argv_buf_i, rel_cmake_bin_path, rel_cmake_bin_path_len);
4100 new_argv_buf_i += rel_cmake_bin_path_len;
4101 new_argv_buf[new_argv_buf_i] = '/';
4102 new_argv_buf_i += 1;
4103 memcpy(new_argv_buf + new_argv_buf_i, "config.zig", strlen("config.zig"));
4104 new_argv_buf_i += strlen("config.zig");
4105 new_argv_buf[new_argv_buf_i] = 0;
4106 new_argv_buf_i += 1;
4107
4108 new_argv[new_argv_i] = build_options_path;
4109 new_argv_i += 1;
4110
4111 new_argv[new_argv_i] = "--pkg-end";
4112 new_argv_i += 1;
4113 }
4114
4115 if (isatty(STDERR_FILENO) != 0) {
4116 new_argv[new_argv_i] = "--color";
4117 new_argv_i += 1;
4118
4119 new_argv[new_argv_i] = "on";
4120 new_argv_i += 1;
4121 }
4122
4123 new_argv[new_argv_i] = NULL;
38494124
38504125 const struct ByteSlice mod = read_file_alloc(wasm_file);
38514126
38524127 int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH));
3853 mkdir(zig_cache_dir_path, 0666);
3854 int cache_dir = err_wrap("opening cache dir", open(zig_cache_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH));
38554128 int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH));
38564129
38574130 add_preopen(0, "stdin", STDIN_FILENO);
......@@ -3873,7 +4146,7 @@ int main(int argc, char **argv) {
38734146 if (version != 1) panic("bad wasm version");
38744147
38754148 uint32_t section_starts[13];
3876 memset(&section_starts, 0, 4 * 13);
4149 memset(&section_starts, 0, sizeof(uint32_t) * 13);
38774150
38784151 while (i < mod.len) {
38794152 uint8_t section_id = mod.ptr[i];
......@@ -3895,6 +4168,7 @@ int main(int argc, char **argv) {
38954168 i += 1;
38964169
38974170 info->param_count = read32_uleb128(mod.ptr, &i);
4171 if (info->param_count > 32) panic("found a type with over 32 parameters");
38984172 info->param_types = 0;
38994173 for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) {
39004174 int64_t param_type = read64_ileb128(mod.ptr, &i);
......@@ -4133,7 +4407,7 @@ int main(int argc, char **argv) {
41334407 uint32_t elem_count = read32_uleb128(mod.ptr, &i);
41344408
41354409 table = arena_alloc(sizeof(uint32_t) * maximum);
4136 memset(table, 0, maximum);
4410 memset(table, 0, sizeof(uint32_t) * maximum);
41374411
41384412 for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) {
41394413 table[elem_i + offset] = read32_uleb128(mod.ptr, &i);
......@@ -4142,6 +4416,9 @@ int main(int argc, char **argv) {
41424416 }
41434417
41444418 struct VirtualMachine vm;
4419#ifndef NDEBUG
4420 memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version
4421#endif
41454422 vm.stack = arena_alloc(sizeof(uint64_t) * 10000000),
41464423 vm.mod_ptr = mod.ptr;
41474424 vm.opcodes = arena_alloc(2000000);
......@@ -4154,7 +4431,7 @@ int main(int argc, char **argv) {
41544431 vm.memory_len = memory_len;
41554432 vm.imports = imports;
41564433 vm.imports_len = imports_len;
4157 vm.args = argv + vm_argv_start;
4434 vm.args = new_argv;
41584435 vm.table = table;
41594436
41604437 {
......@@ -4171,18 +4448,19 @@ int main(int argc, char **argv) {
41714448
41724449 struct TypeInfo *type_info = &vm.types[func->type_idx];
41734450 func->locals_count = 0;
4174 func->local_types = arena_alloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32));
4451 func->local_types = malloc(sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32));
41754452 func->local_types[0] = type_info->param_types;
41764453
41774454 for (uint32_t local_sets_count = read32_uleb128(mod.ptr, &code_i);
4178 local_sets_count > 0; local_sets_count -= 1) {
4455 local_sets_count > 0; local_sets_count -= 1)
4456 {
41794457 uint32_t set_count = read32_uleb128(mod.ptr, &code_i);
41804458 int64_t local_type = read64_ileb128(mod.ptr, &code_i);
41814459
41824460 uint32_t i = type_info->param_count + func->locals_count;
41834461 func->locals_count += set_count;
41844462 if ((type_info->param_count + func->locals_count + 31) / 32 > (i + 31) / 32)
4185 func->local_types = arena_realloc(func->local_types, sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32));
4463 func->local_types = realloc(func->local_types, sizeof(uint32_t) * ((type_info->param_count + func->locals_count + 31) / 32));
41864464 for (; i < type_info->param_count + func->locals_count; i += 1)
41874465 switch (local_type) {
41884466 case -1: case -3: bs_unset(func->local_types, i); break;
......@@ -4191,26 +4469,11 @@ int main(int argc, char **argv) {
41914469 }
41924470 }
41934471
4472 //fprintf(stderr, "set up func %u with pc %u:%u\n", func->type_idx, pc.opcode, pc.operand);
41944473 func->entry_pc = pc;
41954474 vm_decodeCode(&vm, func, &code_i, &pc);
41964475 if (code_i != code_begin + size) panic("bad code size");
41974476 }
4198
4199 uint64_t opcode_counts[0x100];
4200 memset(opcode_counts, 0, 0x100);
4201 uint64_t prefixed_opcode_counts[0x100];
4202 memset(prefixed_opcode_counts, 0, 0x100);
4203 bool is_prefixed = false;
4204 for (uint32_t opcode_i = 0; opcode_i < pc.opcode; opcode_i += 1) {
4205 uint8_t opcode = vm.opcodes[opcode_i];
4206 if (!is_prefixed) {
4207 opcode_counts[opcode] += 1;
4208 is_prefixed = opcode == WasmOp_prefixed;
4209 } else {
4210 prefixed_opcode_counts[opcode] += 1;
4211 is_prefixed = false;
4212 }
4213 }
42144477 }
42154478
42164479 vm_call(&vm, start_fn_idx);