| author | |
| committer | |
| log | 80f79cc9e8ed02f631c9d59f68e5f20a909e85fc |
| tree | ba8da3ef0611a547fe67c61ed2d42d4ea67e6d2e |
| parent | cb38bd0a1436bd18de8ed57c45ffc890c8ddfb78 |
| parent | 4261fa3c49be715355c9623102bad0bf93d537a3 |
| signature |
closes #373013 files changed, 205 insertions(+), 106 deletions(-)
lib/std/build.zig+8| ... | @@ -1064,6 +1064,9 @@ pub const LibExeObjStep = struct { | ... | @@ -1064,6 +1064,9 @@ pub const LibExeObjStep = struct { |
| 1064 | /// Uses system QEMU installation to run cross compiled foreign architecture build artifacts. | 1064 | /// Uses system QEMU installation to run cross compiled foreign architecture build artifacts. |
| 1065 | enable_qemu: bool = false, | 1065 | enable_qemu: bool = false, |
| 1066 | 1066 | ||
| 1067 | /// Uses system Wasmtime installation to run cross compiled wasm/wasi build artifacts. | ||
| 1068 | enable_wasmtime: bool = false, | ||
| 1069 | |||
| 1067 | /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc, | 1070 | /// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc, |
| 1068 | /// this will be the directory $glibc-build-dir/install/glibcs | 1071 | /// this will be the directory $glibc-build-dir/install/glibcs |
| 1069 | /// Given the example of the aarch64 target, this is the directory | 1072 | /// Given the example of the aarch64 target, this is the directory |
| ... | @@ -1863,6 +1866,11 @@ pub const LibExeObjStep = struct { | ... | @@ -1863,6 +1866,11 @@ pub const LibExeObjStep = struct { |
| 1863 | try zig_args.append(bin_name); | 1866 | try zig_args.append(bin_name); |
| 1864 | try zig_args.append("--test-cmd-bin"); | 1867 | try zig_args.append("--test-cmd-bin"); |
| 1865 | }, | 1868 | }, |
| 1869 | .wasmtime => |bin_name| if (self.enable_wasmtime) { | ||
| 1870 | try zig_args.append("--test-cmd"); | ||
| 1871 | try zig_args.append(bin_name); | ||
| 1872 | try zig_args.append("--test-cmd-bin"); | ||
| 1873 | }, | ||
| 1866 | } | 1874 | } |
| 1867 | for (self.packages.toSliceConst()) |pkg| { | 1875 | for (self.packages.toSliceConst()) |pkg| { |
| 1868 | zig_args.append("--pkg-begin") catch unreachable; | 1876 | zig_args.append("--pkg-begin") catch unreachable; |
lib/std/debug.zig+2-1| ... | @@ -213,7 +213,8 @@ pub fn assert(ok: bool) void { | ... | @@ -213,7 +213,8 @@ pub fn assert(ok: bool) void { |
| 213 | 213 | ||
| 214 | pub fn panic(comptime format: []const u8, args: ...) noreturn { | 214 | pub fn panic(comptime format: []const u8, args: ...) noreturn { |
| 215 | @setCold(true); | 215 | @setCold(true); |
| 216 | const first_trace_addr = @returnAddress(); | 216 | // TODO: remove conditional once wasi / LLVM defines __builtin_return_address |
| 217 | const first_trace_addr = if (builtin.os == .wasi) null else @returnAddress(); | ||
| 217 | panicExtra(null, first_trace_addr, format, args); | 218 | panicExtra(null, first_trace_addr, format, args); |
| 218 | } | 219 | } |
| 219 | 220 |
lib/std/heap.zig+91-98| ... | @@ -33,11 +33,19 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new | ... | @@ -33,11 +33,19 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new |
| 33 | 33 | ||
| 34 | /// This allocator makes a syscall directly for every allocation and free. | 34 | /// This allocator makes a syscall directly for every allocation and free. |
| 35 | /// Thread-safe and lock-free. | 35 | /// Thread-safe and lock-free. |
| 36 | pub const page_allocator = &page_allocator_state; | 36 | pub const page_allocator = if (std.Target.current.isWasm()) |
| 37 | &wasm_page_allocator_state | ||
| 38 | else | ||
| 39 | &page_allocator_state; | ||
| 40 | |||
| 37 | var page_allocator_state = Allocator{ | 41 | var page_allocator_state = Allocator{ |
| 38 | .reallocFn = PageAllocator.realloc, | 42 | .reallocFn = PageAllocator.realloc, |
| 39 | .shrinkFn = PageAllocator.shrink, | 43 | .shrinkFn = PageAllocator.shrink, |
| 40 | }; | 44 | }; |
| 45 | var wasm_page_allocator_state = Allocator{ | ||
| 46 | .reallocFn = WasmPageAllocator.realloc, | ||
| 47 | .shrinkFn = WasmPageAllocator.shrink, | ||
| 48 | }; | ||
| 41 | 49 | ||
| 42 | /// Deprecated. Use `page_allocator`. | 50 | /// Deprecated. Use `page_allocator`. |
| 43 | pub const direct_allocator = page_allocator; | 51 | pub const direct_allocator = page_allocator; |
| ... | @@ -238,6 +246,88 @@ const PageAllocator = struct { | ... | @@ -238,6 +246,88 @@ const PageAllocator = struct { |
| 238 | } | 246 | } |
| 239 | }; | 247 | }; |
| 240 | 248 | ||
| 249 | // TODO Exposed LLVM intrinsics is a bug | ||
| 250 | // See: https://github.com/ziglang/zig/issues/2291 | ||
| 251 | extern fn @"llvm.wasm.memory.size.i32"(u32) u32; | ||
| 252 | extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32; | ||
| 253 | |||
| 254 | /// TODO: make this re-use freed pages, and cooperate with other callers of these global intrinsics | ||
| 255 | /// by better utilizing the return value of grow() | ||
| 256 | const WasmPageAllocator = struct { | ||
| 257 | var start_ptr: [*]u8 = undefined; | ||
| 258 | var num_pages: usize = 0; | ||
| 259 | var end_index: usize = 0; | ||
| 260 | |||
| 261 | comptime { | ||
| 262 | if (builtin.arch != .wasm32) { | ||
| 263 | @compileError("WasmPageAllocator is only available for wasm32 arch"); | ||
| 264 | } | ||
| 265 | } | ||
| 266 | |||
| 267 | fn alloc(allocator: *Allocator, size: usize, alignment: u29) ![]u8 { | ||
| 268 | const addr = @ptrToInt(start_ptr) + end_index; | ||
| 269 | const adjusted_addr = mem.alignForward(addr, alignment); | ||
| 270 | const adjusted_index = end_index + (adjusted_addr - addr); | ||
| 271 | const new_end_index = adjusted_index + size; | ||
| 272 | |||
| 273 | if (new_end_index > num_pages * mem.page_size) { | ||
| 274 | const required_memory = new_end_index - (num_pages * mem.page_size); | ||
| 275 | |||
| 276 | var inner_num_pages: usize = required_memory / mem.page_size; | ||
| 277 | if (required_memory % mem.page_size != 0) { | ||
| 278 | inner_num_pages += 1; | ||
| 279 | } | ||
| 280 | |||
| 281 | const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, inner_num_pages)); | ||
| 282 | if (prev_page == -1) { | ||
| 283 | return error.OutOfMemory; | ||
| 284 | } | ||
| 285 | |||
| 286 | num_pages += inner_num_pages; | ||
| 287 | } | ||
| 288 | |||
| 289 | const result = start_ptr[adjusted_index..new_end_index]; | ||
| 290 | end_index = new_end_index; | ||
| 291 | |||
| 292 | return result; | ||
| 293 | } | ||
| 294 | |||
| 295 | // Check if memory is the last "item" and is aligned correctly | ||
| 296 | fn is_last_item(memory: []u8, alignment: u29) bool { | ||
| 297 | return memory.ptr == start_ptr + end_index - memory.len and mem.alignForward(@ptrToInt(memory.ptr), alignment) == @ptrToInt(memory.ptr); | ||
| 298 | } | ||
| 299 | |||
| 300 | fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { | ||
| 301 | // Initialize start_ptr at the first realloc | ||
| 302 | if (num_pages == 0) { | ||
| 303 | start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size); | ||
| 304 | } | ||
| 305 | |||
| 306 | if (is_last_item(old_mem, new_align)) { | ||
| 307 | const start_index = end_index - old_mem.len; | ||
| 308 | const new_end_index = start_index + new_size; | ||
| 309 | |||
| 310 | if (new_end_index > num_pages * mem.page_size) { | ||
| 311 | _ = try alloc(allocator, new_end_index - end_index, new_align); | ||
| 312 | } | ||
| 313 | const result = start_ptr[start_index..new_end_index]; | ||
| 314 | |||
| 315 | end_index = new_end_index; | ||
| 316 | return result; | ||
| 317 | } else if (new_size <= old_mem.len and new_align <= old_align) { | ||
| 318 | return error.OutOfMemory; | ||
| 319 | } else { | ||
| 320 | const result = try alloc(allocator, new_size, new_align); | ||
| 321 | mem.copy(u8, result, old_mem); | ||
| 322 | return result; | ||
| 323 | } | ||
| 324 | } | ||
| 325 | |||
| 326 | fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { | ||
| 327 | return old_mem[0..new_size]; | ||
| 328 | } | ||
| 329 | }; | ||
| 330 | |||
| 241 | pub const HeapAllocator = switch (builtin.os) { | 331 | pub const HeapAllocator = switch (builtin.os) { |
| 242 | .windows => struct { | 332 | .windows => struct { |
| 243 | allocator: Allocator, | 333 | allocator: Allocator, |
| ... | @@ -487,103 +577,6 @@ pub const FixedBufferAllocator = struct { | ... | @@ -487,103 +577,6 @@ pub const FixedBufferAllocator = struct { |
| 487 | } | 577 | } |
| 488 | }; | 578 | }; |
| 489 | 579 | ||
| 490 | // TODO Exposed LLVM intrinsics is a bug | ||
| 491 | // See: https://github.com/ziglang/zig/issues/2291 | ||
| 492 | extern fn @"llvm.wasm.memory.size.i32"(u32) u32; | ||
| 493 | extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32; | ||
| 494 | |||
| 495 | pub const wasm_allocator = &wasm_allocator_state.allocator; | ||
| 496 | var wasm_allocator_state = WasmAllocator{ | ||
| 497 | .allocator = Allocator{ | ||
| 498 | .reallocFn = WasmAllocator.realloc, | ||
| 499 | .shrinkFn = WasmAllocator.shrink, | ||
| 500 | }, | ||
| 501 | .start_ptr = undefined, | ||
| 502 | .num_pages = 0, | ||
| 503 | .end_index = 0, | ||
| 504 | }; | ||
| 505 | |||
| 506 | const WasmAllocator = struct { | ||
| 507 | allocator: Allocator, | ||
| 508 | start_ptr: [*]u8, | ||
| 509 | num_pages: usize, | ||
| 510 | end_index: usize, | ||
| 511 | |||
| 512 | comptime { | ||
| 513 | if (builtin.arch != .wasm32) { | ||
| 514 | @compileError("WasmAllocator is only available for wasm32 arch"); | ||
| 515 | } | ||
| 516 | } | ||
| 517 | |||
| 518 | fn alloc(allocator: *Allocator, size: usize, alignment: u29) ![]u8 { | ||
| 519 | const self = @fieldParentPtr(WasmAllocator, "allocator", allocator); | ||
| 520 | |||
| 521 | const addr = @ptrToInt(self.start_ptr) + self.end_index; | ||
| 522 | const adjusted_addr = mem.alignForward(addr, alignment); | ||
| 523 | const adjusted_index = self.end_index + (adjusted_addr - addr); | ||
| 524 | const new_end_index = adjusted_index + size; | ||
| 525 | |||
| 526 | if (new_end_index > self.num_pages * mem.page_size) { | ||
| 527 | const required_memory = new_end_index - (self.num_pages * mem.page_size); | ||
| 528 | |||
| 529 | var num_pages: usize = required_memory / mem.page_size; | ||
| 530 | if (required_memory % mem.page_size != 0) { | ||
| 531 | num_pages += 1; | ||
| 532 | } | ||
| 533 | |||
| 534 | const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, num_pages)); | ||
| 535 | if (prev_page == -1) { | ||
| 536 | return error.OutOfMemory; | ||
| 537 | } | ||
| 538 | |||
| 539 | self.num_pages += num_pages; | ||
| 540 | } | ||
| 541 | |||
| 542 | const result = self.start_ptr[adjusted_index..new_end_index]; | ||
| 543 | self.end_index = new_end_index; | ||
| 544 | |||
| 545 | return result; | ||
| 546 | } | ||
| 547 | |||
| 548 | // Check if memory is the last "item" and is aligned correctly | ||
| 549 | fn is_last_item(allocator: *Allocator, memory: []u8, alignment: u29) bool { | ||
| 550 | const self = @fieldParentPtr(WasmAllocator, "allocator", allocator); | ||
| 551 | return memory.ptr == self.start_ptr + self.end_index - memory.len and mem.alignForward(@ptrToInt(memory.ptr), alignment) == @ptrToInt(memory.ptr); | ||
| 552 | } | ||
| 553 | |||
| 554 | fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 { | ||
| 555 | const self = @fieldParentPtr(WasmAllocator, "allocator", allocator); | ||
| 556 | |||
| 557 | // Initialize start_ptr at the first realloc | ||
| 558 | if (self.num_pages == 0) { | ||
| 559 | self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size); | ||
| 560 | } | ||
| 561 | |||
| 562 | if (is_last_item(allocator, old_mem, new_align)) { | ||
| 563 | const start_index = self.end_index - old_mem.len; | ||
| 564 | const new_end_index = start_index + new_size; | ||
| 565 | |||
| 566 | if (new_end_index > self.num_pages * mem.page_size) { | ||
| 567 | _ = try alloc(allocator, new_end_index - self.end_index, new_align); | ||
| 568 | } | ||
| 569 | const result = self.start_ptr[start_index..new_end_index]; | ||
| 570 | |||
| 571 | self.end_index = new_end_index; | ||
| 572 | return result; | ||
| 573 | } else if (new_size <= old_mem.len and new_align <= old_align) { | ||
| 574 | return error.OutOfMemory; | ||
| 575 | } else { | ||
| 576 | const result = try alloc(allocator, new_size, new_align); | ||
| 577 | mem.copy(u8, result, old_mem); | ||
| 578 | return result; | ||
| 579 | } | ||
| 580 | } | ||
| 581 | |||
| 582 | fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 { | ||
| 583 | return old_mem[0..new_size]; | ||
| 584 | } | ||
| 585 | }; | ||
| 586 | |||
| 587 | pub const ThreadSafeFixedBufferAllocator = blk: { | 580 | pub const ThreadSafeFixedBufferAllocator = blk: { |
| 588 | if (builtin.single_threaded) { | 581 | if (builtin.single_threaded) { |
| 589 | break :blk FixedBufferAllocator; | 582 | break :blk FixedBufferAllocator; |
lib/std/os.zig+43-1| ... | @@ -1527,7 +1527,22 @@ pub fn isatty(handle: fd_t) bool { | ... | @@ -1527,7 +1527,22 @@ pub fn isatty(handle: fd_t) bool { |
| 1527 | return system.isatty(handle) != 0; | 1527 | return system.isatty(handle) != 0; |
| 1528 | } | 1528 | } |
| 1529 | if (builtin.os == .wasi) { | 1529 | if (builtin.os == .wasi) { |
| 1530 | @compileError("TODO implement std.os.isatty for WASI"); | 1530 | var statbuf: fdstat_t = undefined; |
| 1531 | const err = system.fd_fdstat_get(handle, &statbuf); | ||
| 1532 | if (err != 0) { | ||
| 1533 | // errno = err; | ||
| 1534 | return false; | ||
| 1535 | } | ||
| 1536 | |||
| 1537 | // A tty is a character device that we can't seek or tell on. | ||
| 1538 | if (statbuf.fs_filetype != FILETYPE_CHARACTER_DEVICE or | ||
| 1539 | (statbuf.fs_rights_base & (RIGHT_FD_SEEK | RIGHT_FD_TELL)) != 0) | ||
| 1540 | { | ||
| 1541 | // errno = ENOTTY; | ||
| 1542 | return false; | ||
| 1543 | } | ||
| 1544 | |||
| 1545 | return true; | ||
| 1531 | } | 1546 | } |
| 1532 | if (builtin.os == .linux) { | 1547 | if (builtin.os == .linux) { |
| 1533 | var wsz: linux.winsize = undefined; | 1548 | var wsz: linux.winsize = undefined; |
| ... | @@ -2720,6 +2735,20 @@ pub fn dl_iterate_phdr( | ... | @@ -2720,6 +2735,20 @@ pub fn dl_iterate_phdr( |
| 2720 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; | 2735 | pub const ClockGetTimeError = error{UnsupportedClock} || UnexpectedError; |
| 2721 | 2736 | ||
| 2722 | pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { | 2737 | pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { |
| 2738 | if (comptime std.Target.current.getOs() == .wasi) { | ||
| 2739 | var ts: timestamp_t = undefined; | ||
| 2740 | switch (system.clock_time_get(@bitCast(u32, clk_id), 1, &ts)) { | ||
| 2741 | 0 => { | ||
| 2742 | tp.* = .{ | ||
| 2743 | .tv_sec = @intCast(i64, ts / std.time.ns_per_s), | ||
| 2744 | .tv_nsec = @intCast(isize, ts % std.time.ns_per_s), | ||
| 2745 | }; | ||
| 2746 | }, | ||
| 2747 | EINVAL => return error.UnsupportedClock, | ||
| 2748 | else => |err| return unexpectedErrno(err), | ||
| 2749 | } | ||
| 2750 | return; | ||
| 2751 | } | ||
| 2723 | switch (errno(system.clock_gettime(clk_id, tp))) { | 2752 | switch (errno(system.clock_gettime(clk_id, tp))) { |
| 2724 | 0 => return, | 2753 | 0 => return, |
| 2725 | EFAULT => unreachable, | 2754 | EFAULT => unreachable, |
| ... | @@ -2729,6 +2758,19 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { | ... | @@ -2729,6 +2758,19 @@ pub fn clock_gettime(clk_id: i32, tp: *timespec) ClockGetTimeError!void { |
| 2729 | } | 2758 | } |
| 2730 | 2759 | ||
| 2731 | pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { | 2760 | pub fn clock_getres(clk_id: i32, res: *timespec) ClockGetTimeError!void { |
| 2761 | if (comptime std.Target.current.getOs() == .wasi) { | ||
| 2762 | var ts: timestamp_t = undefined; | ||
| 2763 | switch (system.clock_res_get(@bitCast(u32, clk_id), &ts)) { | ||
| 2764 | 0 => res.* = .{ | ||
| 2765 | .tv_sec = @intCast(i64, ts / std.time.ns_per_s), | ||
| 2766 | .tv_nsec = @intCast(isize, ts % std.time.ns_per_s), | ||
| 2767 | }, | ||
| 2768 | EINVAL => return error.UnsupportedClock, | ||
| 2769 | else => |err| return unexpectedErrno(err), | ||
| 2770 | } | ||
| 2771 | return; | ||
| 2772 | } | ||
| 2773 | |||
| 2732 | switch (errno(system.clock_getres(clk_id, res))) { | 2774 | switch (errno(system.clock_getres(clk_id, res))) { |
| 2733 | 0 => return, | 2775 | 0 => return, |
| 2734 | EFAULT => unreachable, | 2776 | EFAULT => unreachable, |
lib/std/os/bits/wasi.zig+7-1| ... | @@ -138,7 +138,7 @@ pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004; | ... | @@ -138,7 +138,7 @@ pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004; |
| 138 | pub const FDFLAG_RSYNC: fdflags_t = 0x0008; | 138 | pub const FDFLAG_RSYNC: fdflags_t = 0x0008; |
| 139 | pub const FDFLAG_SYNC: fdflags_t = 0x0010; | 139 | pub const FDFLAG_SYNC: fdflags_t = 0x0010; |
| 140 | 140 | ||
| 141 | const fdstat_t = extern struct { | 141 | pub const fdstat_t = extern struct { |
| 142 | fs_filetype: filetype_t, | 142 | fs_filetype: filetype_t, |
| 143 | fs_flags: fdflags_t, | 143 | fs_flags: fdflags_t, |
| 144 | fs_rights_base: rights_t, | 144 | fs_rights_base: rights_t, |
| ... | @@ -298,6 +298,7 @@ pub const subscription_t = extern struct { | ... | @@ -298,6 +298,7 @@ pub const subscription_t = extern struct { |
| 298 | }; | 298 | }; |
| 299 | 299 | ||
| 300 | pub const timestamp_t = u64; | 300 | pub const timestamp_t = u64; |
| 301 | pub const time_t = i64; // match https://github.com/CraneStation/wasi-libc | ||
| 301 | 302 | ||
| 302 | pub const userdata_t = u64; | 303 | pub const userdata_t = u64; |
| 303 | 304 | ||
| ... | @@ -305,3 +306,8 @@ pub const whence_t = u8; | ... | @@ -305,3 +306,8 @@ pub const whence_t = u8; |
| 305 | pub const WHENCE_CUR: whence_t = 0; | 306 | pub const WHENCE_CUR: whence_t = 0; |
| 306 | pub const WHENCE_END: whence_t = 1; | 307 | pub const WHENCE_END: whence_t = 1; |
| 307 | pub const WHENCE_SET: whence_t = 2; | 308 | pub const WHENCE_SET: whence_t = 2; |
| 309 | |||
| 310 | pub const timespec = extern struct { | ||
| 311 | tv_sec: time_t, | ||
| 312 | tv_nsec: isize, | ||
| 313 | }; |
lib/std/os/wasi.zig+5| ... | @@ -76,3 +76,8 @@ pub extern "wasi_unstable" fn sched_yield() errno_t; | ... | @@ -76,3 +76,8 @@ pub extern "wasi_unstable" fn sched_yield() errno_t; |
| 76 | pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t; | 76 | pub extern "wasi_unstable" fn sock_recv(sock: fd_t, ri_data: *const iovec_t, ri_data_len: usize, ri_flags: riflags_t, ro_datalen: *usize, ro_flags: *roflags_t) errno_t; |
| 77 | pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t; | 77 | pub extern "wasi_unstable" fn sock_send(sock: fd_t, si_data: *const ciovec_t, si_data_len: usize, si_flags: siflags_t, so_datalen: *usize) errno_t; |
| 78 | pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t; | 78 | pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t; |
| 79 | |||
| 80 | /// Get the errno from a syscall return value, or 0 for no error. | ||
| 81 | pub fn getErrno(r: errno_t) usize { | ||
| 82 | return r; | ||
| 83 | } |
lib/std/target.zig+12| ... | @@ -607,10 +607,15 @@ pub const Target = union(enum) { | ... | @@ -607,10 +607,15 @@ pub const Target = union(enum) { |
| 607 | } | 607 | } |
| 608 | } | 608 | } |
| 609 | 609 | ||
| 610 | pub fn supportsNewStackCall(self: Target) bool { | ||
| 611 | return !self.isWasm(); | ||
| 612 | } | ||
| 613 | |||
| 610 | pub const Executor = union(enum) { | 614 | pub const Executor = union(enum) { |
| 611 | native, | 615 | native, |
| 612 | qemu: []const u8, | 616 | qemu: []const u8, |
| 613 | wine: []const u8, | 617 | wine: []const u8, |
| 618 | wasmtime: []const u8, | ||
| 614 | unavailable, | 619 | unavailable, |
| 615 | }; | 620 | }; |
| 616 | 621 | ||
| ... | @@ -649,6 +654,13 @@ pub const Target = union(enum) { | ... | @@ -649,6 +654,13 @@ pub const Target = union(enum) { |
| 649 | } | 654 | } |
| 650 | } | 655 | } |
| 651 | 656 | ||
| 657 | if (self.getOs() == .wasi) { | ||
| 658 | switch (self.getArchPtrBitWidth()) { | ||
| 659 | 32 => return Executor{ .wasmtime = "wasmtime" }, | ||
| 660 | else => return .unavailable, | ||
| 661 | } | ||
| 662 | } | ||
| 663 | |||
| 652 | return .unavailable; | 664 | return .unavailable; |
| 653 | } | 665 | } |
| 654 | }; | 666 | }; |
src/analyze.cpp+2-1| ... | @@ -978,7 +978,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { | ... | @@ -978,7 +978,8 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) { |
| 978 | if (g->zig_target->arch == ZigLLVM_x86 || | 978 | if (g->zig_target->arch == ZigLLVM_x86 || |
| 979 | g->zig_target->arch == ZigLLVM_x86_64 || | 979 | g->zig_target->arch == ZigLLVM_x86_64 || |
| 980 | target_is_arm(g->zig_target) || | 980 | target_is_arm(g->zig_target) || |
| 981 | target_is_riscv(g->zig_target)) | 981 | target_is_riscv(g->zig_target) || |
| 982 | target_is_wasm(g->zig_target)) | ||
| 982 | { | 983 | { |
| 983 | X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); | 984 | X64CABIClass abi_class = type_c_abi_x86_64_class(g, fn_type_id->return_type); |
| 984 | return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval; | 985 | return abi_class == X64CABIClass_MEMORY || abi_class == X64CABIClass_MEMORY_nobyval; |
src/ir.cpp+8| ... | @@ -17095,6 +17095,14 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCall | ... | @@ -17095,6 +17095,14 @@ static IrInstruction *analyze_casted_new_stack(IrAnalyze *ira, IrInstructionCall |
| 17095 | if (call_instruction->new_stack == nullptr) | 17095 | if (call_instruction->new_stack == nullptr) |
| 17096 | return nullptr; | 17096 | return nullptr; |
| 17097 | 17097 | ||
| 17098 | if (!call_instruction->is_async_call_builtin && | ||
| 17099 | arch_stack_pointer_register_name(ira->codegen->zig_target->arch) == nullptr) | ||
| 17100 | { | ||
| 17101 | ir_add_error(ira, &call_instruction->base, | ||
| 17102 | buf_sprintf("target arch '%s' does not support @newStackCall", | ||
| 17103 | target_arch_name(ira->codegen->zig_target->arch))); | ||
| 17104 | } | ||
| 17105 | |||
| 17098 | IrInstruction *new_stack = call_instruction->new_stack->child; | 17106 | IrInstruction *new_stack = call_instruction->new_stack->child; |
| 17099 | if (type_is_invalid(new_stack->value->type)) | 17107 | if (type_is_invalid(new_stack->value->type)) |
| 17100 | return ira->codegen->invalid_instruction; | 17108 | return ira->codegen->invalid_instruction; |
src/target.cpp+4-2| ... | @@ -1458,6 +1458,10 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { | ... | @@ -1458,6 +1458,10 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { |
| 1458 | case ZigLLVM_mipsel: | 1458 | case ZigLLVM_mipsel: |
| 1459 | return "sp"; | 1459 | return "sp"; |
| 1460 | 1460 | ||
| 1461 | case ZigLLVM_wasm32: | ||
| 1462 | case ZigLLVM_wasm64: | ||
| 1463 | return nullptr; // known to be not available | ||
| 1464 | |||
| 1461 | case ZigLLVM_amdgcn: | 1465 | case ZigLLVM_amdgcn: |
| 1462 | case ZigLLVM_amdil: | 1466 | case ZigLLVM_amdil: |
| 1463 | case ZigLLVM_amdil64: | 1467 | case ZigLLVM_amdil64: |
| ... | @@ -1491,8 +1495,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { | ... | @@ -1491,8 +1495,6 @@ const char *arch_stack_pointer_register_name(ZigLLVM_ArchType arch) { |
| 1491 | case ZigLLVM_systemz: | 1495 | case ZigLLVM_systemz: |
| 1492 | case ZigLLVM_tce: | 1496 | case ZigLLVM_tce: |
| 1493 | case ZigLLVM_tcele: | 1497 | case ZigLLVM_tcele: |
| 1494 | case ZigLLVM_wasm32: | ||
| 1495 | case ZigLLVM_wasm64: | ||
| 1496 | case ZigLLVM_xcore: | 1498 | case ZigLLVM_xcore: |
| 1497 | case ZigLLVM_ppc: | 1499 | case ZigLLVM_ppc: |
| 1498 | case ZigLLVM_ppc64: | 1500 | case ZigLLVM_ppc64: |
test/compile_errors.zig+18-1| ... | @@ -2,6 +2,24 @@ const tests = @import("tests.zig"); | ... | @@ -2,6 +2,24 @@ const tests = @import("tests.zig"); |
| 2 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 3 | 3 | ||
| 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { | 4 | pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 5 | cases.addCase(x: { | ||
| 6 | var tc = cases.create("@newStackCall on unsupported target", | ||
| 7 | \\export fn entry() void { | ||
| 8 | \\ var buf: [10]u8 align(16) = undefined; | ||
| 9 | \\ @newStackCall(&buf, foo); | ||
| 10 | \\} | ||
| 11 | \\fn foo() void {} | ||
| 12 | , "tmp.zig:3:5: error: target arch 'wasm32' does not support @newStackCall"); | ||
| 13 | tc.target = tests.Target{ | ||
| 14 | .Cross = tests.CrossTarget{ | ||
| 15 | .arch = .wasm32, | ||
| 16 | .os = .wasi, | ||
| 17 | .abi = .none, | ||
| 18 | }, | ||
| 19 | }; | ||
| 20 | break :x tc; | ||
| 21 | }); | ||
| 22 | |||
| 5 | cases.add( | 23 | cases.add( |
| 6 | "incompatible sentinels", | 24 | "incompatible sentinels", |
| 7 | \\export fn entry1(ptr: [*:255]u8) [*:0]u8 { | 25 | \\export fn entry1(ptr: [*:255]u8) [*:0]u8 { |
| ... | @@ -26,7 +44,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -26,7 +44,6 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 26 | "tmp.zig:8:35: note: destination array requires a terminating '0' sentinel, but source array has a terminating '255' sentinel", | 44 | "tmp.zig:8:35: note: destination array requires a terminating '0' sentinel, but source array has a terminating '255' sentinel", |
| 27 | "tmp.zig:11:31: error: expected type '[2:0]u8', found '[2]u8'", | 45 | "tmp.zig:11:31: error: expected type '[2:0]u8', found '[2]u8'", |
| 28 | "tmp.zig:11:31: note: destination array requires a terminating '0' sentinel", | 46 | "tmp.zig:11:31: note: destination array requires a terminating '0' sentinel", |
| 29 | |||
| 30 | ); | 47 | ); |
| 31 | 48 | ||
| 32 | cases.add( | 49 | cases.add( |
test/stage1/behavior/asm.zig+2-1| ... | @@ -1,5 +1,6 @@ | ... | @@ -1,5 +1,6 @@ |
| 1 | const std = @import("std"); | ||
| 1 | const config = @import("builtin"); | 2 | const config = @import("builtin"); |
| 2 | const expect = @import("std").testing.expect; | 3 | const expect = std.testing.expect; |
| 3 | 4 | ||
| 4 | comptime { | 5 | comptime { |
| 5 | if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { | 6 | if (config.arch == config.Arch.x86_64 and config.os == config.Os.linux) { |
test/stage1/behavior/new_stack_call.zig+3| ... | @@ -12,6 +12,9 @@ test "calling a function with a new stack" { | ... | @@ -12,6 +12,9 @@ test "calling a function with a new stack" { |
| 12 | // TODO: https://github.com/ziglang/zig/issues/3338 | 12 | // TODO: https://github.com/ziglang/zig/issues/3338 |
| 13 | return error.SkipZigTest; | 13 | return error.SkipZigTest; |
| 14 | } | 14 | } |
| 15 | if (comptime !std.Target.current.supportsNewStackCall()) { | ||
| 16 | return error.SkipZigTest; | ||
| 17 | } | ||
| 15 | 18 | ||
| 16 | const arg = 1234; | 19 | const arg = 1234; |
| 17 | 20 |