mirror of
https://github.com/ziglang/zig.git
synced 2026-01-20 14:25:16 +00:00
Merge branch 'wasi-run-tests' of https://github.com/fengb/zig into fengb-wasi-run-tests
This commit is contained in:
commit
659c1bdeee
@ -1064,6 +1064,9 @@ pub const LibExeObjStep = struct {
|
||||
/// Uses system QEMU installation to run cross compiled foreign architecture build artifacts.
|
||||
enable_qemu: bool = false,
|
||||
|
||||
/// Uses system Wasmtime installation to run cross compiled wasm/wasi build artifacts.
|
||||
enable_wasmtime: bool = false,
|
||||
|
||||
/// After following the steps in https://github.com/ziglang/zig/wiki/Updating-libc#glibc,
|
||||
/// this will be the directory $glibc-build-dir/install/glibcs
|
||||
/// Given the example of the aarch64 target, this is the directory
|
||||
@ -1863,6 +1866,11 @@ pub const LibExeObjStep = struct {
|
||||
try zig_args.append(bin_name);
|
||||
try zig_args.append("--test-cmd-bin");
|
||||
},
|
||||
.wasmtime => |bin_name| if (self.enable_wasmtime) {
|
||||
try zig_args.append("--test-cmd");
|
||||
try zig_args.append(bin_name);
|
||||
try zig_args.append("--test-cmd-bin");
|
||||
},
|
||||
}
|
||||
for (self.packages.toSliceConst()) |pkg| {
|
||||
zig_args.append("--pkg-begin") catch unreachable;
|
||||
|
||||
@ -213,7 +213,8 @@ pub fn assert(ok: bool) void {
|
||||
|
||||
pub fn panic(comptime format: []const u8, args: ...) noreturn {
|
||||
@setCold(true);
|
||||
const first_trace_addr = @returnAddress();
|
||||
// TODO: remove conditional once wasi / LLVM defines __builtin_return_address
|
||||
const first_trace_addr = if (builtin.os == .wasi) null else @returnAddress();
|
||||
panicExtra(null, first_trace_addr, format, args);
|
||||
}
|
||||
|
||||
|
||||
189
lib/std/heap.zig
189
lib/std/heap.zig
@ -33,11 +33,19 @@ fn cShrink(self: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new
|
||||
|
||||
/// This allocator makes a syscall directly for every allocation and free.
|
||||
/// Thread-safe and lock-free.
|
||||
pub const page_allocator = &page_allocator_state;
|
||||
pub const page_allocator = if (std.Target.current.isWasm())
|
||||
&wasm_page_allocator_state
|
||||
else
|
||||
&page_allocator_state;
|
||||
|
||||
var page_allocator_state = Allocator{
|
||||
.reallocFn = PageAllocator.realloc,
|
||||
.shrinkFn = PageAllocator.shrink,
|
||||
};
|
||||
var wasm_page_allocator_state = Allocator{
|
||||
.reallocFn = WasmPageAllocator.realloc,
|
||||
.shrinkFn = WasmPageAllocator.shrink,
|
||||
};
|
||||
|
||||
/// Deprecated. Use `page_allocator`.
|
||||
pub const direct_allocator = page_allocator;
|
||||
@ -238,6 +246,88 @@ const PageAllocator = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO Exposed LLVM intrinsics is a bug
|
||||
// See: https://github.com/ziglang/zig/issues/2291
|
||||
extern fn @"llvm.wasm.memory.size.i32"(u32) u32;
|
||||
extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32;
|
||||
|
||||
/// TODO: make this re-use freed pages, and cooperate with other callers of these global intrinsics
|
||||
/// by better utilizing the return value of grow()
|
||||
const WasmPageAllocator = struct {
|
||||
var start_ptr: [*]u8 = undefined;
|
||||
var num_pages: usize = 0;
|
||||
var end_index: usize = 0;
|
||||
|
||||
comptime {
|
||||
if (builtin.arch != .wasm32) {
|
||||
@compileError("WasmPageAllocator is only available for wasm32 arch");
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc(allocator: *Allocator, size: usize, alignment: u29) ![]u8 {
|
||||
const addr = @ptrToInt(start_ptr) + end_index;
|
||||
const adjusted_addr = mem.alignForward(addr, alignment);
|
||||
const adjusted_index = end_index + (adjusted_addr - addr);
|
||||
const new_end_index = adjusted_index + size;
|
||||
|
||||
if (new_end_index > num_pages * mem.page_size) {
|
||||
const required_memory = new_end_index - (num_pages * mem.page_size);
|
||||
|
||||
var num_pages: usize = required_memory / mem.page_size;
|
||||
if (required_memory % mem.page_size != 0) {
|
||||
num_pages += 1;
|
||||
}
|
||||
|
||||
const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, num_pages));
|
||||
if (prev_page == -1) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
|
||||
num_pages += num_pages;
|
||||
}
|
||||
|
||||
const result = start_ptr[adjusted_index..new_end_index];
|
||||
end_index = new_end_index;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if memory is the last "item" and is aligned correctly
|
||||
fn is_last_item(memory: []u8, alignment: u29) bool {
|
||||
return memory.ptr == start_ptr + end_index - memory.len and mem.alignForward(@ptrToInt(memory.ptr), alignment) == @ptrToInt(memory.ptr);
|
||||
}
|
||||
|
||||
fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
|
||||
// Initialize start_ptr at the first realloc
|
||||
if (num_pages == 0) {
|
||||
start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size);
|
||||
}
|
||||
|
||||
if (is_last_item(old_mem, new_align)) {
|
||||
const start_index = end_index - old_mem.len;
|
||||
const new_end_index = start_index + new_size;
|
||||
|
||||
if (new_end_index > num_pages * mem.page_size) {
|
||||
_ = try alloc(allocator, new_end_index - end_index, new_align);
|
||||
}
|
||||
const result = start_ptr[start_index..new_end_index];
|
||||
|
||||
end_index = new_end_index;
|
||||
return result;
|
||||
} else if (new_size <= old_mem.len and new_align <= old_align) {
|
||||
return error.OutOfMemory;
|
||||
} else {
|
||||
const result = try alloc(allocator, new_size, new_align);
|
||||
mem.copy(u8, result, old_mem);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
|
||||
return old_mem[0..new_size];
|
||||
}
|
||||
};
|
||||
|
||||
pub const HeapAllocator = switch (builtin.os) {
|
||||
.windows => struct {
|
||||
allocator: Allocator,
|
||||
@ -487,103 +577,6 @@ pub const FixedBufferAllocator = struct {
|
||||
}
|
||||
};
|
||||
|
||||
// TODO Exposed LLVM intrinsics is a bug
|
||||
// See: https://github.com/ziglang/zig/issues/2291
|
||||
extern fn @"llvm.wasm.memory.size.i32"(u32) u32;
|
||||
extern fn @"llvm.wasm.memory.grow.i32"(u32, u32) i32;
|
||||
|
||||
pub const wasm_allocator = &wasm_allocator_state.allocator;
|
||||
var wasm_allocator_state = WasmAllocator{
|
||||
.allocator = Allocator{
|
||||
.reallocFn = WasmAllocator.realloc,
|
||||
.shrinkFn = WasmAllocator.shrink,
|
||||
},
|
||||
.start_ptr = undefined,
|
||||
.num_pages = 0,
|
||||
.end_index = 0,
|
||||
};
|
||||
|
||||
const WasmAllocator = struct {
|
||||
allocator: Allocator,
|
||||
start_ptr: [*]u8,
|
||||
num_pages: usize,
|
||||
end_index: usize,
|
||||
|
||||
comptime {
|
||||
if (builtin.arch != .wasm32) {
|
||||
@compileError("WasmAllocator is only available for wasm32 arch");
|
||||
}
|
||||
}
|
||||
|
||||
fn alloc(allocator: *Allocator, size: usize, alignment: u29) ![]u8 {
|
||||
const self = @fieldParentPtr(WasmAllocator, "allocator", allocator);
|
||||
|
||||
const addr = @ptrToInt(self.start_ptr) + self.end_index;
|
||||
const adjusted_addr = mem.alignForward(addr, alignment);
|
||||
const adjusted_index = self.end_index + (adjusted_addr - addr);
|
||||
const new_end_index = adjusted_index + size;
|
||||
|
||||
if (new_end_index > self.num_pages * mem.page_size) {
|
||||
const required_memory = new_end_index - (self.num_pages * mem.page_size);
|
||||
|
||||
var num_pages: usize = required_memory / mem.page_size;
|
||||
if (required_memory % mem.page_size != 0) {
|
||||
num_pages += 1;
|
||||
}
|
||||
|
||||
const prev_page = @"llvm.wasm.memory.grow.i32"(0, @intCast(u32, num_pages));
|
||||
if (prev_page == -1) {
|
||||
return error.OutOfMemory;
|
||||
}
|
||||
|
||||
self.num_pages += num_pages;
|
||||
}
|
||||
|
||||
const result = self.start_ptr[adjusted_index..new_end_index];
|
||||
self.end_index = new_end_index;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// Check if memory is the last "item" and is aligned correctly
|
||||
fn is_last_item(allocator: *Allocator, memory: []u8, alignment: u29) bool {
|
||||
const self = @fieldParentPtr(WasmAllocator, "allocator", allocator);
|
||||
return memory.ptr == self.start_ptr + self.end_index - memory.len and mem.alignForward(@ptrToInt(memory.ptr), alignment) == @ptrToInt(memory.ptr);
|
||||
}
|
||||
|
||||
fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
|
||||
const self = @fieldParentPtr(WasmAllocator, "allocator", allocator);
|
||||
|
||||
// Initialize start_ptr at the first realloc
|
||||
if (self.num_pages == 0) {
|
||||
self.start_ptr = @intToPtr([*]u8, @intCast(usize, @"llvm.wasm.memory.size.i32"(0)) * mem.page_size);
|
||||
}
|
||||
|
||||
if (is_last_item(allocator, old_mem, new_align)) {
|
||||
const start_index = self.end_index - old_mem.len;
|
||||
const new_end_index = start_index + new_size;
|
||||
|
||||
if (new_end_index > self.num_pages * mem.page_size) {
|
||||
_ = try alloc(allocator, new_end_index - self.end_index, new_align);
|
||||
}
|
||||
const result = self.start_ptr[start_index..new_end_index];
|
||||
|
||||
self.end_index = new_end_index;
|
||||
return result;
|
||||
} else if (new_size <= old_mem.len and new_align <= old_align) {
|
||||
return error.OutOfMemory;
|
||||
} else {
|
||||
const result = try alloc(allocator, new_size, new_align);
|
||||
mem.copy(u8, result, old_mem);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
|
||||
return old_mem[0..new_size];
|
||||
}
|
||||
};
|
||||
|
||||
pub const ThreadSafeFixedBufferAllocator = blk: {
|
||||
if (builtin.single_threaded) {
|
||||
break :blk FixedBufferAllocator;
|
||||
|
||||
@ -1527,7 +1527,7 @@ pub fn isatty(handle: fd_t) bool {
|
||||
return system.isatty(handle) != 0;
|
||||
}
|
||||
if (builtin.os == .wasi) {
|
||||
@compileError("TODO implement std.os.isatty for WASI");
|
||||
return system.isatty(handle);
|
||||
}
|
||||
if (builtin.os == .linux) {
|
||||
var wsz: linux.winsize = undefined;
|
||||
|
||||
@ -138,7 +138,7 @@ pub const FDFLAG_NONBLOCK: fdflags_t = 0x0004;
|
||||
pub const FDFLAG_RSYNC: fdflags_t = 0x0008;
|
||||
pub const FDFLAG_SYNC: fdflags_t = 0x0010;
|
||||
|
||||
const fdstat_t = extern struct {
|
||||
pub const fdstat_t = extern struct {
|
||||
fs_filetype: filetype_t,
|
||||
fs_flags: fdflags_t,
|
||||
fs_rights_base: rights_t,
|
||||
@ -298,6 +298,7 @@ pub const subscription_t = extern struct {
|
||||
};
|
||||
|
||||
pub const timestamp_t = u64;
|
||||
pub const time_t = i64; // match https://github.com/CraneStation/wasi-libc
|
||||
|
||||
pub const userdata_t = u64;
|
||||
|
||||
@ -305,3 +306,8 @@ pub const whence_t = u8;
|
||||
pub const WHENCE_CUR: whence_t = 0;
|
||||
pub const WHENCE_END: whence_t = 1;
|
||||
pub const WHENCE_SET: whence_t = 2;
|
||||
|
||||
pub const timespec = extern struct {
|
||||
tv_sec: time_t,
|
||||
tv_nsec: isize,
|
||||
};
|
||||
|
||||
@ -76,3 +76,54 @@ pub extern "wasi_unstable" fn sched_yield() errno_t;
|
||||
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;
|
||||
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;
|
||||
pub extern "wasi_unstable" fn sock_shutdown(sock: fd_t, how: sdflags_t) errno_t;
|
||||
|
||||
/// Get the errno from a syscall return value, or 0 for no error.
|
||||
pub fn getErrno(r: usize) usize {
|
||||
const signed_r = @bitCast(isize, r);
|
||||
return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
|
||||
}
|
||||
|
||||
pub fn clock_getres(clock_id: i32, res: *timespec) errno_t {
|
||||
var ts: timestamp_t = undefined;
|
||||
const err = clock_res_get(@bitCast(u32, clock_id), &ts);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
res.* = .{
|
||||
.tv_sec = @intCast(i64, ts / std.time.ns_per_s),
|
||||
.tv_nsec = @intCast(isize, ts % std.time.ns_per_s),
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn clock_gettime(clock_id: i32, tp: *timespec) errno_t {
|
||||
var ts: timestamp_t = undefined;
|
||||
const err = clock_time_get(@bitCast(u32, clock_id), 1, &ts);
|
||||
if (err != 0) {
|
||||
return err;
|
||||
}
|
||||
tp.* = .{
|
||||
.tv_sec = @intCast(i64, ts / std.time.ns_per_s),
|
||||
.tv_nsec = @intCast(isize, ts % std.time.ns_per_s),
|
||||
};
|
||||
return 0;
|
||||
}
|
||||
|
||||
pub fn isatty(fd: fd_t) bool {
|
||||
var statbuf: fdstat_t = undefined;
|
||||
const err = fd_fdstat_get(fd, &statbuf);
|
||||
if (err != 0) {
|
||||
// errno = err;
|
||||
return false;
|
||||
}
|
||||
|
||||
// A tty is a character device that we can't seek or tell on.
|
||||
if (statbuf.fs_filetype != FILETYPE_CHARACTER_DEVICE or
|
||||
(statbuf.fs_rights_base & (RIGHT_FD_SEEK | RIGHT_FD_TELL)) != 0)
|
||||
{
|
||||
// errno = ENOTTY;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -611,6 +611,7 @@ pub const Target = union(enum) {
|
||||
native,
|
||||
qemu: []const u8,
|
||||
wine: []const u8,
|
||||
wasmtime: []const u8,
|
||||
unavailable,
|
||||
};
|
||||
|
||||
@ -649,6 +650,13 @@ pub const Target = union(enum) {
|
||||
}
|
||||
}
|
||||
|
||||
if (self.isWasm()) {
|
||||
switch (self.getArchPtrBitWidth()) {
|
||||
32 => return Executor{ .wasmtime = "wasmtime" },
|
||||
else => return .unavailable,
|
||||
}
|
||||
}
|
||||
|
||||
return .unavailable;
|
||||
}
|
||||
};
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user