| ... | @@ -10,11 +10,16 @@ | ... | @@ -10,11 +10,16 @@ |
| 10 | #include <stdlib.h> | 10 | #include <stdlib.h> |
| 11 | #include <string.h> | 11 | #include <string.h> |
| 12 | | 12 | |
| | 13 | #include <fcntl.h> |
| 13 | #include <sys/mman.h> | 14 | #include <sys/mman.h> |
| 14 | #include <sys/stat.h> | 15 | #include <sys/stat.h> |
| 15 | #include <fcntl.h> | 16 | #include <time.h> |
| 16 | #include <unistd.h> | 17 | #include <unistd.h> |
| 17 | | 18 | |
| | 19 | #ifdef __linux__ |
| | 20 | #include <sys/random.h> |
| | 21 | #endif |
| | 22 | |
| 18 | enum wasi_errno_t { | 23 | enum wasi_errno_t { |
| 19 | WASI_ESUCCESS = 0, | 24 | WASI_ESUCCESS = 0, |
| 20 | WASI_E2BIG = 1, | 25 | WASI_E2BIG = 1, |
| ... | @@ -131,15 +136,12 @@ static uint64_t rotr64(uint64_t n, unsigned c) { | ... | @@ -131,15 +136,12 @@ static uint64_t rotr64(uint64_t n, unsigned c) { |
| 131 | static void *arena_alloc(size_t n) { | 136 | static void *arena_alloc(size_t n) { |
| 132 | void *ptr = malloc(n); | 137 | void *ptr = malloc(n); |
| 133 | if (!ptr) panic("out of memory"); | 138 | if (!ptr) panic("out of memory"); |
| | 139 | #ifndef NDEBUG |
| | 140 | memset(ptr, 0xaa, n); // to match the zig version |
| | 141 | #endif |
| 134 | return ptr; | 142 | return ptr; |
| 135 | } | 143 | } |
| 136 | | 144 | |
| 137 | static 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 | | | |
| 143 | static int err_wrap(const char *prefix, int rc) { | 145 | static int err_wrap(const char *prefix, int rc) { |
| 144 | if (rc == -1) { | 146 | if (rc == -1) { |
| 145 | perror(prefix); | 147 | perror(prefix); |
| ... | @@ -152,7 +154,7 @@ static bool bs_isSet(const uint32_t *bitset, uint32_t index) { | ... | @@ -152,7 +154,7 @@ static bool bs_isSet(const uint32_t *bitset, uint32_t index) { |
| 152 | return (bitset[index >> 5] >> (index & 0x1f)) & 1; | 154 | return (bitset[index >> 5] >> (index & 0x1f)) & 1; |
| 153 | } | 155 | } |
| 154 | static void bs_set(uint32_t *bitset, uint32_t index) { | 156 | static 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)); |
| 156 | } | 158 | } |
| 157 | static void bs_unset(uint32_t *bitset, uint32_t index) { | 159 | static void bs_unset(uint32_t *bitset, uint32_t index) { |
| 158 | bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f)); | 160 | bitset[index >> 5] &= ~((uint32_t)1 << (index & 0x1f)); |
| ... | @@ -213,7 +215,7 @@ static const struct Preopen *find_preopen(int32_t wasi_fd) { | ... | @@ -213,7 +215,7 @@ static const struct Preopen *find_preopen(int32_t wasi_fd) { |
| 213 | return NULL; | 215 | return NULL; |
| 214 | } | 216 | } |
| 215 | | 217 | |
| 216 | static const size_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB | 218 | static const uint32_t max_memory = 2ul * 1024ul * 1024ul * 1024ul; // 2 GiB |
| 217 | | 219 | |
| 218 | static uint16_t read_u16_le(const char *ptr) { | 220 | static uint16_t read_u16_le(const char *ptr) { |
| 219 | const uint8_t *u8_ptr = (const uint8_t *)ptr; | 221 | const uint8_t *u8_ptr = (const uint8_t *)ptr; |
| ... | @@ -655,6 +657,7 @@ struct VirtualMachine { | ... | @@ -655,6 +657,7 @@ struct VirtualMachine { |
| 655 | /// Points to one after the last stack item. | 657 | /// Points to one after the last stack item. |
| 656 | uint32_t stack_top; | 658 | uint32_t stack_top; |
| 657 | struct ProgramCounter pc; | 659 | struct ProgramCounter pc; |
| | 660 | /// Actual memory usage of the WASI code. The capacity is max_memory. |
| 658 | uint32_t memory_len; | 661 | uint32_t memory_len; |
| 659 | const char *mod_ptr; | 662 | const char *mod_ptr; |
| 660 | uint8_t *opcodes; | 663 | uint8_t *opcodes; |
| ... | @@ -666,7 +669,7 @@ struct VirtualMachine { | ... | @@ -666,7 +669,7 @@ struct VirtualMachine { |
| 666 | char *memory; | 669 | char *memory; |
| 667 | struct Import *imports; | 670 | struct Import *imports; |
| 668 | uint32_t imports_len; | 671 | uint32_t imports_len; |
| 669 | char **args; | 672 | const char **args; |
| 670 | uint32_t *table; | 673 | uint32_t *table; |
| 671 | }; | 674 | }; |
| 672 | | 675 | |
| ... | @@ -678,22 +681,156 @@ static int to_host_fd(int32_t wasi_fd) { | ... | @@ -678,22 +681,156 @@ static int to_host_fd(int32_t wasi_fd) { |
| 678 | | 681 | |
| 679 | static enum wasi_errno_t to_wasi_err(int err) { | 682 | static enum wasi_errno_t to_wasi_err(int err) { |
| 680 | switch (err) { | 683 | switch (err) { |
| | 684 | case E2BIG: return WASI_E2BIG; |
| 681 | case EACCES: return WASI_EACCES; | 685 | 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; |
| 682 | case EDQUOT: return WASI_EDQUOT; | 702 | case EDQUOT: return WASI_EDQUOT; |
| 683 | case EIO: return WASI_EIO; | 703 | case EEXIST: return WASI_EEXIST; |
| | 704 | case EFAULT: return WASI_EFAULT; |
| 684 | case EFBIG: return WASI_EFBIG; | 705 | 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; |
| 685 | case ENOSPC: return WASI_ENOSPC; | 734 | 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; |
| 686 | case EPIPE: return WASI_EPIPE; | 747 | case EPIPE: return WASI_EPIPE; |
| 687 | case EBADF: return WASI_EBADF; | 748 | case EPROTO: return WASI_EPROTO; |
| 688 | case ENOMEM: return WASI_ENOMEM; | 749 | case EPROTONOSUPPORT: return WASI_EPROTONOSUPPORT; |
| 689 | case ENOENT: return WASI_ENOENT; | 750 | case EPROTOTYPE: return WASI_EPROTOTYPE; |
| 690 | case EEXIST: return WASI_EEXIST; | 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; |
| 691 | default: | 759 | default: |
| 692 | fprintf(stderr, "unexpected errno: %s\n", strerror(err)); | 760 | fprintf(stderr, "unexpected errno: %s\n", strerror(err)); |
| 693 | abort(); | 761 | abort(); |
| 694 | }; | 762 | }; |
| 695 | } | 763 | } |
| 696 | | 764 | |
| | 765 | enum 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 | |
| | 776 | static const uint16_t WASI_O_CREAT = 0x0001; |
| | 777 | static const uint16_t WASI_O_DIRECTORY = 0x0002; |
| | 778 | static const uint16_t WASI_O_EXCL = 0x0004; |
| | 779 | static const uint16_t WASI_O_TRUNC = 0x0008; |
| | 780 | |
| | 781 | static const uint16_t WASI_FDFLAG_APPEND = 0x0001; |
| | 782 | static const uint16_t WASI_FDFLAG_DSYNC = 0x0002; |
| | 783 | static const uint16_t WASI_FDFLAG_NONBLOCK = 0x0004; |
| | 784 | static const uint16_t WASI_FDFLAG_SYNC = 0x0010; |
| | 785 | |
| | 786 | static const uint64_t WASI_RIGHT_FD_READ = 0x0000000000000002ull; |
| | 787 | static const uint64_t WASI_RIGHT_FD_WRITE = 0x0000000000000040ull; |
| | 788 | |
| | 789 | static 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 | |
| | 806 | static 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 | /// }; |
| | 820 | static 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 | |
| 697 | /// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; | 834 | /// fn args_sizes_get(argc: *usize, argv_buf_size: *usize) errno_t; |
| 698 | static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, | 835 | static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, |
| 699 | uint32_t argc, uint32_t argv_buf_size) | 836 | uint32_t argc, uint32_t argv_buf_size) |
| ... | @@ -713,17 +850,19 @@ static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, | ... | @@ -713,17 +850,19 @@ static enum wasi_errno_t wasi_args_sizes_get(struct VirtualMachine *vm, |
| 713 | static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, | 850 | static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, |
| 714 | uint32_t argv, uint32_t argv_buf) | 851 | uint32_t argv, uint32_t argv_buf) |
| 715 | { | 852 | { |
| 716 | panic("TODO implement wasi_args_get"); | 853 | uint32_t argv_buf_i = 0; |
| 717 | //var argv_buf_i: usize = 0; | 854 | uint32_t arg_i = 0; |
| 718 | //for (vm->args) |arg, arg_i| { | 855 | for (;; arg_i += 1) { |
| 719 | // // Write the arg to the buffer. | 856 | const char *arg = vm->args[arg_i]; |
| 720 | // const argv_ptr = argv_buf + argv_buf_i; | 857 | if (!arg) break; |
| 721 | // const arg_len = mem.span(arg).len + 1; | 858 | // Write the arg to the buffer. |
| 722 | // mem.copy(u8, vm->memory[argv_buf + argv_buf_i ..], arg[0..arg_len]); | 859 | uint32_t argv_ptr = argv_buf + argv_buf_i; |
| 723 | // argv_buf_i += arg_len; | 860 | uint32_t arg_len = strlen(arg) + 1; |
| 724 | | 861 | memcpy(vm->memory + argv_buf + argv_buf_i, arg, arg_len); |
| 725 | // write_u32_le(vm->memory[argv + 4 * arg_i ..][0..4], @intCast(u32, argv_ptr)); | 862 | argv_buf_i += arg_len; |
| 726 | //} | 863 | |
| | 864 | write_u32_le(vm->memory + argv + 4 * arg_i , argv_ptr); |
| | 865 | } |
| 727 | return WASI_ESUCCESS; | 866 | return WASI_ESUCCESS; |
| 728 | } | 867 | } |
| 729 | | 868 | |
| ... | @@ -731,9 +870,15 @@ static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, | ... | @@ -731,9 +870,15 @@ static enum wasi_errno_t wasi_args_get(struct VirtualMachine *vm, |
| 731 | static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, | 870 | static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, |
| 732 | uint32_t buf, uint32_t buf_len) | 871 | uint32_t buf, uint32_t buf_len) |
| 733 | { | 872 | { |
| 734 | panic("TODO implement wasi_random_get"); | 873 | #ifdef __linux__ |
| 735 | //const host_buf = vm->memory[buf..][0..buf_len]; | 874 | if (getrandom(vm->memory + buf, buf_len, 0) != buf_len) { |
| 736 | //std.crypto.random.bytes(host_buf); | 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 |
| 737 | return WASI_ESUCCESS; | 882 | return WASI_ESUCCESS; |
| 738 | } | 883 | } |
| 739 | | 884 | |
| ... | @@ -745,10 +890,10 @@ static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, | ... | @@ -745,10 +890,10 @@ static enum wasi_errno_t wasi_random_get(struct VirtualMachine *vm, |
| 745 | static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, | 890 | static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, |
| 746 | int32_t fd, uint32_t buf) | 891 | int32_t fd, uint32_t buf) |
| 747 | { | 892 | { |
| 748 | panic("TODO implement wasi_fd_prestat_get"); | 893 | const struct Preopen *preopen = find_preopen(fd); |
| 749 | //const preopen = findPreopen(fd) orelse return .BADF; | 894 | if (!preopen) return WASI_EBADF; |
| 750 | //write_u32_le(vm->memory[buf + 0 ..][0..4], 0); | 895 | write_u32_le(vm->memory + buf + 0, 0); |
| 751 | //write_u32_le(vm->memory[buf + 4 ..][0..4], @intCast(u32, preopen.name.len)); | 896 | write_u32_le(vm->memory + buf + 4, preopen->name_len); |
| 752 | return WASI_ESUCCESS; | 897 | return WASI_ESUCCESS; |
| 753 | } | 898 | } |
| 754 | | 899 | |
| ... | @@ -756,19 +901,18 @@ static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, | ... | @@ -756,19 +901,18 @@ static enum wasi_errno_t wasi_fd_prestat_get(struct VirtualMachine *vm, |
| 756 | static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm, | 901 | static enum wasi_errno_t wasi_fd_prestat_dir_name(struct VirtualMachine *vm, |
| 757 | int32_t fd, uint32_t path, uint32_t path_len) | 902 | int32_t fd, uint32_t path, uint32_t path_len) |
| 758 | { | 903 | { |
| 759 | panic("TODO implement wasi_fd_prestat_dir_name"); | 904 | const struct Preopen *preopen = find_preopen(fd); |
| 760 | //const preopen = findPreopen(fd) orelse return .BADF; | 905 | if (!preopen) return WASI_EBADF; |
| 761 | //assert(path_len == preopen.name.len); | 906 | if (path_len != preopen->name_len) |
| 762 | //mem.copy(u8, vm->memory[path..], preopen.name); | 907 | panic("wasi_fd_prestat_dir_name expects correct name_len"); |
| | 908 | memcpy(vm->memory + path, preopen->name, path_len); |
| 763 | return WASI_ESUCCESS; | 909 | return WASI_ESUCCESS; |
| 764 | } | 910 | } |
| 765 | | 911 | |
| 766 | /// extern fn fd_close(fd: fd_t) errno_t; | 912 | /// extern fn fd_close(fd: fd_t) errno_t; |
| 767 | static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) { | 913 | static enum wasi_errno_t wasi_fd_close(struct VirtualMachine *vm, int32_t fd) { |
| 768 | panic("TODO implement wasi_fd_close"); | 914 | int host_fd = to_host_fd(fd); |
| 769 | //_ = vm; | 915 | close(host_fd); |
| 770 | //const host_fd = toHostFd(fd); | | |
| 771 | //os.close(host_fd); | | |
| 772 | return WASI_ESUCCESS; | 916 | return WASI_ESUCCESS; |
| 773 | } | 917 | } |
| 774 | | 918 | |
| ... | @@ -779,20 +923,18 @@ static enum wasi_errno_t wasi_fd_read( | ... | @@ -779,20 +923,18 @@ static enum wasi_errno_t wasi_fd_read( |
| 779 | uint32_t iovs_len, // usize | 923 | uint32_t iovs_len, // usize |
| 780 | uint32_t nread // *usize | 924 | uint32_t nread // *usize |
| 781 | ) { | 925 | ) { |
| 782 | panic("TODO implement wasi_fd_read"); | 926 | int host_fd = to_host_fd(fd); |
| 783 | //const host_fd = toHostFd(fd); | 927 | uint32_t i = 0; |
| 784 | //var i: u32 = 0; | 928 | size_t total_read = 0; |
| 785 | //var total_read: usize = 0; | 929 | for (; i < iovs_len; i += 1) { |
| 786 | //while (i < iovs_len) : (i += 1) { | 930 | uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); |
| 787 | // 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); |
| 788 | // uint32_t len = read_u32_le(vm->memory + iovs + i * 8 + 4); | 932 | ssize_t amt_read = read(host_fd, vm->memory + ptr, len); |
| 789 | // const buf = vm->memory[ptr..][0..len]; | 933 | if (amt_read < 0) return to_wasi_err(errno); |
| 790 | // const read = os.read(host_fd, buf) catch |err| return toWasiError(err); | 934 | total_read += amt_read; |
| 791 | // trace_log.debug("read {d} bytes out of {d}", .{ read, buf.len }); | 935 | if (amt_read != len) break; |
| 792 | // total_read += read; | 936 | } |
| 793 | // if (read != buf.len) break; | 937 | write_u32_le(vm->memory + nread, total_read); |
| 794 | //} | | |
| 795 | //write_u32_le(vm->memory[nread..][0..4], @intCast(u32, total_read)); | | |
| 796 | return WASI_ESUCCESS; | 938 | return WASI_ESUCCESS; |
| 797 | } | 939 | } |
| 798 | | 940 | |
| ... | @@ -826,19 +968,18 @@ static enum wasi_errno_t wasi_fd_pwrite( | ... | @@ -826,19 +968,18 @@ static enum wasi_errno_t wasi_fd_pwrite( |
| 826 | uint64_t offset, // wasi.filesize_t, | 968 | uint64_t offset, // wasi.filesize_t, |
| 827 | uint32_t written_ptr // *usize | 969 | uint32_t written_ptr // *usize |
| 828 | ) { | 970 | ) { |
| 829 | panic("TODO implement wasi_fd_pwrite"); | 971 | int host_fd = to_host_fd(fd); |
| 830 | //const host_fd = toHostFd(fd); | 972 | uint32_t i = 0; |
| 831 | //var i: u32 = 0; | 973 | size_t written = 0; |
| 832 | //var written: usize = 0; | 974 | for (; i < iovs_len; i += 1) { |
| 833 | //while (i < iovs_len) : (i += 1) { | 975 | uint32_t ptr = read_u32_le(vm->memory + iovs + i * 8 + 0); |
| 834 | // 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); |
| 835 | // 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); |
| 836 | // const buf = vm->memory[ptr..][0..len]; | 978 | if (w < 0) return to_wasi_err(errno); |
| 837 | // const w = os.pwrite(host_fd, buf, offset + written) catch |err| return toWasiError(err); | 979 | written += w; |
| 838 | // written += w; | 980 | if (w != len) break; |
| 839 | // if (w != buf.len) break; | 981 | } |
| 840 | //} | 982 | write_u32_le(vm->memory + written_ptr, written); |
| 841 | //write_u32_le(vm->memory[written_ptr..][0..4], @intCast(u32, written)); | | |
| 842 | return WASI_ESUCCESS; | 983 | return WASI_ESUCCESS; |
| 843 | } | 984 | } |
| 844 | | 985 | |
| ... | @@ -865,29 +1006,34 @@ static enum wasi_errno_t wasi_path_open( | ... | @@ -865,29 +1006,34 @@ static enum wasi_errno_t wasi_path_open( |
| 865 | uint16_t fs_flags, // wasi.fdflags_t, | 1006 | uint16_t fs_flags, // wasi.fdflags_t, |
| 866 | uint32_t fd | 1007 | uint32_t fd |
| 867 | ) { | 1008 | ) { |
| 868 | panic("TODO implement wasi_path_open"); | 1009 | char sub_path[PATH_MAX]; |
| 869 | //const sub_path = vm->memory[path..][0..path_len]; | 1010 | memcpy(sub_path, vm->memory + path, path_len); |
| 870 | //const host_fd = toHostFd(dirfd); | 1011 | sub_path[path_len] = 0; |
| 871 | //var flags: u32 = @as(u32, if (oflags & wasi.O.CREAT != 0) os.O.CREAT else 0) | | 1012 | |
| 872 | // @as(u32, if (oflags & wasi.O.DIRECTORY != 0) os.O.DIRECTORY else 0) | | 1013 | int host_fd = to_host_fd(dirfd); |
| 873 | // @as(u32, if (oflags & wasi.O.EXCL != 0) os.O.EXCL else 0) | | 1014 | uint32_t flags = |
| 874 | // @as(u32, if (oflags & wasi.O.TRUNC != 0) os.O.TRUNC else 0) | | 1015 | (((oflags & WASI_O_CREAT) != 0) ? O_CREAT : 0) | |
| 875 | // @as(u32, if (fs_flags & wasi.FDFLAG.APPEND != 0) os.O.APPEND else 0) | | 1016 | (((oflags & WASI_O_DIRECTORY) != 0) ? O_DIRECTORY : 0) | |
| 876 | // @as(u32, if (fs_flags & wasi.FDFLAG.DSYNC != 0) os.O.DSYNC else 0) | | 1017 | (((oflags & WASI_O_EXCL) != 0) ? O_EXCL : 0) | |
| 877 | // @as(u32, if (fs_flags & wasi.FDFLAG.NONBLOCK != 0) os.O.NONBLOCK else 0) | | 1018 | (((oflags & WASI_O_TRUNC) != 0) ? O_TRUNC : 0) | |
| 878 | // @as(u32, if (fs_flags & wasi.FDFLAG.SYNC != 0) os.O.SYNC else 0); | 1019 | (((fs_flags & WASI_FDFLAG_APPEND) != 0) ? O_APPEND : 0) | |
| 879 | //if ((fs_rights_base & wasi.RIGHT.FD_READ != 0) and | 1020 | (((fs_flags & WASI_FDFLAG_DSYNC) != 0) ? O_DSYNC : 0) | |
| 880 | // (fs_rights_base & wasi.RIGHT.FD_WRITE != 0)) | 1021 | (((fs_flags & WASI_FDFLAG_NONBLOCK) != 0) ? O_NONBLOCK : 0) | |
| 881 | //{ | 1022 | (((fs_flags & WASI_FDFLAG_SYNC) != 0) ? O_SYNC : 0); |
| 882 | // flags |= os.O.RDWR; | 1023 | |
| 883 | //} else if (fs_rights_base & wasi.RIGHT.FD_WRITE != 0) { | 1024 | if (((fs_rights_base & WASI_RIGHT_FD_READ) != 0) && |
| 884 | // flags |= os.O.WRONLY; | 1025 | ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0)) |
| 885 | //} else if (fs_rights_base & wasi.RIGHT.FD_READ != 0) { | 1026 | { |
| 886 | // flags |= os.O.RDONLY; // no-op because O_RDONLY is 0 | 1027 | flags |= O_RDWR; |
| 887 | //} | 1028 | } else if ((fs_rights_base & WASI_RIGHT_FD_WRITE) != 0) { |
| 888 | //const mode = 0o644; | 1029 | flags |= O_WRONLY; |
| 889 | //const res_fd = os.openat(host_fd, sub_path, flags, mode) catch |err| return toWasiError(err); | 1030 | } else if ((fs_rights_base & WASI_RIGHT_FD_READ) != 0) { |
| 890 | //mem.writeIntLittle(i32, vm->memory[fd..][0..4], res_fd); | 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); |
| 891 | return WASI_ESUCCESS; | 1037 | return WASI_ESUCCESS; |
| 892 | } | 1038 | } |
| 893 | | 1039 | |
| ... | @@ -899,23 +1045,26 @@ static enum wasi_errno_t wasi_path_filestat_get( | ... | @@ -899,23 +1045,26 @@ static enum wasi_errno_t wasi_path_filestat_get( |
| 899 | uint32_t path_len, // usize | 1045 | uint32_t path_len, // usize |
| 900 | uint32_t buf // *filestat_t | 1046 | uint32_t buf // *filestat_t |
| 901 | ) { | 1047 | ) { |
| 902 | panic("TODO implement wasi_path_filestat_get"); | 1048 | char sub_path[PATH_MAX]; |
| 903 | //const sub_path = vm->memory[path..][0..path_len]; | 1049 | memcpy(sub_path, vm->memory + path, path_len); |
| 904 | //const host_fd = toHostFd(fd); | 1050 | sub_path[path_len] = 0; |
| 905 | //const dir: fs.Dir = .{ .fd = host_fd }; | 1051 | |
| 906 | //const stat = dir.statFile(sub_path) catch |err| return toWasiError(err); | 1052 | int host_fd = to_host_fd(fd); |
| 907 | //return finishWasiStat(vm, buf, stat); | 1053 | struct stat st; |
| 908 | return WASI_ESUCCESS; | 1054 | if (fstatat(host_fd, sub_path, &st, 0) == -1) return to_wasi_err(errno); |
| | 1055 | return finish_wasi_stat(vm, buf, st); |
| 909 | } | 1056 | } |
| 910 | | 1057 | |
| 911 | /// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; | 1058 | /// extern fn path_create_directory(fd: fd_t, path: [*]const u8, path_len: usize) errno_t; |
| 912 | static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, int32_t fd, uint32_t path, uint32_t path_len) { | 1059 | static enum wasi_errno_t wasi_path_create_directory(struct VirtualMachine *vm, |
| 913 | panic("TODO implement wasi_path_create_directory"); | 1060 | int32_t wasi_fd, uint32_t path, uint32_t path_len) |
| 914 | //const sub_path = vm->memory[path..][0..path_len]; | 1061 | { |
| 915 | //trace_log.debug("wasi_path_create_directory fd={d} path={s}", .{ fd, sub_path }); | 1062 | char sub_path[PATH_MAX]; |
| 916 | //const host_fd = toHostFd(fd); | 1063 | memcpy(sub_path, vm->memory + path, path_len); |
| 917 | //const dir: fs.Dir = .{ .fd = host_fd }; | 1064 | sub_path[path_len] = 0; |
| 918 | //dir.makeDir(sub_path) catch |err| return toWasiError(err); | 1065 | |
| | 1066 | int host_fd = to_host_fd(wasi_fd); |
| | 1067 | if (mkdirat(host_fd, sub_path, 0777) == -1) return to_wasi_err(errno); |
| 919 | return WASI_ESUCCESS; | 1068 | return WASI_ESUCCESS; |
| 920 | } | 1069 | } |
| 921 | | 1070 | |
| ... | @@ -928,35 +1077,33 @@ static enum wasi_errno_t wasi_path_rename( | ... | @@ -928,35 +1077,33 @@ static enum wasi_errno_t wasi_path_rename( |
| 928 | uint32_t new_path_ptr, // [*]const u8 | 1077 | uint32_t new_path_ptr, // [*]const u8 |
| 929 | uint32_t new_path_len // usize | 1078 | uint32_t new_path_len // usize |
| 930 | ) { | 1079 | ) { |
| 931 | panic("TODO implement wasi_path_rename"); | 1080 | char old_path[PATH_MAX]; |
| 932 | //const old_path = vm->memory[old_path_ptr..][0..old_path_len]; | 1081 | memcpy(old_path, vm->memory + old_path_ptr, old_path_len); |
| 933 | //const new_path = vm->memory[new_path_ptr..][0..new_path_len]; | 1082 | old_path[old_path_len] = 0; |
| 934 | //trace_log.debug("wasi_path_rename old_fd={d} old_path={s} new_fd={d} new_path={s}", .{ | 1083 | |
| 935 | // old_fd, old_path, new_fd, new_path, | 1084 | char new_path[PATH_MAX]; |
| 936 | //}); | 1085 | memcpy(new_path, vm->memory + new_path_ptr, new_path_len); |
| 937 | //const old_host_fd = toHostFd(old_fd); | 1086 | new_path[new_path_len] = 0; |
| 938 | //const new_host_fd = toHostFd(new_fd); | 1087 | |
| 939 | //os.renameat(old_host_fd, old_path, new_host_fd, new_path) catch |err| return toWasiError(err); | 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); |
| 940 | return WASI_ESUCCESS; | 1091 | return WASI_ESUCCESS; |
| 941 | } | 1092 | } |
| 942 | | 1093 | |
| 943 | /// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; | 1094 | /// extern fn fd_filestat_get(fd: fd_t, buf: *filestat_t) errno_t; |
| 944 | static enum wasi_errno_t wasi_fd_filestat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { | 1095 | static 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"); | 1096 | int host_fd = to_host_fd(fd); |
| 946 | //const host_fd = toHostFd(fd); | 1097 | struct stat st; |
| 947 | //const file = fs.File{ .handle = host_fd }; | 1098 | if (fstat(host_fd, &st) == -1) return to_wasi_err(errno); |
| 948 | //const stat = file.stat() catch |err| return toWasiError(err); | 1099 | return finish_wasi_stat(vm, buf, st); |
| 949 | //return finishWasiStat(vm, buf, stat); | | |
| 950 | return WASI_ESUCCESS; | | |
| 951 | } | 1100 | } |
| 952 | | 1101 | |
| 953 | static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, | 1102 | static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, |
| 954 | int32_t fd, uint64_t size) | 1103 | int32_t fd, uint64_t size) |
| 955 | { | 1104 | { |
| 956 | panic("TODO implement wasi_fd_filestat_set_size"); | 1105 | int host_fd = to_host_fd(fd); |
| 957 | //_ = vm; | 1106 | if (ftruncate(host_fd, size) == -1) return to_wasi_err(errno); |
| 958 | //const host_fd = toHostFd(fd); | | |
| 959 | //os.ftruncate(host_fd, size) catch |err| return toWasiError(err); | | |
| 960 | return WASI_ESUCCESS; | 1107 | return WASI_ESUCCESS; |
| 961 | } | 1108 | } |
| 962 | | 1109 | |
| ... | @@ -968,14 +1115,13 @@ static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, | ... | @@ -968,14 +1115,13 @@ static enum wasi_errno_t wasi_fd_filestat_set_size( struct VirtualMachine *vm, |
| 968 | /// fs_rights_inheriting: rights_t, u64 | 1115 | /// fs_rights_inheriting: rights_t, u64 |
| 969 | /// }; | 1116 | /// }; |
| 970 | static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t fd, uint32_t buf) { | 1117 | static 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"); | 1118 | int host_fd = to_host_fd(fd); |
| 972 | //const host_fd = toHostFd(fd); | 1119 | struct stat st; |
| 973 | //const file = fs.File{ .handle = host_fd }; | 1120 | if (fstat(host_fd, &st) == -1) return to_wasi_err(errno); |
| 974 | //const stat = file.stat() catch |err| return toWasiError(err); | 1121 | write_u16_le(vm->memory + buf + 0x00, to_wasi_filetype(st.st_mode)); |
| 975 | //mem.writeIntLittle(u16, vm->memory[buf + 0x00 ..][0..2], @enumToInt(toWasiFileType(stat.kind))); | 1122 | write_u16_le(vm->memory + buf + 0x02, 0); // flags |
| 976 | //mem.writeIntLittle(u16, vm->memory[buf + 0x02 ..][0..2], 0); // flags | 1123 | write_u64_le(vm->memory + buf + 0x08, UINT64_MAX); // rights_base |
| 977 | //mem.writeIntLittle(u64, vm->memory[buf + 0x08 ..][0..8], math.maxInt(u64)); // rights_base | 1124 | write_u64_le(vm->memory + buf + 0x10, UINT64_MAX); // rights_inheriting |
| 978 | //mem.writeIntLittle(u64, vm->memory[buf + 0x10 ..][0..8], math.maxInt(u64)); // rights_inheriting | | |
| 979 | return WASI_ESUCCESS; | 1125 | return WASI_ESUCCESS; |
| 980 | } | 1126 | } |
| 981 | | 1127 | |
| ... | @@ -983,31 +1129,24 @@ static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t f | ... | @@ -983,31 +1129,24 @@ static enum wasi_errno_t wasi_fd_fdstat_get(struct VirtualMachine *vm, int32_t f |
| 983 | static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, | 1129 | static enum wasi_errno_t wasi_clock_time_get(struct VirtualMachine *vm, |
| 984 | uint32_t clock_id, uint64_t precision, uint32_t timestamp) | 1130 | uint32_t clock_id, uint64_t precision, uint32_t timestamp) |
| 985 | { | 1131 | { |
| 986 | panic("TODO implement wasi_clock_time_get"); | 1132 | if (clock_id != 1) panic("expected wasi_clock_time_get to use CLOCK_MONOTONIC"); |
| 987 | ////const host_clock_id = toHostClockId(clock_id); | 1133 | struct timespec ts; |
| 988 | //_ = precision; | 1134 | if (clock_gettime(CLOCK_MONOTONIC, &ts) == -1) return to_wasi_err(errno); |
| 989 | //_ = clock_id; | 1135 | uint64_t wasi_ts = to_wasi_timestamp(ts); |
| 990 | //const wasi_ts = toWasiTimestamp(std.time.nanoTimestamp()); | 1136 | write_u64_le(vm->memory + timestamp, wasi_ts); |
| 991 | //mem.writeIntLittle(u64, vm->memory[timestamp..][0..8], wasi_ts); | | |
| 992 | return WASI_ESUCCESS; | 1137 | return WASI_ESUCCESS; |
| 993 | } | 1138 | } |
| 994 | | 1139 | |
| 995 | ///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; | 1140 | ///pub extern "wasi_snapshot_preview1" fn debug(string: [*:0]const u8, x: u64) void; |
| 996 | void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { | 1141 | void wasi_debug(struct VirtualMachine *vm, uint32_t text, uint64_t n) { |
| 997 | panic("TODO implement wasi_debug"); | 1142 | fprintf(stderr, "wasi_debug: '%s' number=%lu %lx\n", vm->memory + text, n, n); |
| 998 | //const s = mem.sliceTo(vm->memory[text..], 0); | | |
| 999 | //trace_log.debug("wasi_debug: '{s}' number={d} {x}", .{ s, n, n }); | | |
| 1000 | } | 1143 | } |
| 1001 | | 1144 | |
| 1002 | /// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; | 1145 | /// pub extern "wasi_snapshot_preview1" fn debug_slice(ptr: [*]const u8, len: usize) void; |
| 1003 | void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) { | 1146 | void wasi_debug_slice(struct VirtualMachine *vm, uint32_t ptr, uint32_t len) { |
| 1004 | panic("TODO implement wasi_debug_slice"); | 1147 | fprintf(stderr, "wasi_debug_slice: '%.*s'\n", len, vm->memory + ptr); |
| 1005 | //const s = vm->memory[ptr..][0..len]; | | |
| 1006 | //trace_log.debug("wasi_debug_slice: '{s}'", .{s}); | | |
| 1007 | } | 1148 | } |
| 1008 | | 1149 | |
| 1009 | | | |
| 1010 | | | |
| 1011 | struct Label { | 1150 | struct Label { |
| 1012 | enum WasmOp opcode; | 1151 | enum WasmOp opcode; |
| 1013 | uint32_t stack_depth; | 1152 | uint32_t stack_depth; |
| ... | @@ -1049,6 +1188,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1049,6 +1188,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1049 | static uint32_t stack_types[1 << (12 - 3)]; | 1188 | static uint32_t stack_types[1 << (12 - 3)]; |
| 1050 | | 1189 | |
| 1051 | static struct Label labels[1 << 9]; | 1190 | 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 |
| 1052 | uint32_t label_i = 0; | 1194 | uint32_t label_i = 0; |
| 1053 | labels[label_i].opcode = WasmOp_block; | 1195 | labels[label_i].opcode = WasmOp_block; |
| 1054 | labels[label_i].stack_depth = stack_depth; | 1196 | labels[label_i].stack_depth = stack_depth; |
| ... | @@ -1061,6 +1203,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1061,6 +1203,9 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1061 | enum WasmPrefixedOp prefixed_opcode; | 1203 | enum WasmPrefixedOp prefixed_opcode; |
| 1062 | if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i); | 1204 | if (opcode == WasmOp_prefixed) prefixed_opcode = read32_uleb128(mod_ptr, code_i); |
| 1063 | | 1205 | |
| | 1206 | //fprintf(stderr, "decodeCode opcode=0x%x pc=%u:%u\n", opcode, pc->opcode, pc->operand); |
| | 1207 | //struct ProgramCounter old_pc = *pc; |
| | 1208 | |
| 1064 | uint32_t initial_stack_depth = stack_depth; | 1209 | uint32_t initial_stack_depth = stack_depth; |
| 1065 | if (unreachable_depth == 0) { | 1210 | if (unreachable_depth == 0) { |
| 1066 | switch (opcode) { | 1211 | switch (opcode) { |
| ... | @@ -1549,11 +1694,16 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1549,11 +1694,16 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1549 | label->type_info.param_count = 0; | 1694 | label->type_info.param_count = 0; |
| 1550 | label->type_info.param_types = 0; | 1695 | label->type_info.param_types = 0; |
| 1551 | label->type_info.result_count = block_type != -0x40; | 1696 | label->type_info.result_count = block_type != -0x40; |
| 1552 | label->type_info.result_types = 0; | | |
| 1553 | switch (block_type) { | 1697 | switch (block_type) { |
| 1554 | case -0x40: break; | 1698 | case -0x40: |
| 1555 | case -1: case -3: bs_unset(&label->type_info.param_types, 0); break; | 1699 | case -1: |
| 1556 | case -2: case -4: bs_set(&label->type_info.param_types, 0); break; | 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; |
| 1557 | default: panic("unexpected param type"); | 1707 | default: panic("unexpected param type"); |
| 1558 | } | 1708 | } |
| 1559 | } else { | 1709 | } else { |
| ... | @@ -1584,7 +1734,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1584,7 +1734,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1584 | break; | 1734 | break; |
| 1585 | | 1735 | |
| 1586 | case WasmOp_else: | 1736 | case WasmOp_else: |
| 1587 | { | 1737 | if (unreachable_depth <= 1) { |
| 1588 | struct Label *label = &labels[label_i]; | 1738 | struct Label *label = &labels[label_i]; |
| 1589 | assert(label->opcode == WasmOp_if); | 1739 | assert(label->opcode == WasmOp_if); |
| 1590 | label->opcode = WasmOp_else; | 1740 | label->opcode = WasmOp_else; |
| ... | @@ -1596,9 +1746,12 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1596,9 +1746,12 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1596 | break; | 1746 | break; |
| 1597 | | 1747 | |
| 1598 | case 1: | 1748 | case 1: |
| 1599 | switch ((int)Label_operandType(label, 0)) { | 1749 | //fprintf(stderr, "label_i=%u operand_type=%d\n", |
| 1600 | case false: opcodes[pc->opcode] = Op_br_32; break; | 1750 | // label_i, Label_operandType(label, 0)); |
| 1601 | case true: opcodes[pc->opcode] = Op_br_64; break; | 1751 | if (Label_operandType(label, 0)) { |
| | 1752 | opcodes[pc->opcode] = Op_br_64; |
| | 1753 | } else { |
| | 1754 | opcodes[pc->opcode] = Op_br_32; |
| 1602 | } | 1755 | } |
| 1603 | break; | 1756 | break; |
| 1604 | | 1757 | |
| ... | @@ -1614,7 +1767,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1614,7 +1767,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1614 | operands[label->extra.else_ref + 0] = pc->opcode; | 1767 | operands[label->extra.else_ref + 0] = pc->opcode; |
| 1615 | operands[label->extra.else_ref + 1] = pc->operand; | 1768 | operands[label->extra.else_ref + 1] = pc->operand; |
| 1616 | stack_depth = label->stack_depth + label->type_info.param_count; | 1769 | stack_depth = label->stack_depth + label->type_info.param_count; |
| 1617 | }; | 1770 | } |
| 1618 | break; | 1771 | break; |
| 1619 | | 1772 | |
| 1620 | case WasmOp_end: | 1773 | case WasmOp_end: |
| ... | @@ -1705,7 +1858,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1705,7 +1858,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1705 | } | 1858 | } |
| 1706 | break; | 1859 | break; |
| 1707 | | 1860 | |
| 1708 | default: panic("unexpected opcode"); | 1861 | default: panic("unreachable"); |
| 1709 | } | 1862 | } |
| 1710 | pc->opcode += 1; | 1863 | pc->opcode += 1; |
| 1711 | operands[pc->operand + 0] = stack_depth - operand_count - label->stack_depth; | 1864 | 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 | ... | @@ -1748,11 +1901,6 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1748 | label->ref_list = pc->operand + 1; | 1901 | label->ref_list = pc->operand + 1; |
| 1749 | pc->operand += 3; | 1902 | pc->operand += 3; |
| 1750 | } | 1903 | } |
| 1751 | | | |
| 1752 | opcodes[pc->opcode] = opcode; | | |
| 1753 | pc->opcode += 1; | | |
| 1754 | operands[pc->operand] = labels_len; | | |
| 1755 | pc->operand += 1; | | |
| 1756 | } | 1904 | } |
| 1757 | break; | 1905 | break; |
| 1758 | | 1906 | |
| ... | @@ -1796,7 +1944,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -1796,7 +1944,7 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 1796 | break; | 1944 | break; |
| 1797 | | 1945 | |
| 1798 | case WasmOp_return: | 1946 | case WasmOp_return: |
| 1799 | { | 1947 | if (unreachable_depth <= 1) { |
| 1800 | uint32_t operand_count = Label_operandCount(&labels[0]); | 1948 | uint32_t operand_count = Label_operandCount(&labels[0]); |
| 1801 | switch (operand_count) { | 1949 | switch (operand_count) { |
| 1802 | case 0: | 1950 | case 0: |
| ... | @@ -2066,9 +2214,11 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -2066,9 +2214,11 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 2066 | break; | 2214 | break; |
| 2067 | | 2215 | |
| 2068 | default: | 2216 | default: |
| 2069 | opcodes[pc->opcode + 0] = Op_wasm; | 2217 | if (unreachable_depth == 0) { |
| 2070 | opcodes[pc->opcode + 1] = opcode; | 2218 | opcodes[pc->opcode + 0] = Op_wasm; |
| 2071 | pc->opcode += 2; | 2219 | opcodes[pc->opcode + 1] = opcode; |
| | 2220 | pc->opcode += 2; |
| | 2221 | } |
| 2072 | break; | 2222 | break; |
| 2073 | | 2223 | |
| 2074 | case WasmOp_prefixed: | 2224 | case WasmOp_prefixed: |
| ... | @@ -2125,6 +2275,13 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint | ... | @@ -2125,6 +2275,13 @@ static void vm_decodeCode(struct VirtualMachine *vm, struct Function *func, uint |
| 2125 | default: | 2275 | default: |
| 2126 | break; | 2276 | break; |
| 2127 | } | 2277 | } |
| | 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 | //} |
| 2128 | } | 2285 | } |
| 2129 | } | 2286 | } |
| 2130 | | 2287 | |
| ... | @@ -2184,7 +2341,7 @@ static float vm_pop_f32(struct VirtualMachine *vm) { | ... | @@ -2184,7 +2341,7 @@ static float vm_pop_f32(struct VirtualMachine *vm) { |
| 2184 | } | 2341 | } |
| 2185 | | 2342 | |
| 2186 | static double vm_pop_f64(struct VirtualMachine *vm) { | 2343 | static double vm_pop_f64(struct VirtualMachine *vm) { |
| 2187 | uint32_t integer = vm_pop_u64(vm); | 2344 | uint64_t integer = vm_pop_u64(vm); |
| 2188 | double result; | 2345 | double result; |
| 2189 | memcpy(&result, &integer, 8); | 2346 | memcpy(&result, &integer, 8); |
| 2190 | return result; | 2347 | return result; |
| ... | @@ -2251,7 +2408,7 @@ static void vm_callImport(struct VirtualMachine *vm, struct Import import) { | ... | @@ -2251,7 +2408,7 @@ static void vm_callImport(struct VirtualMachine *vm, struct Import import) { |
| 2251 | break; | 2408 | break; |
| 2252 | case ImpName_fd_readdir: | 2409 | case ImpName_fd_readdir: |
| 2253 | { | 2410 | { |
| 2254 | panic("TODO implement fd_readdir"); | 2411 | panic("unexpected call to fd_readdir"); |
| 2255 | } | 2412 | } |
| 2256 | break; | 2413 | break; |
| 2257 | case ImpName_fd_write: | 2414 | case ImpName_fd_write: |
| ... | @@ -2422,8 +2579,12 @@ static void vm_call(struct VirtualMachine *vm, uint32_t fn_id) { | ... | @@ -2422,8 +2579,12 @@ static void vm_call(struct VirtualMachine *vm, uint32_t fn_id) { |
| 2422 | uint32_t fn_idx = fn_id - vm->imports_len; | 2579 | uint32_t fn_idx = fn_id - vm->imports_len; |
| 2423 | struct Function *func = &vm->functions[fn_idx]; | 2580 | struct Function *func = &vm->functions[fn_idx]; |
| 2424 | | 2581 | |
| | 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 | |
| 2425 | // Push zeroed locals to stack | 2586 | // 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)); |
| 2427 | vm->stack_top += func->locals_count; | 2588 | vm->stack_top += func->locals_count; |
| 2428 | | 2589 | |
| 2429 | vm_push_u32(vm, vm->pc.opcode); | 2590 | vm_push_u32(vm, vm->pc.opcode); |
| ... | @@ -2504,6 +2665,10 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -2504,6 +2665,10 @@ static void vm_run(struct VirtualMachine *vm) { |
| 2504 | for (;;) { | 2665 | for (;;) { |
| 2505 | enum Op op = opcodes[pc->opcode]; | 2666 | enum Op op = opcodes[pc->opcode]; |
| 2506 | pc->opcode += 1; | 2667 | 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 | //} |
| 2507 | switch (op) { | 2672 | switch (op) { |
| 2508 | case Op_unreachable: | 2673 | case Op_unreachable: |
| 2509 | panic("unreachable reached"); | 2674 | panic("unreachable reached"); |
| ... | @@ -2738,6 +2903,7 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -2738,6 +2903,7 @@ static void vm_run(struct VirtualMachine *vm) { |
| 2738 | case Op_wasm: | 2903 | case Op_wasm: |
| 2739 | { | 2904 | { |
| 2740 | enum WasmOp wasm_op = opcodes[pc->opcode]; | 2905 | enum WasmOp wasm_op = opcodes[pc->opcode]; |
| | 2906 | //fprintf(stderr, "op2=%x\n", wasm_op); |
| 2741 | pc->opcode += 1; | 2907 | pc->opcode += 1; |
| 2742 | switch (wasm_op) { | 2908 | switch (wasm_op) { |
| 2743 | case WasmOp_unreachable: | 2909 | case WasmOp_unreachable: |
| ... | @@ -2820,7 +2986,7 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -2820,7 +2986,7 @@ static void vm_run(struct VirtualMachine *vm) { |
| 2820 | { | 2986 | { |
| 2821 | uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); | 2987 | uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); |
| 2822 | pc->operand += 1; | 2988 | pc->operand += 1; |
| 2823 | vm_push_u32(vm, vm->memory[offset]); | 2989 | vm_push_u32(vm, (uint8_t)vm->memory[offset]); |
| 2824 | } | 2990 | } |
| 2825 | break; | 2991 | break; |
| 2826 | case WasmOp_i32_load16_s: | 2992 | case WasmOp_i32_load16_s: |
| ... | @@ -2850,7 +3016,7 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -2850,7 +3016,7 @@ static void vm_run(struct VirtualMachine *vm) { |
| 2850 | { | 3016 | { |
| 2851 | uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); | 3017 | uint32_t offset = operands[pc->operand] + vm_pop_u32(vm); |
| 2852 | pc->operand += 1; | 3018 | pc->operand += 1; |
| 2853 | vm_push_u64(vm, vm->memory[offset]); | 3019 | vm_push_u64(vm, (uint8_t)vm->memory[offset]); |
| 2854 | } | 3020 | } |
| 2855 | break; | 3021 | break; |
| 2856 | case WasmOp_i64_load16_s: | 3022 | case WasmOp_i64_load16_s: |
| ... | @@ -2968,7 +3134,7 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -2968,7 +3134,7 @@ static void vm_run(struct VirtualMachine *vm) { |
| 2968 | uint32_t page_count = vm_pop_u32(vm); | 3134 | uint32_t page_count = vm_pop_u32(vm); |
| 2969 | uint32_t old_page_count = vm->memory_len / wasm_page_size; | 3135 | uint32_t old_page_count = vm->memory_len / wasm_page_size; |
| 2970 | uint32_t new_len = vm->memory_len + page_count * wasm_page_size; | 3136 | 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) { |
| 2972 | vm_push_i32(vm, -1); | 3138 | vm_push_i32(vm, -1); |
| 2973 | } else { | 3139 | } else { |
| 2974 | vm->memory_len = new_len; | 3140 | vm->memory_len = new_len; |
| ... | @@ -3294,21 +3460,21 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -3294,21 +3460,21 @@ static void vm_run(struct VirtualMachine *vm) { |
| 3294 | { | 3460 | { |
| 3295 | uint32_t rhs = vm_pop_u32(vm); | 3461 | uint32_t rhs = vm_pop_u32(vm); |
| 3296 | uint32_t lhs = vm_pop_u32(vm); | 3462 | uint32_t lhs = vm_pop_u32(vm); |
| 3297 | vm_push_u32(vm, lhs << rhs); | 3463 | vm_push_u32(vm, lhs << (rhs & 0x1f)); |
| 3298 | } | 3464 | } |
| 3299 | break; | 3465 | break; |
| 3300 | case WasmOp_i32_shr_s: | 3466 | case WasmOp_i32_shr_s: |
| 3301 | { | 3467 | { |
| 3302 | uint32_t rhs = vm_pop_u32(vm); | 3468 | uint32_t rhs = vm_pop_u32(vm); |
| 3303 | int32_t lhs = vm_pop_i32(vm); | 3469 | int32_t lhs = vm_pop_i32(vm); |
| 3304 | vm_push_i32(vm, lhs >> rhs); | 3470 | vm_push_i32(vm, lhs >> (rhs & 0x1f)); |
| 3305 | } | 3471 | } |
| 3306 | break; | 3472 | break; |
| 3307 | case WasmOp_i32_shr_u: | 3473 | case WasmOp_i32_shr_u: |
| 3308 | { | 3474 | { |
| 3309 | uint32_t rhs = vm_pop_u32(vm); | 3475 | uint32_t rhs = vm_pop_u32(vm); |
| 3310 | uint32_t lhs = vm_pop_u32(vm); | 3476 | uint32_t lhs = vm_pop_u32(vm); |
| 3311 | vm_push_u32(vm, lhs >> rhs); | 3477 | vm_push_u32(vm, lhs >> (rhs & 0x1f)); |
| 3312 | } | 3478 | } |
| 3313 | break; | 3479 | break; |
| 3314 | case WasmOp_i32_rotl: | 3480 | case WasmOp_i32_rotl: |
| ... | @@ -3421,35 +3587,35 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -3421,35 +3587,35 @@ static void vm_run(struct VirtualMachine *vm) { |
| 3421 | { | 3587 | { |
| 3422 | uint64_t rhs = vm_pop_u64(vm); | 3588 | uint64_t rhs = vm_pop_u64(vm); |
| 3423 | uint64_t lhs = vm_pop_u64(vm); | 3589 | uint64_t lhs = vm_pop_u64(vm); |
| 3424 | vm_push_u64(vm, lhs << rhs); | 3590 | vm_push_u64(vm, lhs << (rhs & 0x3f)); |
| 3425 | } | 3591 | } |
| 3426 | break; | 3592 | break; |
| 3427 | case WasmOp_i64_shr_s: | 3593 | case WasmOp_i64_shr_s: |
| 3428 | { | 3594 | { |
| 3429 | uint64_t rhs = vm_pop_u64(vm); | 3595 | uint64_t rhs = vm_pop_u64(vm); |
| 3430 | int64_t lhs = vm_pop_i64(vm); | 3596 | int64_t lhs = vm_pop_i64(vm); |
| 3431 | vm_push_i64(vm, lhs >> rhs); | 3597 | vm_push_i64(vm, lhs >> (rhs & 0x3f)); |
| 3432 | } | 3598 | } |
| 3433 | break; | 3599 | break; |
| 3434 | case WasmOp_i64_shr_u: | 3600 | case WasmOp_i64_shr_u: |
| 3435 | { | 3601 | { |
| 3436 | uint64_t rhs = vm_pop_u64(vm); | 3602 | uint64_t rhs = vm_pop_u64(vm); |
| 3437 | uint64_t lhs = vm_pop_u64(vm); | 3603 | uint64_t lhs = vm_pop_u64(vm); |
| 3438 | vm_push_u64(vm, lhs >> rhs); | 3604 | vm_push_u64(vm, lhs >> (rhs & 0x3f)); |
| 3439 | } | 3605 | } |
| 3440 | break; | 3606 | break; |
| 3441 | case WasmOp_i64_rotl: | 3607 | case WasmOp_i64_rotl: |
| 3442 | { | 3608 | { |
| 3443 | uint64_t rhs = vm_pop_u64(vm); | 3609 | uint64_t rhs = vm_pop_u64(vm); |
| 3444 | uint64_t lhs = vm_pop_u64(vm); | 3610 | uint64_t lhs = vm_pop_u64(vm); |
| 3445 | vm_push_u64(vm, rotl64(lhs, rhs )); | 3611 | vm_push_u64(vm, rotl64(lhs, rhs)); |
| 3446 | } | 3612 | } |
| 3447 | break; | 3613 | break; |
| 3448 | case WasmOp_i64_rotr: | 3614 | case WasmOp_i64_rotr: |
| 3449 | { | 3615 | { |
| 3450 | uint64_t rhs = vm_pop_u64(vm); | 3616 | uint64_t rhs = vm_pop_u64(vm); |
| 3451 | uint64_t lhs = vm_pop_u64(vm); | 3617 | uint64_t lhs = vm_pop_u64(vm); |
| 3452 | vm_push_u64(vm, rotr64(lhs, rhs )); | 3618 | vm_push_u64(vm, rotr64(lhs, rhs)); |
| 3453 | } | 3619 | } |
| 3454 | break; | 3620 | break; |
| 3455 | | 3621 | |
| ... | @@ -3839,19 +4005,126 @@ static void vm_run(struct VirtualMachine *vm) { | ... | @@ -3839,19 +4005,126 @@ static void vm_run(struct VirtualMachine *vm) { |
| 3839 | } | 4005 | } |
| 3840 | } | 4006 | } |
| 3841 | | 4007 | |
| | 4008 | static 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 | |
| 3842 | int main(int argc, char **argv) { | 4014 | int main(int argc, char **argv) { |
| 3843 | char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); | 4015 | char *memory = mmap( NULL, max_memory, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); |
| 3844 | | 4016 | |
| 3845 | const char *zig_lib_dir_path = argv[1]; | 4017 | const char *zig_lib_dir_path = argv[1]; |
| 3846 | const char *zig_cache_dir_path = argv[2]; | 4018 | const char *cmake_binary_dir_path = argv[2]; |
| 3847 | const size_t vm_argv_start = 3; | 4019 | const char *root_name = argv[3]; |
| 3848 | const char *wasm_file = argv[vm_argv_start]; | 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; |
| 3849 | | 4124 | |
| 3850 | const struct ByteSlice mod = read_file_alloc(wasm_file); | 4125 | const struct ByteSlice mod = read_file_alloc(wasm_file); |
| 3851 | | 4126 | |
| 3852 | int cwd = err_wrap("opening cwd", open(".", O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); | 4127 | 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)); | | |
| 3855 | int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); | 4128 | int zig_lib_dir = err_wrap("opening zig lib dir", open(zig_lib_dir_path, O_DIRECTORY|O_RDONLY|O_CLOEXEC|O_PATH)); |
| 3856 | | 4129 | |
| 3857 | add_preopen(0, "stdin", STDIN_FILENO); | 4130 | add_preopen(0, "stdin", STDIN_FILENO); |
| ... | @@ -3873,7 +4146,7 @@ int main(int argc, char **argv) { | ... | @@ -3873,7 +4146,7 @@ int main(int argc, char **argv) { |
| 3873 | if (version != 1) panic("bad wasm version"); | 4146 | if (version != 1) panic("bad wasm version"); |
| 3874 | | 4147 | |
| 3875 | uint32_t section_starts[13]; | 4148 | uint32_t section_starts[13]; |
| 3876 | memset(&section_starts, 0, 4 * 13); | 4149 | memset(&section_starts, 0, sizeof(uint32_t) * 13); |
| 3877 | | 4150 | |
| 3878 | while (i < mod.len) { | 4151 | while (i < mod.len) { |
| 3879 | uint8_t section_id = mod.ptr[i]; | 4152 | uint8_t section_id = mod.ptr[i]; |
| ... | @@ -3895,6 +4168,7 @@ int main(int argc, char **argv) { | ... | @@ -3895,6 +4168,7 @@ int main(int argc, char **argv) { |
| 3895 | i += 1; | 4168 | i += 1; |
| 3896 | | 4169 | |
| 3897 | info->param_count = read32_uleb128(mod.ptr, &i); | 4170 | info->param_count = read32_uleb128(mod.ptr, &i); |
| | 4171 | if (info->param_count > 32) panic("found a type with over 32 parameters"); |
| 3898 | info->param_types = 0; | 4172 | info->param_types = 0; |
| 3899 | for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) { | 4173 | for (uint32_t param_i = 0; param_i < info->param_count; param_i += 1) { |
| 3900 | int64_t param_type = read64_ileb128(mod.ptr, &i); | 4174 | int64_t param_type = read64_ileb128(mod.ptr, &i); |
| ... | @@ -4133,7 +4407,7 @@ int main(int argc, char **argv) { | ... | @@ -4133,7 +4407,7 @@ int main(int argc, char **argv) { |
| 4133 | uint32_t elem_count = read32_uleb128(mod.ptr, &i); | 4407 | uint32_t elem_count = read32_uleb128(mod.ptr, &i); |
| 4134 | | 4408 | |
| 4135 | table = arena_alloc(sizeof(uint32_t) * maximum); | 4409 | table = arena_alloc(sizeof(uint32_t) * maximum); |
| 4136 | memset(table, 0, maximum); | 4410 | memset(table, 0, sizeof(uint32_t) * maximum); |
| 4137 | | 4411 | |
| 4138 | for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) { | 4412 | for (uint32_t elem_i = 0; elem_i < elem_count; elem_i += 1) { |
| 4139 | table[elem_i + offset] = read32_uleb128(mod.ptr, &i); | 4413 | table[elem_i + offset] = read32_uleb128(mod.ptr, &i); |
| ... | @@ -4142,6 +4416,9 @@ int main(int argc, char **argv) { | ... | @@ -4142,6 +4416,9 @@ int main(int argc, char **argv) { |
| 4142 | } | 4416 | } |
| 4143 | | 4417 | |
| 4144 | struct VirtualMachine vm; | 4418 | struct VirtualMachine vm; |
| | 4419 | #ifndef NDEBUG |
| | 4420 | memset(&vm, 0xaa, sizeof(struct VirtualMachine)); // to match the zig version |
| | 4421 | #endif |
| 4145 | vm.stack = arena_alloc(sizeof(uint64_t) * 10000000), | 4422 | vm.stack = arena_alloc(sizeof(uint64_t) * 10000000), |
| 4146 | vm.mod_ptr = mod.ptr; | 4423 | vm.mod_ptr = mod.ptr; |
| 4147 | vm.opcodes = arena_alloc(2000000); | 4424 | vm.opcodes = arena_alloc(2000000); |
| ... | @@ -4154,7 +4431,7 @@ int main(int argc, char **argv) { | ... | @@ -4154,7 +4431,7 @@ int main(int argc, char **argv) { |
| 4154 | vm.memory_len = memory_len; | 4431 | vm.memory_len = memory_len; |
| 4155 | vm.imports = imports; | 4432 | vm.imports = imports; |
| 4156 | vm.imports_len = imports_len; | 4433 | vm.imports_len = imports_len; |
| 4157 | vm.args = argv + vm_argv_start; | 4434 | vm.args = new_argv; |
| 4158 | vm.table = table; | 4435 | vm.table = table; |
| 4159 | | 4436 | |
| 4160 | { | 4437 | { |
| ... | @@ -4171,18 +4448,19 @@ int main(int argc, char **argv) { | ... | @@ -4171,18 +4448,19 @@ int main(int argc, char **argv) { |
| 4171 | | 4448 | |
| 4172 | struct TypeInfo *type_info = &vm.types[func->type_idx]; | 4449 | struct TypeInfo *type_info = &vm.types[func->type_idx]; |
| 4173 | func->locals_count = 0; | 4450 | 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)); |
| 4175 | func->local_types[0] = type_info->param_types; | 4452 | func->local_types[0] = type_info->param_types; |
| 4176 | | 4453 | |
| 4177 | for (uint32_t local_sets_count = read32_uleb128(mod.ptr, &code_i); | 4454 | 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 | { |
| 4179 | uint32_t set_count = read32_uleb128(mod.ptr, &code_i); | 4457 | uint32_t set_count = read32_uleb128(mod.ptr, &code_i); |
| 4180 | int64_t local_type = read64_ileb128(mod.ptr, &code_i); | 4458 | int64_t local_type = read64_ileb128(mod.ptr, &code_i); |
| 4181 | | 4459 | |
| 4182 | uint32_t i = type_info->param_count + func->locals_count; | 4460 | uint32_t i = type_info->param_count + func->locals_count; |
| 4183 | func->locals_count += set_count; | 4461 | func->locals_count += set_count; |
| 4184 | if ((type_info->param_count + func->locals_count + 31) / 32 > (i + 31) / 32) | 4462 | 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)); |
| 4186 | for (; i < type_info->param_count + func->locals_count; i += 1) | 4464 | for (; i < type_info->param_count + func->locals_count; i += 1) |
| 4187 | switch (local_type) { | 4465 | switch (local_type) { |
| 4188 | case -1: case -3: bs_unset(func->local_types, i); break; | 4466 | case -1: case -3: bs_unset(func->local_types, i); break; |
| ... | @@ -4191,26 +4469,11 @@ int main(int argc, char **argv) { | ... | @@ -4191,26 +4469,11 @@ int main(int argc, char **argv) { |
| 4191 | } | 4469 | } |
| 4192 | } | 4470 | } |
| 4193 | | 4471 | |
| | 4472 | //fprintf(stderr, "set up func %u with pc %u:%u\n", func->type_idx, pc.opcode, pc.operand); |
| 4194 | func->entry_pc = pc; | 4473 | func->entry_pc = pc; |
| 4195 | vm_decodeCode(&vm, func, &code_i, &pc); | 4474 | vm_decodeCode(&vm, func, &code_i, &pc); |
| 4196 | if (code_i != code_begin + size) panic("bad code size"); | 4475 | if (code_i != code_begin + size) panic("bad code size"); |
| 4197 | } | 4476 | } |
| 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 | } | | |
| 4214 | } | 4477 | } |
| 4215 | | 4478 | |
| 4216 | vm_call(&vm, start_fn_idx); | 4479 | vm_call(&vm, start_fn_idx); |