authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-12 16:41:20-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-05-12 16:41:20-07:00
logc9cc09a3bfb45d93b84577238047cd69ef0a7d88
tree1686cda92ae0c5d9ae55c02e7755c55d4e6f3c18
parent71afc3088009944fcd8339ac71e69a0b77a781ab
parent40a47eae65b918866abc9d745f89d837f6a1e591

Merge remote-tracking branch 'origin/master' into stage2-whole-file-astgen

Conflicts: * lib/std/os/linux.zig * lib/std/os/windows/bits.zig * src/Module.zig * src/Sema.zig * test/stage2/test.zig Mainly I wanted Jakub's new macOS code for respecting stack size, since we now depend on it for debug builds able to pass one of the test cases for recursive comptime function calls with `@setEvalBranchQuota`. The conflicts were all trivial.

72 files changed, 5411 insertions(+), 1378 deletions(-)

ci/azure/linux_script+5-3
...@@ -9,7 +9,7 @@ sudo apt-get install -y cmake s3cmd tidy...@@ -9,7 +9,7 @@ sudo apt-get install -y cmake s3cmd tidy
9ZIGDIR="$(pwd)"9ZIGDIR="$(pwd)"
10ARCH="$(uname -m)"10ARCH="$(uname -m)"
11TARGET="$ARCH-linux-musl"11TARGET="$ARCH-linux-musl"
12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.1939+5a3ea9bec"12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.2168+2d1196773"
13PREFIX="$HOME/$CACHE_BASENAME"13PREFIX="$HOME/$CACHE_BASENAME"
14MCPU="baseline"14MCPU="baseline"
15JOBS="-j$(nproc)"15JOBS="-j$(nproc)"
...@@ -25,8 +25,10 @@ wget -nv "https://ziglang.org/deps/$QEMUBASE.tar.xz"...@@ -25,8 +25,10 @@ wget -nv "https://ziglang.org/deps/$QEMUBASE.tar.xz"
25tar xf "$QEMUBASE.tar.xz"25tar xf "$QEMUBASE.tar.xz"
26export PATH="$(pwd)/$QEMUBASE/bin:$PATH"26export PATH="$(pwd)/$QEMUBASE/bin:$PATH"
2727
28WASMTIME="wasmtime-v0.20.0-x86_64-linux"28# Bump to v0.23 once this issue is resolved:
29wget -nv "https://github.com/bytecodealliance/wasmtime/releases/download/v0.20.0/$WASMTIME.tar.xz"29# https://github.com/ziglang/zig/issues/8742
30WASMTIME="wasmtime-v0.22.1-x86_64-linux"
31wget -nv "https://github.com/bytecodealliance/wasmtime/releases/download/v0.22.1/$WASMTIME.tar.xz"
30tar xf "$WASMTIME.tar.xz"32tar xf "$WASMTIME.tar.xz"
31export PATH="$(pwd)/$WASMTIME:$PATH"33export PATH="$(pwd)/$WASMTIME:$PATH"
3234
ci/azure/macos_arm64_script+60-60
...@@ -3,24 +3,31 @@...@@ -3,24 +3,31 @@
3set -x3set -x
4set -e4set -e
55
6brew update && brew install s3cmd ninja gnu-tar6brew update && brew install s3cmd
77
8ZIGDIR="$(pwd)"8ZIGDIR="$(pwd)"
9
10HOST_ARCH="x86_64"
11HOST_TARGET="$HOST_ARCH-macos-gnu"
12HOST_MCPU="baseline"
13HOST_CACHE_BASENAME="zig+llvm+lld+clang-$HOST_TARGET-0.8.0-dev.2168+2d1196773"
14HOST_PREFIX="$HOME/$HOST_CACHE_BASENAME"
15
9ARCH="aarch64"16ARCH="aarch64"
10# {product}-{os}{sdk_version}-{arch}-{llvm_version}-{cmake_build_type}17TARGET="$ARCH-macos-gnu"
11CACHE_HOST_BASENAME="ci-llvm-macos10.15-x86_64-12.0.0.1-release"18MCPU="cyclone"
12CACHE_ARM64_BASENAME="ci-llvm-macos11.0-arm64-12.0.0.1-release"19CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.2168+2d1196773"
13PREFIX_HOST="$HOME/$CACHE_HOST_BASENAME"20PREFIX="$HOME/$CACHE_BASENAME"
14PREFIX_ARM64="$HOME/$CACHE_ARM64_BASENAME"21
15JOBS="-j2"22JOBS="-j2"
1623
17rm -rf $PREFIX24rm -rf $HOST_PREFIX $PREFIX
18cd $HOME25cd $HOME
19wget -nv "https://ziglang.org/deps/$CACHE_HOST_BASENAME.tar.xz"
20wget -nv "https://ziglang.org/deps/$CACHE_ARM64_BASENAME.tar.xz"
2126
22gtar xf "$CACHE_HOST_BASENAME.tar.xz"27wget -nv "https://ziglang.org/deps/$HOST_CACHE_BASENAME.tar.xz"
23gtar xf "$CACHE_ARM64_BASENAME.tar.xz"28wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
29tar xf "$HOST_CACHE_BASENAME.tar.xz"
30tar xf "$CACHE_BASENAME.tar.xz"
2431
25cd $ZIGDIR32cd $ZIGDIR
2633
...@@ -30,83 +37,75 @@ git config core.abbrev 9...@@ -30,83 +37,75 @@ git config core.abbrev 9
30git fetch --unshallow || true37git fetch --unshallow || true
31git fetch --tags38git fetch --tags
3239
33# Select xcode: latest version found on vmImage macOS-10.15 .40# Build host zig compiler in debug so that we can get the
34DEVELOPER_DIR=/Applications/Xcode_12.4.app41# current version when packaging
3542
36export ZIG_LOCAL_CACHE_DIR="$ZIGDIR/zig-cache"43ZIG="$HOST_PREFIX/bin/zig"
37export ZIG_GLOBAL_CACHE_DIR="$ZIGDIR/zig-cache"
3844
39# Build zig for host and use `Debug` type to make builds a little faster.45export CC="$ZIG cc -target $HOST_TARGET -mcpu=$HOST_MCPU"
46export CXX="$ZIG c++ -target $HOST_TARGET -mcpu=$HOST_MCPU"
4047
41cd $ZIGDIR
42mkdir build.host48mkdir build.host
43cd build.host49cd build.host
44cmake -G "Ninja" .. \50cmake .. \
45 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \51 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
46 -DCMAKE_PREFIX_PATH="$PREFIX_HOST" \52 -DCMAKE_PREFIX_PATH="$HOST_PREFIX" \
47 -DCMAKE_BUILD_TYPE="Debug" \53 -DCMAKE_BUILD_TYPE=Debug \
48 -DZIG_STATIC="OFF"54 -DZIG_TARGET_TRIPLE="$HOST_TARGET" \
4955 -DZIG_TARGET_MCPU="$HOST_MCPU" \
50# Build but do not install.56 -DZIG_STATIC=ON
51ninja $JOBS
5257
53ZIG_EXE="$ZIGDIR/build.host/zig"58unset CC
59unset CXX
5460
55# Build zig for arm64 target.61make $JOBS install
56# - use `Release` type for published tarballs
57# - ad-hoc codesign with linker
58# - note: apple quarantine of downloads (eg. via safari) still apply
5962
63# Build zig compiler cross-compiled for arm64
60cd $ZIGDIR64cd $ZIGDIR
61mkdir build.arm6465
62cd build.arm6466ZIG="$ZIGDIR/build.host/release/bin/zig"
63cmake -G "Ninja" .. \67
68export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
69export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
70
71mkdir build
72cd build
73cmake .. \
64 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \74 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
65 -DCMAKE_PREFIX_PATH="$PREFIX_ARM64" \75 -DCMAKE_PREFIX_PATH="$PREFIX" \
66 -DCMAKE_BUILD_TYPE="Release" \76 -DCMAKE_BUILD_TYPE=Release \
67 -DCMAKE_CROSSCOMPILING="True" \77 -DZIG_TARGET_TRIPLE="$TARGET" \
68 -DCMAKE_SYSTEM_NAME="Darwin" \78 -DZIG_TARGET_MCPU="$MCPU" \
69 -DCMAKE_C_FLAGS="-arch arm64" \79 -DZIG_EXECUTABLE="$ZIG" \
70 -DCMAKE_CXX_FLAGS="-arch arm64" \80 -DZIG_STATIC=ON
71 -DCMAKE_EXE_LINKER_FLAGS="-lz -Xlinker -adhoc_codesign" \81
72 -DZIG_USE_LLVM_CONFIG="OFF" \82unset CC
73 -DZIG_EXECUTABLE="$ZIG_EXE" \83unset CXX
74 -DZIG_TARGET_TRIPLE="${ARCH}-macos" \84
75 -DZIG_STATIC="OFF"85make $JOBS install
76
77ninja $JOBS install
78
79# Disable test because binary is foreign arch.
80#release/bin/zig build test
8186
82if [ "${BUILD_REASON}" != "PullRequest" ]; then87if [ "${BUILD_REASON}" != "PullRequest" ]; then
83 mv ../LICENSE release/88 mv ../LICENSE release/
8489
85 # We do not run test suite but still need langref.90 # We do not run test suite but still need langref.
86 mkdir -p release/docs91 mkdir -p release/docs
87 $ZIG_EXE run ../doc/docgen.zig -- $ZIG_EXE ../doc/langref.html.in release/docs/langref.html92 $ZIG run ../doc/docgen.zig -- $ZIG ../doc/langref.html.in release/docs/langref.html
8893
89 # Produce the experimental std lib documentation.94 # Produce the experimental std lib documentation.
90 mkdir -p release/docs/std95 mkdir -p release/docs/std
91 $ZIG_EXE test ../lib/std/std.zig \96 $ZIG test ../lib/std/std.zig \
92 --override-lib-dir ../lib \97 --override-lib-dir ../lib \
93 -femit-docs=release/docs/std \98 -femit-docs=release/docs/std \
94 -fno-emit-bin99 -fno-emit-bin
95100
96 # Remove the unnecessary bin dir in $prefix/bin/zig
97 mv release/bin/zig release/101 mv release/bin/zig release/
98 rmdir release/bin102 rmdir release/bin
99103
100 # Remove the unnecessary zig dir in $prefix/lib/zig/std/std.zig104 VERSION=$(../build.host/release/bin/zig version)
101 mv release/lib/zig release/lib2
102 rmdir release/lib
103 mv release/lib2 release/lib
104
105 VERSION=$($ZIG_EXE version)
106 DIRNAME="zig-macos-$ARCH-$VERSION"105 DIRNAME="zig-macos-$ARCH-$VERSION"
107 TARBALL="$DIRNAME.tar.xz"106 TARBALL="$DIRNAME.tar.xz"
108 gtar cJf "$TARBALL" release/ --owner=root --sort=name --transform="s,^release,${DIRNAME},"107 mv release "$DIRNAME"
109 ln "$TARBALL" "$BUILD_ARTIFACTSTAGINGDIRECTORY/."108 tar cfJ "$TARBALL" "$DIRNAME"
110109
111 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"110 mv "$DOWNLOADSECUREFILE_SECUREFILEPATH" "$HOME/.s3cfg"
112 s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/111 s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/
...@@ -114,12 +113,13 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then...@@ -114,12 +113,13 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
114 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)113 SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
115 BYTESIZE=$(wc -c < $TARBALL)114 BYTESIZE=$(wc -c < $TARBALL)
116115
117 JSONFILE="tarball.json"116 JSONFILE="macos-$GITBRANCH.json"
118 touch $JSONFILE117 touch $JSONFILE
119 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE118 echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE
120 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE119 echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE
121 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE120 echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE
122121
122 s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE"
123 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"123 s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$ARCH-macos-$VERSION.json"
124124
125 # `set -x` causes these variables to be mangled.125 # `set -x` causes these variables to be mangled.
ci/azure/macos_script+9-10
...@@ -7,21 +7,21 @@ brew update && brew install s3cmd...@@ -7,21 +7,21 @@ brew update && brew install s3cmd
77
8ZIGDIR="$(pwd)"8ZIGDIR="$(pwd)"
9ARCH="x86_64"9ARCH="x86_64"
10CACHE_BASENAME="zig+llvm+lld+clang-$ARCH-macos-gnu-0.8.0-dev.1939+5a3ea9bec"10TARGET="$ARCH-macos-gnu"
11MCPU="baseline"
12CACHE_BASENAME="zig+llvm+lld+clang-$TARGET-0.8.0-dev.2168+2d1196773"
11PREFIX="$HOME/$CACHE_BASENAME"13PREFIX="$HOME/$CACHE_BASENAME"
12JOBS="-j2"14JOBS="-j2"
1315
14rm -rf $PREFIX16rm -rf $PREFIX
15cd $HOME17cd $HOME
18
16wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"19wget -nv "https://ziglang.org/deps/$CACHE_BASENAME.tar.xz"
17tar xf "$CACHE_BASENAME.tar.xz"20tar xf "$CACHE_BASENAME.tar.xz"
1821
19ZIG="$PREFIX/bin/zig"22ZIG="$PREFIX/bin/zig"
20NATIVE_LIBC_TXT="$HOME/native_libc.txt"23export CC="$ZIG cc -target $TARGET -mcpu=$MCPU"
21$ZIG libc >"$NATIVE_LIBC_TXT"24export CXX="$ZIG c++ -target $TARGET -mcpu=$MCPU"
22export ZIG_LIBC="$NATIVE_LIBC_TXT"
23export CC="$ZIG cc"
24export CXX="$ZIG c++"
2525
26cd $ZIGDIR26cd $ZIGDIR
2727
...@@ -37,22 +37,21 @@ cmake .. \...@@ -37,22 +37,21 @@ cmake .. \
37 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \37 -DCMAKE_INSTALL_PREFIX="$(pwd)/release" \
38 -DCMAKE_PREFIX_PATH="$PREFIX" \38 -DCMAKE_PREFIX_PATH="$PREFIX" \
39 -DCMAKE_BUILD_TYPE=Release \39 -DCMAKE_BUILD_TYPE=Release \
40 -DZIG_TARGET_TRIPLE="$ARCH-native-gnu" \40 -DZIG_TARGET_TRIPLE="$TARGET" \
41 -DZIG_TARGET_MCPU="baseline" \41 -DZIG_TARGET_MCPU="$MCPU" \
42 -DZIG_STATIC=ON42 -DZIG_STATIC=ON
4343
44# Now cmake will use zig as the C/C++ compiler. We reset the environment variables44# Now cmake will use zig as the C/C++ compiler. We reset the environment variables
45# so that installation and testing do not get affected by them.45# so that installation and testing do not get affected by them.
46unset CC46unset CC
47unset CXX47unset CXX
48unset ZIG_LIBC
4948
50make $JOBS install49make $JOBS install
5150
52# Here we rebuild zig but this time using the Zig binary we just now produced to51# Here we rebuild zig but this time using the Zig binary we just now produced to
53# build zig1.o rather than relying on the one built with stage0. See52# build zig1.o rather than relying on the one built with stage0. See
54# https://github.com/ziglang/zig/issues/6830 for more details.53# https://github.com/ziglang/zig/issues/6830 for more details.
55cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig" -DZIG_TARGET_MCPU="x86_64_v2"54cmake .. -DZIG_EXECUTABLE="$(pwd)/release/bin/zig"
56make $JOBS install55make $JOBS install
5756
58for step in test-toolchain test-std docs; do57for step in test-toolchain test-std docs; do
ci/azure/pipelines.yml+1-7
...@@ -2,9 +2,7 @@ jobs:...@@ -2,9 +2,7 @@ jobs:
2- job: BuildMacOS2- job: BuildMacOS
3 pool:3 pool:
4 vmImage: 'macOS-10.15'4 vmImage: 'macOS-10.15'
5
6 timeoutInMinutes: 3605 timeoutInMinutes: 360
7
8 steps:6 steps:
9 - task: DownloadSecureFile@17 - task: DownloadSecureFile@1
10 inputs:8 inputs:
...@@ -15,9 +13,7 @@ jobs:...@@ -15,9 +13,7 @@ jobs:
15- job: BuildMacOS_arm6413- job: BuildMacOS_arm64
16 pool:14 pool:
17 vmImage: 'macOS-10.15'15 vmImage: 'macOS-10.15'
1816 timeoutInMinutes: 180
19 timeoutInMinutes: 60
20
21 steps:17 steps:
22 - task: DownloadSecureFile@118 - task: DownloadSecureFile@1
23 inputs:19 inputs:
...@@ -28,9 +24,7 @@ jobs:...@@ -28,9 +24,7 @@ jobs:
28- job: BuildLinux24- job: BuildLinux
29 pool:25 pool:
30 vmImage: 'ubuntu-18.04'26 vmImage: 'ubuntu-18.04'
31
32 timeoutInMinutes: 36027 timeoutInMinutes: 360
33
34 steps:28 steps:
35 - task: DownloadSecureFile@129 - task: DownloadSecureFile@1
36 inputs:30 inputs:
lib/libc/glibc/sysdeps/i386/sysdep.h+3-2
...@@ -61,7 +61,7 @@ lose: SYSCALL_PIC_SETUP \...@@ -61,7 +61,7 @@ lose: SYSCALL_PIC_SETUP \
6161
62# define SETUP_PIC_REG(reg) \62# define SETUP_PIC_REG(reg) \
63 .ifndef GET_PC_THUNK(reg); \63 .ifndef GET_PC_THUNK(reg); \
64 .section .gnu.linkonce.t.GET_PC_THUNK(reg),"ax",@progbits; \64 .section .text.GET_PC_THUNK(reg),"axG",@progbits,GET_PC_THUNK(reg),comdat; \
65 .globl GET_PC_THUNK(reg); \65 .globl GET_PC_THUNK(reg); \
66 .hidden GET_PC_THUNK(reg); \66 .hidden GET_PC_THUNK(reg); \
67 .p2align 4; \67 .p2align 4; \
...@@ -97,8 +97,9 @@ GET_PC_THUNK(reg): \...@@ -97,8 +97,9 @@ GET_PC_THUNK(reg): \
9797
98# define SETUP_PIC_REG_STR(reg) \98# define SETUP_PIC_REG_STR(reg) \
99 ".ifndef " GET_PC_THUNK_STR (reg) "\n" \99 ".ifndef " GET_PC_THUNK_STR (reg) "\n" \
100 ".section .gnu.linkonce.t." GET_PC_THUNK_STR (reg) ",\"ax\",@progbits\n" \100 "section .text." GET_PC_THUNK_STR (reg) ",\"axG\",@progbits," \
101 ".globl " GET_PC_THUNK_STR (reg) "\n" \101 ".globl " GET_PC_THUNK_STR (reg) "\n" \
102 GET_PC_THUNK_STR (reg) ",comdat\n" \
102 ".hidden " GET_PC_THUNK_STR (reg) "\n" \103 ".hidden " GET_PC_THUNK_STR (reg) "\n" \
103 ".p2align 4\n" \104 ".p2align 4\n" \
104 ".type " GET_PC_THUNK_STR (reg) ",@function\n" \105 ".type " GET_PC_THUNK_STR (reg) ",@function\n" \
lib/std/array_hash_map.zig+16-4
...@@ -18,11 +18,11 @@ const builtin = std.builtin;...@@ -18,11 +18,11 @@ const builtin = std.builtin;
18const hash_map = @This();18const hash_map = @This();
1919
20pub fn AutoArrayHashMap(comptime K: type, comptime V: type) type {20pub fn AutoArrayHashMap(comptime K: type, comptime V: type) type {
21 return ArrayHashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), autoEqlIsCheap(K));21 return ArrayHashMap(K, V, getAutoHashFn(K), getAutoEqlFn(K), !autoEqlIsCheap(K));
22}22}
2323
24pub fn AutoArrayHashMapUnmanaged(comptime K: type, comptime V: type) type {24pub fn AutoArrayHashMapUnmanaged(comptime K: type, comptime V: type) type {
25 return ArrayHashMapUnmanaged(K, V, getAutoHashFn(K), getAutoEqlFn(K), autoEqlIsCheap(K));25 return ArrayHashMapUnmanaged(K, V, getAutoHashFn(K), getAutoEqlFn(K), !autoEqlIsCheap(K));
26}26}
2727
28/// Builtin hashmap for strings as keys.28/// Builtin hashmap for strings as keys.
...@@ -1318,7 +1318,7 @@ test "reIndex" {...@@ -1318,7 +1318,7 @@ test "reIndex" {
1318 try al.append(std.testing.allocator, .{1318 try al.append(std.testing.allocator, .{
1319 .key = i,1319 .key = i,
1320 .value = i * 10,1320 .value = i * 10,
1321 .hash = hash(i),1321 .hash = {},
1322 });1322 });
1323 }1323 }
13241324
...@@ -1345,7 +1345,7 @@ test "fromOwnedArrayList" {...@@ -1345,7 +1345,7 @@ test "fromOwnedArrayList" {
1345 try al.append(std.testing.allocator, .{1345 try al.append(std.testing.allocator, .{
1346 .key = i,1346 .key = i,
1347 .value = i * 10,1347 .value = i * 10,
1348 .hash = hash(i),1348 .hash = {},
1349 });1349 });
1350 }1350 }
13511351
...@@ -1362,6 +1362,18 @@ test "fromOwnedArrayList" {...@@ -1362,6 +1362,18 @@ test "fromOwnedArrayList" {
1362 }1362 }
1363}1363}
13641364
1365test "auto store_hash" {
1366 const HasCheapEql = AutoArrayHashMap(i32, i32);
1367 const HasExpensiveEql = AutoArrayHashMap([32]i32, i32);
1368 try testing.expect(meta.fieldInfo(HasCheapEql.Entry, .hash).field_type == void);
1369 try testing.expect(meta.fieldInfo(HasExpensiveEql.Entry, .hash).field_type != void);
1370
1371 const HasCheapEqlUn = AutoArrayHashMapUnmanaged(i32, i32);
1372 const HasExpensiveEqlUn = AutoArrayHashMapUnmanaged([32]i32, i32);
1373 try testing.expect(meta.fieldInfo(HasCheapEqlUn.Entry, .hash).field_type == void);
1374 try testing.expect(meta.fieldInfo(HasExpensiveEqlUn.Entry, .hash).field_type != void);
1375}
1376
1365pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {1377pub fn getHashPtrAddrFn(comptime K: type) (fn (K) u32) {
1366 return struct {1378 return struct {
1367 fn hash(key: K) u32 {1379 fn hash(key: K) u32 {
lib/std/c.zig+6-5
...@@ -89,13 +89,13 @@ pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int;...@@ -89,13 +89,13 @@ pub extern "c" fn ftruncate(fd: c_int, length: off_t) c_int;
89pub extern "c" fn raise(sig: c_int) c_int;89pub extern "c" fn raise(sig: c_int) c_int;
90pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;90pub extern "c" fn read(fd: fd_t, buf: [*]u8, nbyte: usize) isize;
91pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize;91pub extern "c" fn readv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint) isize;
92pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: u64) isize;92pub extern "c" fn pread(fd: fd_t, buf: [*]u8, nbyte: usize, offset: off_t) isize;
93pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: u64) isize;93pub extern "c" fn preadv(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: off_t) isize;
94pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) isize;94pub extern "c" fn writev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint) isize;
95pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: u64) isize;95pub extern "c" fn pwritev(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: off_t) isize;
96pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;96pub extern "c" fn write(fd: fd_t, buf: [*]const u8, nbyte: usize) isize;
97pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: u64) isize;97pub extern "c" fn pwrite(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: off_t) isize;
98pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: u64) *c_void;98pub extern "c" fn mmap(addr: ?*align(page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: off_t) *c_void;
99pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;99pub extern "c" fn munmap(addr: *align(page_size) c_void, len: usize) c_int;
100pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;100pub extern "c" fn mprotect(addr: *align(page_size) c_void, len: usize, prot: c_uint) c_int;
101pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;101pub extern "c" fn link(oldpath: [*:0]const u8, newpath: [*:0]const u8, flags: c_int) c_int;
...@@ -151,6 +151,7 @@ pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: soc...@@ -151,6 +151,7 @@ pub extern "c" fn bind(socket: fd_t, address: ?*const sockaddr, address_len: soc
151pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;151pub extern "c" fn socketpair(domain: c_uint, sock_type: c_uint, protocol: c_uint, sv: *[2]fd_t) c_int;
152pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;152pub extern "c" fn listen(sockfd: fd_t, backlog: c_uint) c_int;
153pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;153pub extern "c" fn getsockname(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
154pub extern "c" fn getpeername(sockfd: fd_t, noalias addr: *sockaddr, noalias addrlen: *socklen_t) c_int;
154pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;155pub extern "c" fn connect(sockfd: fd_t, sock_addr: *const sockaddr, addrlen: socklen_t) c_int;
155pub extern "c" fn accept(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t) c_int;156pub extern "c" fn accept(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t) c_int;
156pub extern "c" fn accept4(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t, flags: c_uint) c_int;157pub extern "c" fn accept4(sockfd: fd_t, noalias addr: ?*sockaddr, noalias addrlen: ?*socklen_t, flags: c_uint) c_int;
lib/std/c/linux.zig+17-2
...@@ -63,6 +63,23 @@ pub const EAI = enum(c_int) {...@@ -63,6 +63,23 @@ pub const EAI = enum(c_int) {
63 _,63 _,
64};64};
6565
66pub extern "c" fn fallocate64(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
67pub extern "c" fn fopen64(noalias filename: [*:0]const u8, noalias modes: [*:0]const u8) ?*FILE;
68pub extern "c" fn fstat64(fd: fd_t, buf: *libc_stat) c_int;
69pub extern "c" fn fstatat64(dirfd: fd_t, path: [*:0]const u8, stat_buf: *libc_stat, flags: u32) c_int;
70pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
71pub extern "c" fn getrlimit64(resource: rlimit_resource, rlim: *rlimit) c_int;
72pub extern "c" fn lseek64(fd: fd_t, offset: i64, whence: c_int) i64;
73pub extern "c" fn mmap64(addr: ?*align(std.mem.page_size) c_void, len: usize, prot: c_uint, flags: c_uint, fd: fd_t, offset: i64) *c_void;
74pub extern "c" fn open64(path: [*:0]const u8, oflag: c_uint, ...) c_int;
75pub extern "c" fn openat64(fd: c_int, path: [*:0]const u8, oflag: c_uint, ...) c_int;
76pub extern "c" fn pread64(fd: fd_t, buf: [*]u8, nbyte: usize, offset: i64) isize;
77pub extern "c" fn preadv64(fd: c_int, iov: [*]const iovec, iovcnt: c_uint, offset: i64) isize;
78pub extern "c" fn pwrite64(fd: fd_t, buf: [*]const u8, nbyte: usize, offset: i64) isize;
79pub extern "c" fn pwritev64(fd: c_int, iov: [*]const iovec_const, iovcnt: c_uint, offset: i64) isize;
80pub extern "c" fn sendfile64(out_fd: fd_t, in_fd: fd_t, offset: ?*i64, count: usize) isize;
81pub extern "c" fn setrlimit64(resource: rlimit_resource, rlim: *const rlimit) c_int;
82
66pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;83pub extern "c" fn getrandom(buf_ptr: [*]u8, buf_len: usize, flags: c_uint) isize;
67pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;84pub extern "c" fn sched_getaffinity(pid: c_int, size: usize, set: *cpu_set_t) c_int;
68pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;85pub extern "c" fn eventfd(initval: c_uint, flags: c_uint) c_int;
...@@ -92,8 +109,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;...@@ -92,8 +109,6 @@ pub extern "c" fn pipe2(fds: *[2]fd_t, flags: u32) c_int;
92109
93pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;110pub extern "c" fn fallocate(fd: fd_t, mode: c_int, offset: off_t, len: off_t) c_int;
94111
95pub extern "c" fn ftruncate64(fd: c_int, length: off_t) c_int;
96
97pub extern "c" fn sendfile(112pub extern "c" fn sendfile(
98 out_fd: fd_t,113 out_fd: fd_t,
99 in_fd: fd_t,114 in_fd: fd_t,
lib/std/crypto/pcurves/p256.zig+48-16
...@@ -49,21 +49,26 @@ pub const P256 = struct {...@@ -49,21 +49,26 @@ pub const P256 = struct {
49 }49 }
5050
51 /// Create a point from affine coordinates after checking that they match the curve equation.51 /// Create a point from affine coordinates after checking that they match the curve equation.
52 pub fn fromAffineCoordinates(x: Fe, y: Fe) EncodingError!P256 {52 pub fn fromAffineCoordinates(p: AffineCoordinates) EncodingError!P256 {
53 const x = p.x;
54 const y = p.y;
53 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);55 const x3AxB = x.sq().mul(x).sub(x).sub(x).sub(x).add(B);
54 const yy = y.sq();56 const yy = y.sq();
55 if (!x3AxB.equivalent(yy)) {57 const on_curve = @boolToInt(x3AxB.equivalent(yy));
58 const is_identity = @boolToInt(x.equivalent(AffineCoordinates.identityElement.x)) & @boolToInt(y.equivalent(AffineCoordinates.identityElement.y));
59 if ((on_curve | is_identity) == 0) {
56 return error.InvalidEncoding;60 return error.InvalidEncoding;
57 }61 }
58 const p: P256 = .{ .x = x, .y = y, .z = Fe.one };62 var ret = P256{ .x = x, .y = y, .z = Fe.one };
59 return p;63 ret.z.cMov(P256.identityElement.z, is_identity);
64 return ret;
60 }65 }
6166
62 /// Create a point from serialized affine coordinates.67 /// Create a point from serialized affine coordinates.
63 pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: builtin.Endian) (NonCanonicalError || EncodingError)!P256 {68 pub fn fromSerializedAffineCoordinates(xs: [32]u8, ys: [32]u8, endian: builtin.Endian) (NonCanonicalError || EncodingError)!P256 {
64 const x = try Fe.fromBytes(xs, endian);69 const x = try Fe.fromBytes(xs, endian);
65 const y = try Fe.fromBytes(ys, endian);70 const y = try Fe.fromBytes(ys, endian);
66 return fromAffineCoordinates(x, y);71 return fromAffineCoordinates(.{ .x = x, .y = y });
67 }72 }
6873
69 /// Recover the Y coordinate from the X coordinate.74 /// Recover the Y coordinate from the X coordinate.
...@@ -96,7 +101,7 @@ pub const P256 = struct {...@@ -96,7 +101,7 @@ pub const P256 = struct {
96 if (encoded.len != 64) return error.InvalidEncoding;101 if (encoded.len != 64) return error.InvalidEncoding;
97 const x = try Fe.fromBytes(encoded[0..32].*, .Big);102 const x = try Fe.fromBytes(encoded[0..32].*, .Big);
98 const y = try Fe.fromBytes(encoded[32..64].*, .Big);103 const y = try Fe.fromBytes(encoded[32..64].*, .Big);
99 return P256.fromAffineCoordinates(x, y);104 return P256.fromAffineCoordinates(.{ .x = x, .y = y });
100 },105 },
101 else => return error.InvalidEncoding,106 else => return error.InvalidEncoding,
102 }107 }
...@@ -177,7 +182,7 @@ pub const P256 = struct {...@@ -177,7 +182,7 @@ pub const P256 = struct {
177182
178 /// Add P256 points, the second being specified using affine coordinates.183 /// Add P256 points, the second being specified using affine coordinates.
179 // Algorithm 5 from https://eprint.iacr.org/2015/1060.pdf184 // Algorithm 5 from https://eprint.iacr.org/2015/1060.pdf
180 pub fn addMixed(p: P256, q: struct { x: Fe, y: Fe }) P256 {185 pub fn addMixed(p: P256, q: AffineCoordinates) P256 {
181 var t0 = p.x.mul(q.x);186 var t0 = p.x.mul(q.x);
182 var t1 = p.y.mul(q.y);187 var t1 = p.y.mul(q.y);
183 var t3 = q.x.add(q.y);188 var t3 = q.x.add(q.y);
...@@ -194,9 +199,9 @@ pub const P256 = struct {...@@ -194,9 +199,9 @@ pub const P256 = struct {
194 Z3 = X3.dbl();199 Z3 = X3.dbl();
195 X3 = X3.add(Z3);200 X3 = X3.add(Z3);
196 Z3 = t1.sub(X3);201 Z3 = t1.sub(X3);
197 X3 = t1.dbl();202 X3 = t1.add(X3);
198 Y3 = B.mul(Y3);203 Y3 = B.mul(Y3);
199 t1 = p.z.add(p.z);204 t1 = p.z.dbl();
200 var t2 = t1.add(p.z);205 var t2 = t1.add(p.z);
201 Y3 = Y3.sub(t2);206 Y3 = Y3.sub(t2);
202 Y3 = Y3.sub(t0);207 Y3 = Y3.sub(t0);
...@@ -214,14 +219,16 @@ pub const P256 = struct {...@@ -214,14 +219,16 @@ pub const P256 = struct {
214 Z3 = t4.mul(Z3);219 Z3 = t4.mul(Z3);
215 t1 = t3.mul(t0);220 t1 = t3.mul(t0);
216 Z3 = Z3.add(t1);221 Z3 = Z3.add(t1);
217 return .{222 var ret = P256{
218 .x = X3,223 .x = X3,
219 .y = Y3,224 .y = Y3,
220 .z = Z3,225 .z = Z3,
221 };226 };
227 ret.cMov(p, @boolToInt(q.x.isZero()));
228 return ret;
222 }229 }
223230
224 // Add P256 points.231 /// Add P256 points.
225 // Algorithm 4 from https://eprint.iacr.org/2015/1060.pdf232 // Algorithm 4 from https://eprint.iacr.org/2015/1060.pdf
226 pub fn add(p: P256, q: P256) P256 {233 pub fn add(p: P256, q: P256) P256 {
227 var t0 = p.x.mul(q.x);234 var t0 = p.x.mul(q.x);
...@@ -274,18 +281,19 @@ pub const P256 = struct {...@@ -274,18 +281,19 @@ pub const P256 = struct {
274 };281 };
275 }282 }
276283
277 // Subtract P256 points.284 /// Subtract P256 points.
278 pub fn sub(p: P256, q: P256) P256 {285 pub fn sub(p: P256, q: P256) P256 {
279 return p.add(q.neg());286 return p.add(q.neg());
280 }287 }
281288
282 /// Return affine coordinates.289 /// Return affine coordinates.
283 pub fn affineCoordinates(p: P256) struct { x: Fe, y: Fe } {290 pub fn affineCoordinates(p: P256) AffineCoordinates {
284 const zinv = p.z.invert();291 const zinv = p.z.invert();
285 const ret = .{292 var ret = AffineCoordinates{
286 .x = p.x.mul(zinv),293 .x = p.x.mul(zinv),
287 .y = p.y.mul(zinv),294 .y = p.y.mul(zinv),
288 };295 };
296 ret.cMov(AffineCoordinates.identityElement, @boolToInt(p.x.isZero()));
289 return ret;297 return ret;
290 }298 }
291299
...@@ -382,11 +390,21 @@ pub const P256 = struct {...@@ -382,11 +390,21 @@ pub const P256 = struct {
382 return pc;390 return pc;
383 }391 }
384392
393 const basePointPc = comptime pc: {
394 @setEvalBranchQuota(50000);
395 break :pc precompute(P256.basePoint, 15);
396 };
397
398 const basePointPc8 = comptime pc: {
399 @setEvalBranchQuota(50000);
400 break :pc precompute(P256.basePoint, 8);
401 };
402
385 /// Multiply an elliptic curve point by a scalar.403 /// Multiply an elliptic curve point by a scalar.
386 /// Return error.IdentityElement if the result is the identity element.404 /// Return error.IdentityElement if the result is the identity element.
387 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {405 pub fn mul(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
388 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);406 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
389 const pc = if (p.is_base) precompute(P256.basePoint, 15) else pc: {407 const pc = if (p.is_base) basePointPc else pc: {
390 try p.rejectIdentity();408 try p.rejectIdentity();
391 const xpc = precompute(p, 15);409 const xpc = precompute(p, 15);
392 break :pc xpc;410 break :pc xpc;
...@@ -398,7 +416,7 @@ pub const P256 = struct {...@@ -398,7 +416,7 @@ pub const P256 = struct {
398 /// This can be used for signature verification.416 /// This can be used for signature verification.
399 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {417 pub fn mulPublic(p: P256, s_: [32]u8, endian: builtin.Endian) IdentityElementError!P256 {
400 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);418 const s = if (endian == .Little) s_ else Fe.orderSwap(s_);
401 const pc = if (p.is_base) precompute(P256.basePoint, 8) else pc: {419 const pc = if (p.is_base) basePointPc8 else pc: {
402 try p.rejectIdentity();420 try p.rejectIdentity();
403 const xpc = precompute(p, 8);421 const xpc = precompute(p, 8);
404 break :pc xpc;422 break :pc xpc;
...@@ -407,6 +425,20 @@ pub const P256 = struct {...@@ -407,6 +425,20 @@ pub const P256 = struct {
407 }425 }
408};426};
409427
428/// A point in affine coordinates.
429pub const AffineCoordinates = struct {
430 x: P256.Fe,
431 y: P256.Fe,
432
433 /// Identity element in affine coordinates.
434 pub const identityElement = AffineCoordinates{ .x = P256.identityElement.x, .y = P256.identityElement.y };
435
436 fn cMov(p: *AffineCoordinates, a: AffineCoordinates, c: u1) void {
437 p.x.cMov(a.x, c);
438 p.y.cMov(a.y, c);
439 }
440};
441
410test "p256" {442test "p256" {
411 _ = @import("tests.zig");443 _ = @import("tests.zig");
412}444}
lib/std/crypto/pcurves/tests.zig+6
...@@ -101,3 +101,9 @@ test "p256 field element non-canonical encoding" {...@@ -101,3 +101,9 @@ test "p256 field element non-canonical encoding" {
101 const s = [_]u8{0xff} ** 32;101 const s = [_]u8{0xff} ** 32;
102 try testing.expectError(error.NonCanonical, P256.Fe.fromBytes(s, .Little));102 try testing.expectError(error.NonCanonical, P256.Fe.fromBytes(s, .Little));
103}103}
104
105test "p256 neutral element decoding" {
106 try testing.expectError(error.InvalidEncoding, P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.zero }));
107 const p = try P256.fromAffineCoordinates(.{ .x = P256.Fe.zero, .y = P256.Fe.one });
108 try testing.expectError(error.IdentityElement, p.rejectIdentity());
109}
lib/std/fs/file.zig+2-2
...@@ -524,8 +524,8 @@ pub const File = struct {...@@ -524,8 +524,8 @@ pub const File = struct {
524 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in524 /// The `iovecs` parameter is mutable because this function needs to mutate the fields in
525 /// order to handle partial reads from the underlying OS layer.525 /// order to handle partial reads from the underlying OS layer.
526 /// See https://github.com/ziglang/zig/issues/7699526 /// See https://github.com/ziglang/zig/issues/7699
527 pub fn preadvAll(self: File, iovecs: []const os.iovec, offset: u64) PReadError!void {527 pub fn preadvAll(self: File, iovecs: []os.iovec, offset: u64) PReadError!usize {
528 if (iovecs.len == 0) return;528 if (iovecs.len == 0) return 0;
529529
530 var i: usize = 0;530 var i: usize = 0;
531 var off: usize = 0;531 var off: usize = 0;
lib/std/fs/test.zig+83
...@@ -520,6 +520,89 @@ test "makePath, put some files in it, deleteTree" {...@@ -520,6 +520,89 @@ test "makePath, put some files in it, deleteTree" {
520 }520 }
521}521}
522522
523test "writev, readv" {
524 var tmp = tmpDir(.{});
525 defer tmp.cleanup();
526
527 const line1 = "line1\n";
528 const line2 = "line2\n";
529
530 var buf1: [line1.len]u8 = undefined;
531 var buf2: [line2.len]u8 = undefined;
532 var write_vecs = [_]std.os.iovec_const{
533 .{
534 .iov_base = line1,
535 .iov_len = line1.len,
536 },
537 .{
538 .iov_base = line2,
539 .iov_len = line2.len,
540 },
541 };
542 var read_vecs = [_]std.os.iovec{
543 .{
544 .iov_base = &buf2,
545 .iov_len = buf2.len,
546 },
547 .{
548 .iov_base = &buf1,
549 .iov_len = buf1.len,
550 },
551 };
552
553 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
554 defer src_file.close();
555
556 try src_file.writevAll(&write_vecs);
557 try testing.expectEqual(@as(u64, line1.len + line2.len), try src_file.getEndPos());
558 try src_file.seekTo(0);
559 const read = try src_file.readvAll(&read_vecs);
560 try testing.expectEqual(@as(usize, line1.len + line2.len), read);
561 try testing.expectEqualStrings(&buf1, "line2\n");
562 try testing.expectEqualStrings(&buf2, "line1\n");
563}
564
565test "pwritev, preadv" {
566 var tmp = tmpDir(.{});
567 defer tmp.cleanup();
568
569 const line1 = "line1\n";
570 const line2 = "line2\n";
571
572 var buf1: [line1.len]u8 = undefined;
573 var buf2: [line2.len]u8 = undefined;
574 var write_vecs = [_]std.os.iovec_const{
575 .{
576 .iov_base = line1,
577 .iov_len = line1.len,
578 },
579 .{
580 .iov_base = line2,
581 .iov_len = line2.len,
582 },
583 };
584 var read_vecs = [_]std.os.iovec{
585 .{
586 .iov_base = &buf2,
587 .iov_len = buf2.len,
588 },
589 .{
590 .iov_base = &buf1,
591 .iov_len = buf1.len,
592 },
593 };
594
595 var src_file = try tmp.dir.createFile("test.txt", .{ .read = true });
596 defer src_file.close();
597
598 try src_file.pwritevAll(&write_vecs, 16);
599 try testing.expectEqual(@as(u64, 16 + line1.len + line2.len), try src_file.getEndPos());
600 const read = try src_file.preadvAll(&read_vecs, 16);
601 try testing.expectEqual(@as(usize, line1.len + line2.len), read);
602 try testing.expectEqualStrings(&buf1, "line2\n");
603 try testing.expectEqualStrings(&buf2, "line1\n");
604}
605
523test "access file" {606test "access file" {
524 if (builtin.os.tag == .wasi) return error.SkipZigTest;607 if (builtin.os.tag == .wasi) return error.SkipZigTest;
525608
lib/std/json.zig+20
...@@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:...@@ -1571,6 +1571,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
1571 return error.DuplicateJSONField;1571 return error.DuplicateJSONField;
1572 } else if (options.duplicate_field_behavior == .UseLast) {1572 } else if (options.duplicate_field_behavior == .UseLast) {
1573 parseFree(field.field_type, @field(r, field.name), options);1573 parseFree(field.field_type, @field(r, field.name), options);
1574 fields_seen[i] = false;
1574 }1575 }
1575 }1576 }
1576 if (field.is_comptime) {1577 if (field.is_comptime) {
...@@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:...@@ -1642,6 +1643,7 @@ fn parseInternal(comptime T: type, token: Token, tokens: *TokenStream, options:
1642 switch (ptrInfo.size) {1643 switch (ptrInfo.size) {
1643 .One => {1644 .One => {
1644 const r: T = try allocator.create(ptrInfo.child);1645 const r: T = try allocator.create(ptrInfo.child);
1646 errdefer allocator.destroy(r);
1645 r.* = try parseInternal(ptrInfo.child, token, tokens, options);1647 r.* = try parseInternal(ptrInfo.child, token, tokens, options);
1646 return r;1648 return r;
1647 },1649 },
...@@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" {...@@ -1988,6 +1990,24 @@ test "parse into struct with misc fields" {
1988 try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union);1990 try testing.expectEqual(T.Union{ .float = 100000 }, r.a_union);
1989}1991}
19901992
1993test "parse into struct with duplicate field" {
1994 // allow allocator to detect double frees by keeping bucket in use
1995 const ballast = try testing.allocator.alloc(u64, 1);
1996 defer testing.allocator.free(ballast);
1997
1998 const options = ParseOptions{
1999 .allocator = testing.allocator,
2000 .duplicate_field_behavior = .UseLast,
2001 };
2002 const str = "{ \"a\": 1, \"a\": 0.25 }";
2003
2004 const T1 = struct { a: *u64 };
2005 try testing.expectError(error.UnexpectedToken, parse(T1, &TokenStream.init(str), options));
2006
2007 const T2 = struct { a: f64 };
2008 try testing.expectEqual(T2{ .a = 0.25 }, try parse(T2, &TokenStream.init(str), options));
2009}
2010
1991/// A non-stream JSON parser which constructs a tree of Value's.2011/// A non-stream JSON parser which constructs a tree of Value's.
1992pub const Parser = struct {2012pub const Parser = struct {
1993 allocator: *Allocator,2013 allocator: *Allocator,
lib/std/mem.zig+188
...@@ -603,6 +603,7 @@ test "span" {...@@ -603,6 +603,7 @@ test "span" {
603 try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null)));603 try testing.expectEqual(@as(?[:0]u16, null), span(@as(?[*:0]u16, null)));
604}604}
605605
606/// Deprecated: use std.mem.span() or std.mem.sliceTo()
606/// Same as `span`, except when there is both a sentinel and an array607/// Same as `span`, except when there is both a sentinel and an array
607/// length or slice length, scans the memory for the sentinel value608/// length or slice length, scans the memory for the sentinel value
608/// rather than using the length.609/// rather than using the length.
...@@ -631,6 +632,192 @@ test "spanZ" {...@@ -631,6 +632,192 @@ test "spanZ" {
631 try testing.expectEqual(@as(?[:0]u16, null), spanZ(@as(?[*:0]u16, null)));632 try testing.expectEqual(@as(?[:0]u16, null), spanZ(@as(?[*:0]u16, null)));
632}633}
633634
635/// Helper for the return type of sliceTo()
636fn SliceTo(comptime T: type, comptime end: meta.Elem(T)) type {
637 switch (@typeInfo(T)) {
638 .Optional => |optional_info| {
639 return ?SliceTo(optional_info.child, end);
640 },
641 .Pointer => |ptr_info| {
642 var new_ptr_info = ptr_info;
643 new_ptr_info.size = .Slice;
644 switch (ptr_info.size) {
645 .One => switch (@typeInfo(ptr_info.child)) {
646 .Array => |array_info| {
647 new_ptr_info.child = array_info.child;
648 // The return type must only be sentinel terminated if we are guaranteed
649 // to find the value searched for, which is only the case if it matches
650 // the sentinel of the type passed.
651 if (array_info.sentinel) |sentinel| {
652 if (end == sentinel) {
653 new_ptr_info.sentinel = end;
654 } else {
655 new_ptr_info.sentinel = null;
656 }
657 }
658 },
659 else => {},
660 },
661 .Many, .Slice => {
662 // The return type must only be sentinel terminated if we are guaranteed
663 // to find the value searched for, which is only the case if it matches
664 // the sentinel of the type passed.
665 if (ptr_info.sentinel) |sentinel| {
666 if (end == sentinel) {
667 new_ptr_info.sentinel = end;
668 } else {
669 new_ptr_info.sentinel = null;
670 }
671 }
672 },
673 .C => {
674 new_ptr_info.sentinel = end;
675 // C pointers are always allowzero, but we don't want the return type to be.
676 assert(new_ptr_info.is_allowzero);
677 new_ptr_info.is_allowzero = false;
678 },
679 }
680 return @Type(std.builtin.TypeInfo{ .Pointer = new_ptr_info });
681 },
682 else => {},
683 }
684 @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(T));
685}
686
687/// Takes a pointer to an array, an array, a sentinel-terminated pointer, or a slice and
688/// iterates searching for the first occurrence of `end`, returning the scanned slice.
689/// If `end` is not found, the full length of the array/slice/sentinel terminated pointer is returned.
690/// If the pointer type is sentinel terminated and `end` matches that terminator, the
691/// resulting slice is also sentinel terminated.
692/// Pointer properties such as mutability and alignment are preserved.
693/// C pointers are assumed to be non-null.
694pub fn sliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) SliceTo(@TypeOf(ptr), end) {
695 if (@typeInfo(@TypeOf(ptr)) == .Optional) {
696 const non_null = ptr orelse return null;
697 return sliceTo(non_null, end);
698 }
699 const Result = SliceTo(@TypeOf(ptr), end);
700 const length = lenSliceTo(ptr, end);
701 if (@typeInfo(Result).Pointer.sentinel) |s| {
702 return ptr[0..length :s];
703 } else {
704 return ptr[0..length];
705 }
706}
707
708test "sliceTo" {
709 try testing.expectEqualSlices(u8, "aoeu", sliceTo("aoeu", 0));
710
711 {
712 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
713 try testing.expectEqualSlices(u16, &array, sliceTo(&array, 0));
714 try testing.expectEqualSlices(u16, array[0..3], sliceTo(array[0..3], 0));
715 try testing.expectEqualSlices(u16, array[0..2], sliceTo(&array, 3));
716 try testing.expectEqualSlices(u16, array[0..2], sliceTo(array[0..3], 3));
717
718 const sentinel_ptr = @ptrCast([*:5]u16, &array);
719 try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_ptr, 3));
720 try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_ptr, 99));
721
722 const optional_sentinel_ptr = @ptrCast(?[*:5]u16, &array);
723 try testing.expectEqualSlices(u16, array[0..2], sliceTo(optional_sentinel_ptr, 3).?);
724 try testing.expectEqualSlices(u16, array[0..4], sliceTo(optional_sentinel_ptr, 99).?);
725
726 const c_ptr = @as([*c]u16, &array);
727 try testing.expectEqualSlices(u16, array[0..2], sliceTo(c_ptr, 3));
728
729 const slice: []u16 = &array;
730 try testing.expectEqualSlices(u16, array[0..2], sliceTo(slice, 3));
731 try testing.expectEqualSlices(u16, &array, sliceTo(slice, 99));
732
733 const sentinel_slice: [:5]u16 = array[0..4 :5];
734 try testing.expectEqualSlices(u16, array[0..2], sliceTo(sentinel_slice, 3));
735 try testing.expectEqualSlices(u16, array[0..4], sliceTo(sentinel_slice, 99));
736 }
737 {
738 var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
739 try testing.expectEqualSlices(u16, sentinel_array[0..2], sliceTo(&sentinel_array, 3));
740 try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 0));
741 try testing.expectEqualSlices(u16, &sentinel_array, sliceTo(&sentinel_array, 99));
742 }
743
744 try testing.expectEqual(@as(?[]u8, null), sliceTo(@as(?[]u8, null), 0));
745}
746
747/// Private helper for sliceTo(). If you want the length, use sliceTo(foo, x).len
748fn lenSliceTo(ptr: anytype, comptime end: meta.Elem(@TypeOf(ptr))) usize {
749 switch (@typeInfo(@TypeOf(ptr))) {
750 .Pointer => |ptr_info| switch (ptr_info.size) {
751 .One => switch (@typeInfo(ptr_info.child)) {
752 .Array => |array_info| {
753 if (array_info.sentinel) |sentinel| {
754 if (sentinel == end) {
755 return indexOfSentinel(array_info.child, end, ptr);
756 }
757 }
758 return indexOfScalar(array_info.child, ptr, end) orelse array_info.len;
759 },
760 else => {},
761 },
762 .Many => if (ptr_info.sentinel) |sentinel| {
763 // We may be looking for something other than the sentinel,
764 // but iterating past the sentinel would be a bug so we need
765 // to check for both.
766 var i: usize = 0;
767 while (ptr[i] != end and ptr[i] != sentinel) i += 1;
768 return i;
769 },
770 .C => {
771 assert(ptr != null);
772 return indexOfSentinel(ptr_info.child, end, ptr);
773 },
774 .Slice => {
775 if (ptr_info.sentinel) |sentinel| {
776 if (sentinel == end) {
777 return indexOfSentinel(ptr_info.child, sentinel, ptr);
778 }
779 }
780 return indexOfScalar(ptr_info.child, ptr, end) orelse ptr.len;
781 },
782 },
783 else => {},
784 }
785 @compileError("invalid type given to std.mem.sliceTo: " ++ @typeName(@TypeOf(ptr)));
786}
787
788test "lenSliceTo" {
789 try testing.expect(lenSliceTo("aoeu", 0) == 4);
790
791 {
792 var array: [5]u16 = [_]u16{ 1, 2, 3, 4, 5 };
793 try testing.expectEqual(@as(usize, 5), lenSliceTo(&array, 0));
794 try testing.expectEqual(@as(usize, 3), lenSliceTo(array[0..3], 0));
795 try testing.expectEqual(@as(usize, 2), lenSliceTo(&array, 3));
796 try testing.expectEqual(@as(usize, 2), lenSliceTo(array[0..3], 3));
797
798 const sentinel_ptr = @ptrCast([*:5]u16, &array);
799 try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_ptr, 3));
800 try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_ptr, 99));
801
802 const c_ptr = @as([*c]u16, &array);
803 try testing.expectEqual(@as(usize, 2), lenSliceTo(c_ptr, 3));
804
805 const slice: []u16 = &array;
806 try testing.expectEqual(@as(usize, 2), lenSliceTo(slice, 3));
807 try testing.expectEqual(@as(usize, 5), lenSliceTo(slice, 99));
808
809 const sentinel_slice: [:5]u16 = array[0..4 :5];
810 try testing.expectEqual(@as(usize, 2), lenSliceTo(sentinel_slice, 3));
811 try testing.expectEqual(@as(usize, 4), lenSliceTo(sentinel_slice, 99));
812 }
813 {
814 var sentinel_array: [5:0]u16 = [_:0]u16{ 1, 2, 3, 4, 5 };
815 try testing.expectEqual(@as(usize, 2), lenSliceTo(&sentinel_array, 3));
816 try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 0));
817 try testing.expectEqual(@as(usize, 5), lenSliceTo(&sentinel_array, 99));
818 }
819}
820
634/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer,821/// Takes a pointer to an array, an array, a vector, a sentinel-terminated pointer,
635/// a slice or a tuple, and returns the length.822/// a slice or a tuple, and returns the length.
636/// In the case of a sentinel-terminated array, it uses the array length.823/// In the case of a sentinel-terminated array, it uses the array length.
...@@ -689,6 +876,7 @@ test "len" {...@@ -689,6 +876,7 @@ test "len" {
689 }876 }
690}877}
691878
879/// Deprecated: use std.mem.len() or std.mem.sliceTo().len
692/// Takes a pointer to an array, an array, a sentinel-terminated pointer,880/// Takes a pointer to an array, an array, a sentinel-terminated pointer,
693/// or a slice, and returns the length.881/// or a slice, and returns the length.
694/// In the case of a sentinel-terminated array, it scans the array882/// In the case of a sentinel-terminated array, it scans the array
lib/std/meta.zig+1-7
...@@ -175,13 +175,7 @@ pub fn Elem(comptime T: type) type {...@@ -175,13 +175,7 @@ pub fn Elem(comptime T: type) type {
175 },175 },
176 .Many, .C, .Slice => return info.child,176 .Many, .C, .Slice => return info.child,
177 },177 },
178 .Optional => |info| switch (@typeInfo(info.child)) {178 .Optional => |info| return Elem(info.child),
179 .Pointer => |ptr_info| switch (ptr_info.size) {
180 .Many => return ptr_info.child,
181 else => {},
182 },
183 else => {},
184 },
185 else => {},179 else => {},
186 }180 }
187 @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'");181 @compileError("Expected pointer, slice, array or vector type, found '" ++ @typeName(T) ++ "'");
lib/std/os.zig+147-33
...@@ -497,8 +497,14 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {...@@ -497,8 +497,14 @@ pub fn pread(fd: fd_t, buf: []u8, offset: u64) PReadError!usize {
497 };497 };
498 const adjusted_len = math.min(max_count, buf.len);498 const adjusted_len = math.min(max_count, buf.len);
499499
500 const pread_sym = if (builtin.os.tag == .linux and builtin.link_libc)
501 system.pread64
502 else
503 system.pread;
504
505 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
500 while (true) {506 while (true) {
501 const rc = system.pread(fd, buf.ptr, adjusted_len, offset);507 const rc = pread_sym(fd, buf.ptr, adjusted_len, ioffset);
502 switch (errno(rc)) {508 switch (errno(rc)) {
503 0 => return @intCast(usize, rc),509 0 => return @intCast(usize, rc),
504 EINTR => continue,510 EINTR => continue,
...@@ -567,15 +573,13 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {...@@ -567,15 +573,13 @@ pub fn ftruncate(fd: fd_t, length: u64) TruncateError!void {
567 }573 }
568574
569 while (true) {575 while (true) {
570 const rc = if (builtin.link_libc)576 const ftruncate_sym = if (builtin.os.tag == .linux and builtin.link_libc)
571 if (std.Target.current.os.tag == .linux)577 system.ftruncate64
572 system.ftruncate64(fd, @bitCast(off_t, length))
573 else
574 system.ftruncate(fd, @bitCast(off_t, length))
575 else578 else
576 system.ftruncate(fd, length);579 system.ftruncate;
577580
578 switch (errno(rc)) {581 const ilen = @bitCast(i64, length); // the OS treats this as unsigned
582 switch (errno(ftruncate_sym(fd, ilen))) {
579 0 => return,583 0 => return,
580 EINTR => continue,584 EINTR => continue,
581 EFBIG => return error.FileTooBig,585 EFBIG => return error.FileTooBig,
...@@ -637,8 +641,14 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {...@@ -637,8 +641,14 @@ pub fn preadv(fd: fd_t, iov: []const iovec, offset: u64) PReadError!usize {
637641
638 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);642 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
639643
644 const preadv_sym = if (builtin.os.tag == .linux and builtin.link_libc)
645 system.preadv64
646 else
647 system.preadv;
648
649 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
640 while (true) {650 while (true) {
641 const rc = system.preadv(fd, iov.ptr, iov_count, offset);651 const rc = preadv_sym(fd, iov.ptr, iov_count, ioffset);
642 switch (errno(rc)) {652 switch (errno(rc)) {
643 0 => return @bitCast(usize, rc),653 0 => return @bitCast(usize, rc),
644 EINTR => continue,654 EINTR => continue,
...@@ -895,8 +905,14 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {...@@ -895,8 +905,14 @@ pub fn pwrite(fd: fd_t, bytes: []const u8, offset: u64) PWriteError!usize {
895 };905 };
896 const adjusted_len = math.min(max_count, bytes.len);906 const adjusted_len = math.min(max_count, bytes.len);
897907
908 const pwrite_sym = if (builtin.os.tag == .linux and builtin.link_libc)
909 system.pwrite64
910 else
911 system.pwrite;
912
913 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
898 while (true) {914 while (true) {
899 const rc = system.pwrite(fd, bytes.ptr, adjusted_len, offset);915 const rc = pwrite_sym(fd, bytes.ptr, adjusted_len, ioffset);
900 switch (errno(rc)) {916 switch (errno(rc)) {
901 0 => return @intCast(usize, rc),917 0 => return @intCast(usize, rc),
902 EINTR => continue,918 EINTR => continue,
...@@ -977,9 +993,15 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz...@@ -977,9 +993,15 @@ pub fn pwritev(fd: fd_t, iov: []const iovec_const, offset: u64) PWriteError!usiz
977 }993 }
978 }994 }
979995
996 const pwritev_sym = if (builtin.os.tag == .linux and builtin.link_libc)
997 system.pwritev64
998 else
999 system.pwritev;
1000
980 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);1001 const iov_count = math.cast(u31, iov.len) catch math.maxInt(u31);
1002 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
981 while (true) {1003 while (true) {
982 const rc = system.pwritev(fd, iov.ptr, iov_count, offset);1004 const rc = pwritev_sym(fd, iov.ptr, iov_count, ioffset);
983 switch (errno(rc)) {1005 switch (errno(rc)) {
984 0 => return @intCast(usize, rc),1006 0 => return @intCast(usize, rc),
985 EINTR => continue,1007 EINTR => continue,
...@@ -1068,8 +1090,14 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t...@@ -1068,8 +1090,14 @@ pub fn openZ(file_path: [*:0]const u8, flags: u32, perm: mode_t) OpenError!fd_t
1068 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1090 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
1069 return openW(file_path_w.span(), flags, perm);1091 return openW(file_path_w.span(), flags, perm);
1070 }1092 }
1093
1094 const open_sym = if (builtin.os.tag == .linux and builtin.link_libc)
1095 system.open64
1096 else
1097 system.open;
1098
1071 while (true) {1099 while (true) {
1072 const rc = system.open(file_path, flags, perm);1100 const rc = open_sym(file_path, flags, perm);
1073 switch (errno(rc)) {1101 switch (errno(rc)) {
1074 0 => return @intCast(fd_t, rc),1102 0 => return @intCast(fd_t, rc),
1075 EINTR => continue,1103 EINTR => continue,
...@@ -1202,8 +1230,14 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)...@@ -1202,8 +1230,14 @@ pub fn openatZ(dir_fd: fd_t, file_path: [*:0]const u8, flags: u32, mode: mode_t)
1202 const file_path_w = try windows.cStrToPrefixedFileW(file_path);1230 const file_path_w = try windows.cStrToPrefixedFileW(file_path);
1203 return openatW(dir_fd, file_path_w.span(), flags, mode);1231 return openatW(dir_fd, file_path_w.span(), flags, mode);
1204 }1232 }
1233
1234 const openat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
1235 system.openat64
1236 else
1237 system.openat;
1238
1205 while (true) {1239 while (true) {
1206 const rc = system.openat(dir_fd, file_path, flags, mode);1240 const rc = openat_sym(dir_fd, file_path, flags, mode);
1207 switch (errno(rc)) {1241 switch (errno(rc)) {
1208 0 => return @intCast(fd_t, rc),1242 0 => return @intCast(fd_t, rc),
1209 EINTR => continue,1243 EINTR => continue,
...@@ -2758,9 +2792,9 @@ pub const ShutdownHow = enum { recv, send, both };...@@ -2758,9 +2792,9 @@ pub const ShutdownHow = enum { recv, send, both };
2758pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void {2792pub fn shutdown(sock: socket_t, how: ShutdownHow) ShutdownError!void {
2759 if (builtin.os.tag == .windows) {2793 if (builtin.os.tag == .windows) {
2760 const result = windows.ws2_32.shutdown(sock, switch (how) {2794 const result = windows.ws2_32.shutdown(sock, switch (how) {
2761 .recv => windows.SD_RECEIVE,2795 .recv => windows.ws2_32.SD_RECEIVE,
2762 .send => windows.SD_SEND,2796 .send => windows.ws2_32.SD_SEND,
2763 .both => windows.SD_BOTH,2797 .both => windows.ws2_32.SD_BOTH,
2764 });2798 });
2765 if (0 != result) switch (windows.ws2_32.WSAGetLastError()) {2799 if (0 != result) switch (windows.ws2_32.WSAGetLastError()) {
2766 .WSAECONNABORTED => return error.ConnectionAborted,2800 .WSAECONNABORTED => return error.ConnectionAborted,
...@@ -3217,6 +3251,35 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock...@@ -3217,6 +3251,35 @@ pub fn getsockname(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSock
3217 }3251 }
3218}3252}
32193253
3254pub fn getpeername(sock: socket_t, addr: *sockaddr, addrlen: *socklen_t) GetSockNameError!void {
3255 if (builtin.os.tag == .windows) {
3256 const rc = windows.getpeername(sock, addr, addrlen);
3257 if (rc == windows.ws2_32.SOCKET_ERROR) {
3258 switch (windows.ws2_32.WSAGetLastError()) {
3259 .WSANOTINITIALISED => unreachable,
3260 .WSAENETDOWN => return error.NetworkSubsystemFailed,
3261 .WSAEFAULT => unreachable, // addr or addrlen have invalid pointers or addrlen points to an incorrect value
3262 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
3263 .WSAEINVAL => return error.SocketNotBound,
3264 else => |err| return windows.unexpectedWSAError(err),
3265 }
3266 }
3267 return;
3268 } else {
3269 const rc = system.getpeername(sock, addr, addrlen);
3270 switch (errno(rc)) {
3271 0 => return,
3272 else => |err| return unexpectedErrno(err),
3273
3274 EBADF => unreachable, // always a race condition
3275 EFAULT => unreachable,
3276 EINVAL => unreachable, // invalid parameters
3277 ENOTSOCK => return error.FileDescriptorNotASocket,
3278 ENOBUFS => return error.SystemResources,
3279 }
3280 }
3281}
3282
3220pub const ConnectError = error{3283pub const ConnectError = error{
3221 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket3284 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
3222 /// file, or search permission is denied for one of the directories in the path prefix.3285 /// file, or search permission is denied for one of the directories in the path prefix.
...@@ -3408,8 +3471,13 @@ pub fn fstat(fd: fd_t) FStatError!Stat {...@@ -3408,8 +3471,13 @@ pub fn fstat(fd: fd_t) FStatError!Stat {
3408 @compileError("fstat is not yet implemented on Windows");3471 @compileError("fstat is not yet implemented on Windows");
3409 }3472 }
34103473
3411 var stat: Stat = undefined;3474 const fstat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
3412 switch (errno(system.fstat(fd, &stat))) {3475 system.fstat64
3476 else
3477 system.fstat;
3478
3479 var stat = mem.zeroes(Stat);
3480 switch (errno(fstat_sym(fd, &stat))) {
3413 0 => return stat,3481 0 => return stat,
3414 EINVAL => unreachable,3482 EINVAL => unreachable,
3415 EBADF => unreachable, // Always a race condition.3483 EBADF => unreachable, // Always a race condition.
...@@ -3459,8 +3527,13 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S...@@ -3459,8 +3527,13 @@ pub fn fstatatWasi(dirfd: fd_t, pathname: []const u8, flags: u32) FStatAtError!S
3459/// Same as `fstatat` but `pathname` is null-terminated.3527/// Same as `fstatat` but `pathname` is null-terminated.
3460/// See also `fstatat`.3528/// See also `fstatat`.
3461pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {3529pub fn fstatatZ(dirfd: fd_t, pathname: [*:0]const u8, flags: u32) FStatAtError!Stat {
3462 var stat: Stat = undefined;3530 const fstatat_sym = if (builtin.os.tag == .linux and builtin.link_libc)
3463 switch (errno(system.fstatat(dirfd, pathname, &stat, flags))) {3531 system.fstatat64
3532 else
3533 system.fstatat;
3534
3535 var stat = mem.zeroes(Stat);
3536 switch (errno(fstatat_sym(dirfd, pathname, &stat, flags))) {
3464 0 => return stat,3537 0 => return stat,
3465 EINVAL => unreachable,3538 EINVAL => unreachable,
3466 EBADF => unreachable, // Always a race condition.3539 EBADF => unreachable, // Always a race condition.
...@@ -3672,12 +3745,17 @@ pub fn mmap(...@@ -3672,12 +3745,17 @@ pub fn mmap(
3672 fd: fd_t,3745 fd: fd_t,
3673 offset: u64,3746 offset: u64,
3674) MMapError![]align(mem.page_size) u8 {3747) MMapError![]align(mem.page_size) u8 {
3748 const mmap_sym = if (builtin.os.tag == .linux and builtin.link_libc)
3749 system.mmap64
3750 else
3751 system.mmap;
3752
3753 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
3754 const rc = mmap_sym(ptr, length, prot, flags, fd, ioffset);
3675 const err = if (builtin.link_libc) blk: {3755 const err = if (builtin.link_libc) blk: {
3676 const rc = std.c.mmap(ptr, length, prot, flags, fd, offset);
3677 if (rc != std.c.MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length];3756 if (rc != std.c.MAP_FAILED) return @ptrCast([*]align(mem.page_size) u8, @alignCast(mem.page_size, rc))[0..length];
3678 break :blk system._errno().*;3757 break :blk system._errno().*;
3679 } else blk: {3758 } else blk: {
3680 const rc = system.mmap(ptr, length, prot, flags, fd, offset);
3681 const err = errno(rc);3759 const err = errno(rc);
3682 if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length];3760 if (err == 0) return @intToPtr([*]align(mem.page_size) u8, rc)[0..length];
3683 break :blk err;3761 break :blk err;
...@@ -4027,8 +4105,14 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {...@@ -4027,8 +4105,14 @@ pub fn lseek_SET(fd: fd_t, offset: u64) SeekError!void {
4027 else => |err| return unexpectedErrno(err),4105 else => |err| return unexpectedErrno(err),
4028 }4106 }
4029 }4107 }
4030 const ipos = @bitCast(i64, offset); // the OS treats this as unsigned4108
4031 switch (errno(system.lseek(fd, ipos, SEEK_SET))) {4109 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4110 system.lseek64
4111 else
4112 system.lseek;
4113
4114 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
4115 switch (errno(lseek_sym(fd, ioffset, SEEK_SET))) {
4032 0 => return,4116 0 => return,
4033 EBADF => unreachable, // always a race condition4117 EBADF => unreachable, // always a race condition
4034 EINVAL => return error.Unseekable,4118 EINVAL => return error.Unseekable,
...@@ -4069,7 +4153,13 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {...@@ -4069,7 +4153,13 @@ pub fn lseek_CUR(fd: fd_t, offset: i64) SeekError!void {
4069 else => |err| return unexpectedErrno(err),4153 else => |err| return unexpectedErrno(err),
4070 }4154 }
4071 }4155 }
4072 switch (errno(system.lseek(fd, offset, SEEK_CUR))) {4156 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4157 system.lseek64
4158 else
4159 system.lseek;
4160
4161 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
4162 switch (errno(lseek_sym(fd, ioffset, SEEK_CUR))) {
4073 0 => return,4163 0 => return,
4074 EBADF => unreachable, // always a race condition4164 EBADF => unreachable, // always a race condition
4075 EINVAL => return error.Unseekable,4165 EINVAL => return error.Unseekable,
...@@ -4110,7 +4200,13 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {...@@ -4110,7 +4200,13 @@ pub fn lseek_END(fd: fd_t, offset: i64) SeekError!void {
4110 else => |err| return unexpectedErrno(err),4200 else => |err| return unexpectedErrno(err),
4111 }4201 }
4112 }4202 }
4113 switch (errno(system.lseek(fd, offset, SEEK_END))) {4203 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4204 system.lseek64
4205 else
4206 system.lseek;
4207
4208 const ioffset = @bitCast(i64, offset); // the OS treats this as unsigned
4209 switch (errno(lseek_sym(fd, ioffset, SEEK_END))) {
4114 0 => return,4210 0 => return,
4115 EBADF => unreachable, // always a race condition4211 EBADF => unreachable, // always a race condition
4116 EINVAL => return error.Unseekable,4212 EINVAL => return error.Unseekable,
...@@ -4151,7 +4247,12 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {...@@ -4151,7 +4247,12 @@ pub fn lseek_CUR_get(fd: fd_t) SeekError!u64 {
4151 else => |err| return unexpectedErrno(err),4247 else => |err| return unexpectedErrno(err),
4152 }4248 }
4153 }4249 }
4154 const rc = system.lseek(fd, 0, SEEK_CUR);4250 const lseek_sym = if (builtin.os.tag == .linux and builtin.link_libc)
4251 system.lseek64
4252 else
4253 system.lseek;
4254
4255 const rc = lseek_sym(fd, 0, SEEK_CUR);
4155 switch (errno(rc)) {4256 switch (errno(rc)) {
4156 0 => return @bitCast(u64, rc),4257 0 => return @bitCast(u64, rc),
4157 EBADF => unreachable, // always a race condition4258 EBADF => unreachable, // always a race condition
...@@ -5169,9 +5270,14 @@ pub fn sendfile(...@@ -5169,9 +5270,14 @@ pub fn sendfile(
5169 // Here we match BSD behavior, making a zero count value send as many bytes as possible.5270 // Here we match BSD behavior, making a zero count value send as many bytes as possible.
5170 const adjusted_count = if (in_len == 0) max_count else math.min(in_len, @as(size_t, max_count));5271 const adjusted_count = if (in_len == 0) max_count else math.min(in_len, @as(size_t, max_count));
51715272
5273 const sendfile_sym = if (builtin.link_libc)
5274 system.sendfile64
5275 else
5276 system.sendfile;
5277
5172 while (true) {5278 while (true) {
5173 var offset: off_t = @bitCast(off_t, in_offset);5279 var offset: off_t = @bitCast(off_t, in_offset);
5174 const rc = system.sendfile(out_fd, in_fd, &offset, adjusted_count);5280 const rc = sendfile_sym(out_fd, in_fd, &offset, adjusted_count);
5175 switch (errno(rc)) {5281 switch (errno(rc)) {
5176 0 => {5282 0 => {
5177 const amt = @bitCast(usize, rc);5283 const amt = @bitCast(usize, rc);
...@@ -5722,7 +5828,7 @@ pub const SetSockOptError = error{...@@ -5722,7 +5828,7 @@ pub const SetSockOptError = error{
5722/// Set a socket's options.5828/// Set a socket's options.
5723pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {5829pub fn setsockopt(fd: socket_t, level: u32, optname: u32, opt: []const u8) SetSockOptError!void {
5724 if (builtin.os.tag == .windows) {5830 if (builtin.os.tag == .windows) {
5725 const rc = windows.ws2_32.setsockopt(fd, level, optname, opt.ptr, @intCast(socklen_t, opt.len));5831 const rc = windows.ws2_32.setsockopt(fd, @intCast(i32, level), @intCast(i32, optname), opt.ptr, @intCast(i32, opt.len));
5726 if (rc == windows.ws2_32.SOCKET_ERROR) {5832 if (rc == windows.ws2_32.SOCKET_ERROR) {
5727 switch (windows.ws2_32.WSAGetLastError()) {5833 switch (windows.ws2_32.WSAGetLastError()) {
5728 .WSANOTINITIALISED => unreachable,5834 .WSANOTINITIALISED => unreachable,
...@@ -5989,9 +6095,13 @@ pub fn prctl(option: PR, args: anytype) PrctlError!u31 {...@@ -5989,9 +6095,13 @@ pub fn prctl(option: PR, args: anytype) PrctlError!u31 {
5989pub const GetrlimitError = UnexpectedError;6095pub const GetrlimitError = UnexpectedError;
59906096
5991pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {6097pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
6098 const getrlimit_sym = if (builtin.os.tag == .linux and builtin.link_libc)
6099 system.getrlimit64
6100 else
6101 system.getrlimit;
6102
5992 var limits: rlimit = undefined;6103 var limits: rlimit = undefined;
5993 const rc = system.getrlimit(resource, &limits);6104 switch (errno(getrlimit_sym(resource, &limits))) {
5994 switch (errno(rc)) {
5995 0 => return limits,6105 0 => return limits,
5996 EFAULT => unreachable, // bogus pointer6106 EFAULT => unreachable, // bogus pointer
5997 EINVAL => unreachable,6107 EINVAL => unreachable,
...@@ -6002,8 +6112,12 @@ pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {...@@ -6002,8 +6112,12 @@ pub fn getrlimit(resource: rlimit_resource) GetrlimitError!rlimit {
6002pub const SetrlimitError = error{PermissionDenied} || UnexpectedError;6112pub const SetrlimitError = error{PermissionDenied} || UnexpectedError;
60036113
6004pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void {6114pub fn setrlimit(resource: rlimit_resource, limits: rlimit) SetrlimitError!void {
6005 const rc = system.setrlimit(resource, &limits);6115 const setrlimit_sym = if (builtin.os.tag == .linux and builtin.link_libc)
6006 switch (errno(rc)) {6116 system.setrlimit64
6117 else
6118 system.setrlimit;
6119
6120 switch (errno(setrlimit_sym(resource, &limits))) {
6007 0 => return,6121 0 => return,
6008 EFAULT => unreachable, // bogus pointer6122 EFAULT => unreachable, // bogus pointer
6009 EINVAL => unreachable,6123 EINVAL => unreachable,
lib/std/os/bits/darwin.zig+42
...@@ -23,6 +23,13 @@ pub const sockaddr = extern struct {...@@ -23,6 +23,13 @@ pub const sockaddr = extern struct {
23 family: sa_family_t,23 family: sa_family_t,
24 data: [14]u8,24 data: [14]u8,
25};25};
26pub const sockaddr_storage = extern struct {
27 len: u8,
28 family: sa_family_t,
29 __pad1: [5]u8,
30 __align: i64,
31 __pad2: [112]u8,
32};
26pub const sockaddr_in = extern struct {33pub const sockaddr_in = extern struct {
27 len: u8 = @sizeOf(sockaddr_in),34 len: u8 = @sizeOf(sockaddr_in),
28 family: sa_family_t = AF_INET,35 family: sa_family_t = AF_INET,
...@@ -1744,3 +1751,38 @@ pub const IOCPARM_MASK = 0x1fff;...@@ -1744,3 +1751,38 @@ pub const IOCPARM_MASK = 0x1fff;
1744fn ior(inout: u32, group: usize, num: usize, len: usize) usize {1751fn ior(inout: u32, group: usize, num: usize, len: usize) usize {
1745 return (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num));1752 return (inout | ((len & IOCPARM_MASK) << 16) | ((group) << 8) | (num));
1746}1753}
1754
1755// CPU families mapping
1756pub const CPUFAMILY = enum(u32) {
1757 UNKNOWN = 0,
1758 POWERPC_G3 = 0xcee41549,
1759 POWERPC_G4 = 0x77c184ae,
1760 POWERPC_G5 = 0xed76d8aa,
1761 INTEL_6_13 = 0xaa33392b,
1762 INTEL_PENRYN = 0x78ea4fbc,
1763 INTEL_NEHALEM = 0x6b5a4cd2,
1764 INTEL_WESTMERE = 0x573b5eec,
1765 INTEL_SANDYBRIDGE = 0x5490b78c,
1766 INTEL_IVYBRIDGE = 0x1f65e835,
1767 INTEL_HASWELL = 0x10b282dc,
1768 INTEL_BROADWELL = 0x582ed09c,
1769 INTEL_SKYLAKE = 0x37fc219f,
1770 INTEL_KABYLAKE = 0x0f817246,
1771 ARM_9 = 0xe73283ae,
1772 ARM_11 = 0x8ff620d8,
1773 ARM_XSCALE = 0x53b005f5,
1774 ARM_12 = 0xbd1b0ae9,
1775 ARM_13 = 0x0cc90e64,
1776 ARM_14 = 0x96077ef1,
1777 ARM_15 = 0xa8511bca,
1778 ARM_SWIFT = 0x1e2d6381,
1779 ARM_CYCLONE = 0x37a09642,
1780 ARM_TYPHOON = 0x2c91a47e,
1781 ARM_TWISTER = 0x92fb37c8,
1782 ARM_HURRICANE = 0x67ceee93,
1783 ARM_MONSOON_MISTRAL = 0xe81e7ef6,
1784 ARM_VORTEX_TEMPEST = 0x07d34b9f,
1785 ARM_LIGHTNING_THUNDER = 0x462504d2,
1786 ARM_FIRESTORM_ICESTORM = 0x1b588bb3,
1787 _,
1788};
lib/std/os/bits/dragonfly.zig+9-1
...@@ -380,6 +380,14 @@ pub const sockaddr = extern struct {...@@ -380,6 +380,14 @@ pub const sockaddr = extern struct {
380 sa_data: [14]u8,380 sa_data: [14]u8,
381};381};
382382
383pub const sockaddr_storage = extern struct {
384 len: u8,
385 family: sa_family_t,
386 __pad1: [5]u8,
387 __align: i64,
388 __pad2: [112]u8,
389};
390
383pub const Kevent = extern struct {391pub const Kevent = extern struct {
384 ident: usize,392 ident: usize,
385 filter: c_short,393 filter: c_short,
...@@ -640,7 +648,7 @@ pub const socklen_t = c_uint;...@@ -640,7 +648,7 @@ pub const socklen_t = c_uint;
640pub const sockaddr_storage = extern struct {648pub const sockaddr_storage = extern struct {
641 ss_len: u8,649 ss_len: u8,
642 ss_family: sa_family_t,650 ss_family: sa_family_t,
643 __ss_pad1: [6]u8,651 __ss_pad1: [5]u8,
644 __ss_align: i64,652 __ss_align: i64,
645 __ss_pad2: [112]u8,653 __ss_pad2: [112]u8,
646};654};
lib/std/os/bits/freebsd.zig+8
...@@ -206,6 +206,14 @@ pub const sockaddr = extern struct {...@@ -206,6 +206,14 @@ pub const sockaddr = extern struct {
206 data: [14]u8,206 data: [14]u8,
207};207};
208208
209pub const sockaddr_storage = extern struct {
210 len: u8,
211 family: sa_family_t,
212 __pad1: [5]u8,
213 __align: i64,
214 __pad2: [112]u8,
215};
216
209pub const sockaddr_in = extern struct {217pub const sockaddr_in = extern struct {
210 len: u8 = @sizeOf(sockaddr_in),218 len: u8 = @sizeOf(sockaddr_in),
211 family: sa_family_t = AF_INET,219 family: sa_family_t = AF_INET,
lib/std/os/bits/haiku.zig+8
...@@ -239,6 +239,14 @@ pub const sockaddr = extern struct {...@@ -239,6 +239,14 @@ pub const sockaddr = extern struct {
239 data: [14]u8,239 data: [14]u8,
240};240};
241241
242pub const sockaddr_storage = extern struct {
243 len: u8,
244 family: sa_family_t,
245 __pad1: [5]u8,
246 __align: i64,
247 __pad2: [112]u8,
248};
249
242pub const sockaddr_in = extern struct {250pub const sockaddr_in = extern struct {
243 len: u8 = @sizeOf(sockaddr_in),251 len: u8 = @sizeOf(sockaddr_in),
244 family: sa_family_t = AF_INET,252 family: sa_family_t = AF_INET,
lib/std/os/bits/linux.zig+7
...@@ -1149,6 +1149,13 @@ pub const sockaddr = extern struct {...@@ -1149,6 +1149,13 @@ pub const sockaddr = extern struct {
1149 data: [14]u8,1149 data: [14]u8,
1150};1150};
11511151
1152pub const sockaddr_storage = extern struct {
1153 family: sa_family_t,
1154 __pad1: [6]u8,
1155 __align: i64,
1156 __pad2: [112]u8,
1157};
1158
1152/// IPv4 socket address1159/// IPv4 socket address
1153pub const sockaddr_in = extern struct {1160pub const sockaddr_in = extern struct {
1154 family: sa_family_t = AF_INET,1161 family: sa_family_t = AF_INET,
lib/std/os/bits/netbsd.zig+8
...@@ -226,6 +226,14 @@ pub const sockaddr = extern struct {...@@ -226,6 +226,14 @@ pub const sockaddr = extern struct {
226 data: [14]u8,226 data: [14]u8,
227};227};
228228
229pub const sockaddr_storage = extern struct {
230 len: u8,
231 family: sa_family_t,
232 __pad1: [5]u8,
233 __align: i64,
234 __pad2: [112]u8,
235};
236
229pub const sockaddr_in = extern struct {237pub const sockaddr_in = extern struct {
230 len: u8 = @sizeOf(sockaddr_in),238 len: u8 = @sizeOf(sockaddr_in),
231 family: sa_family_t = AF_INET,239 family: sa_family_t = AF_INET,
lib/std/os/bits/openbsd.zig+149-9
...@@ -246,6 +246,14 @@ pub const sockaddr = extern struct {...@@ -246,6 +246,14 @@ pub const sockaddr = extern struct {
246 data: [14]u8,246 data: [14]u8,
247};247};
248248
249pub const sockaddr_storage = extern struct {
250 len: u8,
251 family: sa_family_t,
252 __pad1: [5]u8,
253 __align: i64,
254 __pad2: [112]u8,
255};
256
249pub const sockaddr_in = extern struct {257pub const sockaddr_in = extern struct {
250 len: u8 = @sizeOf(sockaddr_in),258 len: u8 = @sizeOf(sockaddr_in),
251 family: sa_family_t = AF_INET,259 family: sa_family_t = AF_INET,
...@@ -290,15 +298,6 @@ pub const AI_NUMERICSERV = 16;...@@ -290,15 +298,6 @@ pub const AI_NUMERICSERV = 16;
290/// only if any address is assigned298/// only if any address is assigned
291pub const AI_ADDRCONFIG = 64;299pub const AI_ADDRCONFIG = 64;
292300
293pub const CTL_KERN = 1;
294pub const CTL_DEBUG = 5;
295pub const CTL_HW = 6;
296
297pub const KERN_PROC_ARGS = 55;
298pub const KERN_PROC_ARGV = 1;
299
300pub const HW_NCPUONLINE = 25;
301
302pub const PATH_MAX = 1024;301pub const PATH_MAX = 1024;
303302
304pub const STDIN_FILENO = 0;303pub const STDIN_FILENO = 0;
...@@ -1229,3 +1228,144 @@ pub const POLLNORM = POLLRDNORM;...@@ -1229,3 +1228,144 @@ pub const POLLNORM = POLLRDNORM;
1229pub const POLLWRNORM = POLLOUT;1228pub const POLLWRNORM = POLLOUT;
1230pub const POLLRDBAND = 0x0080;1229pub const POLLRDBAND = 0x0080;
1231pub const POLLWRBAND = 0x0100;1230pub const POLLWRBAND = 0x0100;
1231
1232// sysctl mib
1233pub const CTL_UNSPEC = 0;
1234pub const CTL_KERN = 1;
1235pub const CTL_VM = 2;
1236pub const CTL_FS = 3;
1237pub const CTL_NET = 4;
1238pub const CTL_DEBUG = 5;
1239pub const CTL_HW = 6;
1240pub const CTL_MACHDEP = 7;
1241
1242pub const CTL_DDB = 9;
1243pub const CTL_VFS = 10;
1244
1245pub const KERN_OSTYPE = 1;
1246pub const KERN_OSRELEASE = 2;
1247pub const KERN_OSREV = 3;
1248pub const KERN_VERSION = 4;
1249pub const KERN_MAXVNODES = 5;
1250pub const KERN_MAXPROC = 6;
1251pub const KERN_MAXFILES = 7;
1252pub const KERN_ARGMAX = 8;
1253pub const KERN_SECURELVL = 9;
1254pub const KERN_HOSTNAME = 10;
1255pub const KERN_HOSTID = 11;
1256pub const KERN_CLOCKRATE = 12;
1257
1258pub const KERN_PROF = 16;
1259pub const KERN_POSIX1 = 17;
1260pub const KERN_NGROUPS = 18;
1261pub const KERN_JOB_CONTROL = 19;
1262pub const KERN_SAVED_IDS = 20;
1263pub const KERN_BOOTTIME = 21;
1264pub const KERN_DOMAINNAME = 22;
1265pub const KERN_MAXPARTITIONS = 23;
1266pub const KERN_RAWPARTITION = 24;
1267pub const KERN_MAXTHREAD = 25;
1268pub const KERN_NTHREADS = 26;
1269pub const KERN_OSVERSION = 27;
1270pub const KERN_SOMAXCONN = 28;
1271pub const KERN_SOMINCONN = 29;
1272
1273pub const KERN_NOSUIDCOREDUMP = 32;
1274pub const KERN_FSYNC = 33;
1275pub const KERN_SYSVMSG = 34;
1276pub const KERN_SYSVSEM = 35;
1277pub const KERN_SYSVSHM = 36;
1278
1279pub const KERN_MSGBUFSIZE = 38;
1280pub const KERN_MALLOCSTATS = 39;
1281pub const KERN_CPTIME = 40;
1282pub const KERN_NCHSTATS = 41;
1283pub const KERN_FORKSTAT = 42;
1284pub const KERN_NSELCOLL = 43;
1285pub const KERN_TTY = 44;
1286pub const KERN_CCPU = 45;
1287pub const KERN_FSCALE = 46;
1288pub const KERN_NPROCS = 47;
1289pub const KERN_MSGBUF = 48;
1290pub const KERN_POOL = 49;
1291pub const KERN_STACKGAPRANDOM = 50;
1292pub const KERN_SYSVIPC_INFO = 51;
1293pub const KERN_ALLOWKMEM = 52;
1294pub const KERN_WITNESSWATCH = 53;
1295pub const KERN_SPLASSERT = 54;
1296pub const KERN_PROC_ARGS = 55;
1297pub const KERN_NFILES = 56;
1298pub const KERN_TTYCOUNT = 57;
1299pub const KERN_NUMVNODES = 58;
1300pub const KERN_MBSTAT = 59;
1301pub const KERN_WITNESS = 60;
1302pub const KERN_SEMINFO = 61;
1303pub const KERN_SHMINFO = 62;
1304pub const KERN_INTRCNT = 63;
1305pub const KERN_WATCHDOG = 64;
1306pub const KERN_ALLOWDT = 65;
1307pub const KERN_PROC = 66;
1308pub const KERN_MAXCLUSTERS = 67;
1309pub const KERN_EVCOUNT = 68;
1310pub const KERN_TIMECOUNTER = 69;
1311pub const KERN_MAXLOCKSPERUID = 70;
1312pub const KERN_CPTIME2 = 71;
1313pub const KERN_CACHEPCT = 72;
1314pub const KERN_FILE = 73;
1315pub const KERN_WXABORT = 74;
1316pub const KERN_CONSDEV = 75;
1317pub const KERN_NETLIVELOCKS = 76;
1318pub const KERN_POOL_DEBUG = 77;
1319pub const KERN_PROC_CWD = 78;
1320pub const KERN_PROC_NOBROADCASTKILL = 79;
1321pub const KERN_PROC_VMMAP = 80;
1322pub const KERN_GLOBAL_PTRACE = 81;
1323pub const KERN_CONSBUFSIZE = 82;
1324pub const KERN_CONSBUF = 83;
1325pub const KERN_AUDIO = 84;
1326pub const KERN_CPUSTATS = 85;
1327pub const KERN_PFSTATUS = 86;
1328pub const KERN_TIMEOUT_STATS = 87;
1329pub const KERN_UTC_OFFSET = 88;
1330pub const KERN_VIDEO = 89;
1331
1332pub const HW_MACHINE = 1;
1333pub const HW_MODEL = 2;
1334pub const HW_NCPU = 3;
1335pub const HW_BYTEORDER = 4;
1336pub const HW_PHYSMEM = 5;
1337pub const HW_USERMEM = 6;
1338pub const HW_PAGESIZE = 7;
1339pub const HW_DISKNAMES = 8;
1340pub const HW_DISKSTATS = 9;
1341pub const HW_DISKCOUNT = 10;
1342pub const HW_SENSORS = 11;
1343pub const HW_CPUSPEED = 12;
1344pub const HW_SETPERF = 13;
1345pub const HW_VENDOR = 14;
1346pub const HW_PRODUCT = 15;
1347pub const HW_VERSION = 16;
1348pub const HW_SERIALNO = 17;
1349pub const HW_UUID = 18;
1350pub const HW_PHYSMEM64 = 19;
1351pub const HW_USERMEM64 = 20;
1352pub const HW_NCPUFOUND = 21;
1353pub const HW_ALLOWPOWERDOWN = 22;
1354pub const HW_PERFPOLICY = 23;
1355pub const HW_SMT = 24;
1356pub const HW_NCPUONLINE = 25;
1357
1358pub const KERN_PROC_ALL = 0;
1359pub const KERN_PROC_PID = 1;
1360pub const KERN_PROC_PGRP = 2;
1361pub const KERN_PROC_SESSION = 3;
1362pub const KERN_PROC_TTY = 4;
1363pub const KERN_PROC_UID = 5;
1364pub const KERN_PROC_RUID = 6;
1365pub const KERN_PROC_KTHREAD = 7;
1366pub const KERN_PROC_SHOW_THREADS = 0x40000000;
1367
1368pub const KERN_PROC_ARGV = 1;
1369pub const KERN_PROC_NARGV = 2;
1370pub const KERN_PROC_ENV = 3;
1371pub const KERN_PROC_NENV = 4;
lib/std/os/bits/windows.zig+2
...@@ -321,3 +321,5 @@ pub const O_NOATIME = 0o1000000;...@@ -321,3 +321,5 @@ pub const O_NOATIME = 0o1000000;
321pub const O_PATH = 0o10000000;321pub const O_PATH = 0o10000000;
322pub const O_TMPFILE = 0o20200000;322pub const O_TMPFILE = 0o20200000;
323pub const O_NDELAY = O_NONBLOCK;323pub const O_NDELAY = O_NONBLOCK;
324
325pub const IFNAMESIZE = 30;
lib/std/os/linux.zig+39-24
...@@ -60,15 +60,30 @@ const require_aligned_register_pair =...@@ -60,15 +60,30 @@ const require_aligned_register_pair =
60 std.Target.current.cpu.arch.isThumb();60 std.Target.current.cpu.arch.isThumb();
6161
62// Split a 64bit value into a {LSB,MSB} pair.62// Split a 64bit value into a {LSB,MSB} pair.
63fn splitValue64(val: u64) [2]u32 {63// The LE/BE variants specify the endianness to assume.
64fn splitValueLE64(val: i64) [2]u32 {
65 const u = @bitCast(u64, val);
66 return [2]u32{
67 @truncate(u32, u),
68 @truncate(u32, u >> 32),
69 };
70}
71fn splitValueBE64(val: i64) [2]u32 {
72 return [2]u32{
73 @truncate(u32, u >> 32),
74 @truncate(u32, u),
75 };
76}
77fn splitValue64(val: i64) [2]u32 {
78 const u = @bitCast(u64, val);
64 switch (native_endian) {79 switch (native_endian) {
65 .Little => return [2]u32{80 .Little => return [2]u32{
66 @truncate(u32, val),81 @truncate(u32, u),
67 @truncate(u32, val >> 32),82 @truncate(u32, u >> 32),
68 },83 },
69 .Big => return [2]u32{84 .Big => return [2]u32{
70 @truncate(u32, val >> 32),85 @truncate(u32, u >> 32),
71 @truncate(u32, val),86 @truncate(u32, u),
72 },87 },
73 }88 }
74}89}
...@@ -142,8 +157,8 @@ pub fn utimensat(dirfd: i32, path: ?[*:0]const u8, times: *const [2]timespec, fl...@@ -142,8 +157,8 @@ pub fn utimensat(dirfd: i32, path: ?[*:0]const u8, times: *const [2]timespec, fl
142 return syscall4(.utimensat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(times), flags);157 return syscall4(.utimensat, @bitCast(usize, @as(isize, dirfd)), @ptrToInt(path), @ptrToInt(times), flags);
143}158}
144159
145pub fn fallocate(fd: i32, mode: i32, offset: u64, length: u64) usize {160pub fn fallocate(fd: i32, mode: i32, offset: i64, length: i64) usize {
146 if (@sizeOf(usize) == 4) {161 if (usize_bits < 64) {
147 const offset_halves = splitValue64(offset);162 const offset_halves = splitValue64(offset);
148 const length_halves = splitValue64(length);163 const length_halves = splitValue64(length);
149 return syscall6(164 return syscall6(
...@@ -160,8 +175,8 @@ pub fn fallocate(fd: i32, mode: i32, offset: u64, length: u64) usize {...@@ -160,8 +175,8 @@ pub fn fallocate(fd: i32, mode: i32, offset: u64, length: u64) usize {
160 .fallocate,175 .fallocate,
161 @bitCast(usize, @as(isize, fd)),176 @bitCast(usize, @as(isize, fd)),
162 @bitCast(usize, @as(isize, mode)),177 @bitCast(usize, @as(isize, mode)),
163 offset,178 @bitCast(u64, offset),
164 length,179 @bitCast(u64, length),
165 );180 );
166 }181 }
167}182}
...@@ -244,7 +259,7 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {...@@ -244,7 +259,7 @@ pub fn umount2(special: [*:0]const u8, flags: u32) usize {
244 return syscall2(.umount2, @ptrToInt(special), flags);259 return syscall2(.umount2, @ptrToInt(special), flags);
245}260}
246261
247pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: u64) usize {262pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: i64) usize {
248 if (@hasField(SYS, "mmap2")) {263 if (@hasField(SYS, "mmap2")) {
249 // Make sure the offset is also specified in multiples of page size264 // Make sure the offset is also specified in multiples of page size
250 if ((offset & (MMAP2_UNIT - 1)) != 0)265 if ((offset & (MMAP2_UNIT - 1)) != 0)
...@@ -257,7 +272,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of...@@ -257,7 +272,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
257 prot,272 prot,
258 flags,273 flags,
259 @bitCast(usize, @as(isize, fd)),274 @bitCast(usize, @as(isize, fd)),
260 @truncate(usize, offset / MMAP2_UNIT),275 @truncate(usize, @bitCast(u64, offset) / MMAP2_UNIT),
261 );276 );
262 } else {277 } else {
263 return syscall6(278 return syscall6(
...@@ -267,7 +282,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of...@@ -267,7 +282,7 @@ pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, of
267 prot,282 prot,
268 flags,283 flags,
269 @bitCast(usize, @as(isize, fd)),284 @bitCast(usize, @as(isize, fd)),
270 offset,285 @bitCast(u64, offset),
271 );286 );
272 }287 }
273}288}
...@@ -309,8 +324,8 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {...@@ -309,8 +324,8 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
309 return syscall3(.read, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);324 return syscall3(.read, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
310}325}
311326
312pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {327pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: i64) usize {
313 const offset_halves = splitValue64(offset);328 const offset_halves = splitValueLE64(offset);
314 return syscall5(329 return syscall5(
315 .preadv,330 .preadv,
316 @bitCast(usize, @as(isize, fd)),331 @bitCast(usize, @as(isize, fd)),
...@@ -321,7 +336,7 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {...@@ -321,7 +336,7 @@ pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
321 );336 );
322}337}
323338
324pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: u64, flags: kernel_rwf) usize {339pub fn preadv2(fd: i32, iov: [*]const iovec, count: usize, offset: i64, flags: kernel_rwf) usize {
325 const offset_halves = splitValue64(offset);340 const offset_halves = splitValue64(offset);
326 return syscall6(341 return syscall6(
327 .preadv2,342 .preadv2,
...@@ -342,8 +357,8 @@ pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {...@@ -342,8 +357,8 @@ pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
342 return syscall3(.writev, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count);357 return syscall3(.writev, @bitCast(usize, @as(isize, fd)), @ptrToInt(iov), count);
343}358}
344359
345pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {360pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: i64) usize {
346 const offset_halves = splitValue64(offset);361 const offset_halves = splitValueLE64(offset);
347 return syscall5(362 return syscall5(
348 .pwritev,363 .pwritev,
349 @bitCast(usize, @as(isize, fd)),364 @bitCast(usize, @as(isize, fd)),
...@@ -354,7 +369,7 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us...@@ -354,7 +369,7 @@ pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) us
354 );369 );
355}370}
356371
357pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64, flags: kernel_rwf) usize {372pub fn pwritev2(fd: i32, iov: [*]const iovec_const, count: usize, offset: i64, flags: kernel_rwf) usize {
358 const offset_halves = splitValue64(offset);373 const offset_halves = splitValue64(offset);
359 return syscall6(374 return syscall6(
360 .pwritev2,375 .pwritev2,
...@@ -387,7 +402,7 @@ pub fn symlinkat(existing: [*:0]const u8, newfd: i32, newpath: [*:0]const u8) us...@@ -387,7 +402,7 @@ pub fn symlinkat(existing: [*:0]const u8, newfd: i32, newpath: [*:0]const u8) us
387 return syscall3(.symlinkat, @ptrToInt(existing), @bitCast(usize, @as(isize, newfd)), @ptrToInt(newpath));402 return syscall3(.symlinkat, @ptrToInt(existing), @bitCast(usize, @as(isize, newfd)), @ptrToInt(newpath));
388}403}
389404
390pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {405pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: i64) usize {
391 if (@hasField(SYS, "pread64") and usize_bits < 64) {406 if (@hasField(SYS, "pread64") and usize_bits < 64) {
392 const offset_halves = splitValue64(offset);407 const offset_halves = splitValue64(offset);
393 if (require_aligned_register_pair) {408 if (require_aligned_register_pair) {
...@@ -418,7 +433,7 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {...@@ -418,7 +433,7 @@ pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: u64) usize {
418 @bitCast(usize, @as(isize, fd)),433 @bitCast(usize, @as(isize, fd)),
419 @ptrToInt(buf),434 @ptrToInt(buf),
420 count,435 count,
421 offset,436 @bitCast(u64, offset),
422 );437 );
423 }438 }
424}439}
...@@ -453,7 +468,7 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {...@@ -453,7 +468,7 @@ pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
453 return syscall3(.write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);468 return syscall3(.write, @bitCast(usize, @as(isize, fd)), @ptrToInt(buf), count);
454}469}
455470
456pub fn ftruncate(fd: i32, length: u64) usize {471pub fn ftruncate(fd: i32, length: i64) usize {
457 if (@hasField(SYS, "ftruncate64") and usize_bits < 64) {472 if (@hasField(SYS, "ftruncate64") and usize_bits < 64) {
458 const length_halves = splitValue64(length);473 const length_halves = splitValue64(length);
459 if (require_aligned_register_pair) {474 if (require_aligned_register_pair) {
...@@ -476,12 +491,12 @@ pub fn ftruncate(fd: i32, length: u64) usize {...@@ -476,12 +491,12 @@ pub fn ftruncate(fd: i32, length: u64) usize {
476 return syscall2(491 return syscall2(
477 .ftruncate,492 .ftruncate,
478 @bitCast(usize, @as(isize, fd)),493 @bitCast(usize, @as(isize, fd)),
479 @truncate(usize, length),494 @bitCast(usize, length),
480 );495 );
481 }496 }
482}497}
483498
484pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {499pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: i64) usize {
485 if (@hasField(SYS, "pwrite64") and usize_bits < 64) {500 if (@hasField(SYS, "pwrite64") and usize_bits < 64) {
486 const offset_halves = splitValue64(offset);501 const offset_halves = splitValue64(offset);
487502
...@@ -513,7 +528,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {...@@ -513,7 +528,7 @@ pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: u64) usize {
513 @bitCast(usize, @as(isize, fd)),528 @bitCast(usize, @as(isize, fd)),
514 @ptrToInt(buf),529 @ptrToInt(buf),
515 count,530 count,
516 offset,531 @bitCast(u64, offset),
517 );532 );
518 }533 }
519}534}
lib/std/os/linux/test.zig+1-1
...@@ -20,7 +20,7 @@ test "fallocate" {...@@ -20,7 +20,7 @@ test "fallocate" {
2020
21 try expect((try file.stat()).size == 0);21 try expect((try file.stat()).size == 0);
2222
23 const len: u64 = 65536;23 const len: i64 = 65536;
24 switch (linux.getErrno(linux.fallocate(file.handle, 0, 0, len))) {24 switch (linux.getErrno(linux.fallocate(file.handle, 0, 0, len))) {
25 0 => {},25 0 => {},
26 linux.ENOSYS => return error.SkipZigTest,26 linux.ENOSYS => return error.SkipZigTest,
lib/std/os/test.zig-4
...@@ -263,10 +263,6 @@ test "linkat with different directories" {...@@ -263,10 +263,6 @@ test "linkat with different directories" {
263test "fstatat" {263test "fstatat" {
264 // enable when `fstat` and `fstatat` are implemented on Windows264 // enable when `fstat` and `fstatat` are implemented on Windows
265 if (builtin.os.tag == .windows) return error.SkipZigTest;265 if (builtin.os.tag == .windows) return error.SkipZigTest;
266 if (builtin.os.tag == .freebsd and builtin.mode == .ReleaseFast) {
267 // https://github.com/ziglang/zig/issues/8538
268 return error.SkipZigTest;
269 }
270266
271 var tmp = tmpDir(.{});267 var tmp = tmpDir(.{});
272 defer tmp.cleanup();268 defer tmp.cleanup();
lib/std/os/windows.zig+95
...@@ -389,6 +389,43 @@ pub fn GetQueuedCompletionStatus(...@@ -389,6 +389,43 @@ pub fn GetQueuedCompletionStatus(
389 return GetQueuedCompletionStatusResult.Normal;389 return GetQueuedCompletionStatusResult.Normal;
390}390}
391391
392pub const GetQueuedCompletionStatusError = error{
393 Aborted,
394 Cancelled,
395 EOF,
396 Timeout,
397} || std.os.UnexpectedError;
398
399pub fn GetQueuedCompletionStatusEx(
400 completion_port: HANDLE,
401 completion_port_entries: []OVERLAPPED_ENTRY,
402 timeout_ms: ?DWORD,
403 alertable: bool,
404) GetQueuedCompletionStatusError!u32 {
405 var num_entries_removed: u32 = 0;
406
407 const success = kernel32.GetQueuedCompletionStatusEx(
408 completion_port,
409 completion_port_entries.ptr,
410 @intCast(ULONG, completion_port_entries.len),
411 &num_entries_removed,
412 timeout_ms orelse INFINITE,
413 @boolToInt(alertable),
414 );
415
416 if (success == FALSE) {
417 return switch (kernel32.GetLastError()) {
418 .ABANDONED_WAIT_0 => error.Aborted,
419 .OPERATION_ABORTED => error.Cancelled,
420 .HANDLE_EOF => error.EOF,
421 .IMEOUT => error.Timeout,
422 else => |err| unexpectedError(err),
423 };
424 }
425
426 return num_entries_removed;
427}
428
392pub fn CloseHandle(hObject: HANDLE) void {429pub fn CloseHandle(hObject: HANDLE) void {
393 assert(ntdll.NtClose(hObject) == .SUCCESS);430 assert(ntdll.NtClose(hObject) == .SUCCESS);
394}431}
...@@ -1291,6 +1328,10 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so...@@ -1291,6 +1328,10 @@ pub fn getsockname(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.so
1291 return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));1328 return ws2_32.getsockname(s, name, @ptrCast(*i32, namelen));
1292}1329}
12931330
1331pub fn getpeername(s: ws2_32.SOCKET, name: *ws2_32.sockaddr, namelen: *ws2_32.socklen_t) i32 {
1332 return ws2_32.getpeername(s, name, @ptrCast(*i32, namelen));
1333}
1334
1294pub fn sendmsg(1335pub fn sendmsg(
1295 s: ws2_32.SOCKET,1336 s: ws2_32.SOCKET,
1296 msg: *const ws2_32.WSAMSG,1337 msg: *const ws2_32.WSAMSG,
...@@ -1404,6 +1445,28 @@ pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetCon...@@ -1404,6 +1445,28 @@ pub fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) SetCon
1404 }1445 }
1405}1446}
14061447
1448pub fn SetConsoleCtrlHandler(handler_routine: ?HANDLER_ROUTINE, add: bool) !void {
1449 const success = kernel32.SetConsoleCtrlHandler(
1450 handler_routine,
1451 if (add) TRUE else FALSE,
1452 );
1453
1454 if (success == FALSE) {
1455 return switch (kernel32.GetLastError()) {
1456 else => |err| unexpectedError(err),
1457 };
1458 }
1459}
1460
1461pub fn SetFileCompletionNotificationModes(handle: HANDLE, flags: UCHAR) !void {
1462 const success = kernel32.SetFileCompletionNotificationModes(handle, flags);
1463 if (success == FALSE) {
1464 return switch (kernel32.GetLastError()) {
1465 else => |err| unexpectedError(err),
1466 };
1467 }
1468}
1469
1407pub const GetEnvironmentStringsError = error{OutOfMemory};1470pub const GetEnvironmentStringsError = error{OutOfMemory};
14081471
1409pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*:0]u16 {1472pub fn GetEnvironmentStringsW() GetEnvironmentStringsError![*:0]u16 {
...@@ -1686,6 +1749,38 @@ fn MAKELANGID(p: c_ushort, s: c_ushort) callconv(.Inline) LANGID {...@@ -1686,6 +1749,38 @@ fn MAKELANGID(p: c_ushort, s: c_ushort) callconv(.Inline) LANGID {
1686 return (s << 10) | p;1749 return (s << 10) | p;
1687}1750}
16881751
1752/// Loads a Winsock extension function in runtime specified by a GUID.
1753pub fn loadWinsockExtensionFunction(comptime T: type, sock: ws2_32.SOCKET, guid: GUID) !T {
1754 var function: T = undefined;
1755 var num_bytes: DWORD = undefined;
1756
1757 const rc = ws2_32.WSAIoctl(
1758 sock,
1759 ws2_32.SIO_GET_EXTENSION_FUNCTION_POINTER,
1760 @ptrCast(*const c_void, &guid),
1761 @sizeOf(GUID),
1762 &function,
1763 @sizeOf(T),
1764 &num_bytes,
1765 null,
1766 null,
1767 );
1768
1769 if (rc == ws2_32.SOCKET_ERROR) {
1770 return switch (ws2_32.WSAGetLastError()) {
1771 .WSAEOPNOTSUPP => error.OperationNotSupported,
1772 .WSAENOTSOCK => error.FileDescriptorNotASocket,
1773 else => |err| unexpectedWSAError(err),
1774 };
1775 }
1776
1777 if (num_bytes != @sizeOf(T)) {
1778 return error.ShortRead;
1779 }
1780
1781 return function;
1782}
1783
1689/// Call this when you made a windows DLL call or something that does SetLastError1784/// Call this when you made a windows DLL call or something that does SetLastError
1690/// and you get an unexpected error.1785/// and you get an unexpected error.
1691pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {1786pub fn unexpectedError(err: Win32Error) std.os.UnexpectedError {
lib/std/os/windows/bits.zig+11-4
...@@ -1619,10 +1619,6 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct {...@@ -1619,10 +1619,6 @@ pub const MOUNTMGR_MOUNT_POINTS = extern struct {
1619};1619};
1620pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008;1620pub const IOCTL_MOUNTMGR_QUERY_POINTS: ULONG = 0x6d0008;
16211621
1622pub const SD_RECEIVE = 0;
1623pub const SD_SEND = 1;
1624pub const SD_BOTH = 2;
1625
1626pub const OBJECT_INFORMATION_CLASS = enum(c_int) {1622pub const OBJECT_INFORMATION_CLASS = enum(c_int) {
1627 ObjectBasicInformation = 0,1623 ObjectBasicInformation = 0,
1628 ObjectNameInformation = 1,1624 ObjectNameInformation = 1,
...@@ -1642,3 +1638,14 @@ pub const SRWLOCK = usize;...@@ -1642,3 +1638,14 @@ pub const SRWLOCK = usize;
1642pub const SRWLOCK_INIT: SRWLOCK = 0;1638pub const SRWLOCK_INIT: SRWLOCK = 0;
1643pub const CONDITION_VARIABLE = usize;1639pub const CONDITION_VARIABLE = usize;
1644pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = 0;1640pub const CONDITION_VARIABLE_INIT: CONDITION_VARIABLE = 0;
1641
1642pub const FILE_SKIP_COMPLETION_PORT_ON_SUCCESS = 0x1;
1643pub const FILE_SKIP_SET_EVENT_ON_HANDLE = 0x2;
1644
1645pub const CTRL_C_EVENT: DWORD = 0;
1646pub const CTRL_BREAK_EVENT: DWORD = 1;
1647pub const CTRL_CLOSE_EVENT: DWORD = 2;
1648pub const CTRL_LOGOFF_EVENT: DWORD = 5;
1649pub const CTRL_SHUTDOWN_EVENT: DWORD = 6;
1650
1651pub const HANDLER_ROUTINE = fn (dwCtrlType: DWORD) callconv(.C) BOOL;
lib/std/os/windows/kernel32.zig+18
...@@ -140,6 +140,14 @@ pub extern "kernel32" fn GetOverlappedResult(hFile: HANDLE, lpOverlapped: *OVERL...@@ -140,6 +140,14 @@ pub extern "kernel32" fn GetOverlappedResult(hFile: HANDLE, lpOverlapped: *OVERL
140140
141pub extern "kernel32" fn GetProcessHeap() callconv(WINAPI) ?HANDLE;141pub extern "kernel32" fn GetProcessHeap() callconv(WINAPI) ?HANDLE;
142pub extern "kernel32" fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) callconv(WINAPI) BOOL;142pub extern "kernel32" fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) callconv(WINAPI) BOOL;
143pub extern "kernel32" fn GetQueuedCompletionStatusEx(
144 CompletionPort: HANDLE,
145 lpCompletionPortEntries: [*]OVERLAPPED_ENTRY,
146 ulCount: ULONG,
147 ulNumEntriesRemoved: *ULONG,
148 dwMilliseconds: DWORD,
149 fAlertable: BOOL,
150) callconv(WINAPI) BOOL;
143151
144pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(WINAPI) void;152pub extern "kernel32" fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) callconv(WINAPI) void;
145pub extern "kernel32" fn GetSystemTimeAsFileTime(*FILETIME) callconv(WINAPI) void;153pub extern "kernel32" fn GetSystemTimeAsFileTime(*FILETIME) callconv(WINAPI) void;
...@@ -197,6 +205,16 @@ pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(W...@@ -197,6 +205,16 @@ pub extern "kernel32" fn RemoveDirectoryW(lpPathName: [*:0]const u16) callconv(W
197205
198pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL;206pub extern "kernel32" fn SetConsoleTextAttribute(hConsoleOutput: HANDLE, wAttributes: WORD) callconv(WINAPI) BOOL;
199207
208pub extern "kernel32" fn SetConsoleCtrlHandler(
209 HandlerRoutine: ?HANDLER_ROUTINE,
210 Add: BOOL,
211) callconv(WINAPI) BOOL;
212
213pub extern "kernel32" fn SetFileCompletionNotificationModes(
214 FileHandle: HANDLE,
215 Flags: UCHAR,
216) callconv(WINAPI) BOOL;
217
200pub extern "kernel32" fn SetFilePointerEx(218pub extern "kernel32" fn SetFilePointerEx(
201 in_fFile: HANDLE,219 in_fFile: HANDLE,
202 in_liDistanceToMove: LARGE_INTEGER,220 in_liDistanceToMove: LARGE_INTEGER,
lib/std/os/windows/ws2_32.zig+1668-246
...@@ -7,10 +7,929 @@ usingnamespace @import("bits.zig");...@@ -7,10 +7,929 @@ usingnamespace @import("bits.zig");
77
8pub const SOCKET = *opaque {};8pub const SOCKET = *opaque {};
9pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));9pub const INVALID_SOCKET = @intToPtr(SOCKET, ~@as(usize, 0));
10pub const SOCKET_ERROR = -1;
1110
11pub const GROUP = u32;
12pub const ADDRESS_FAMILY = u16;
13pub const WSAEVENT = HANDLE;
14
15// Microsoft use the signed c_int for this, but it should never be negative
16pub const socklen_t = u32;
17
18pub const LM_HB_Extension = 128;
19pub const LM_HB1_PnP = 1;
20pub const LM_HB1_PDA_Palmtop = 2;
21pub const LM_HB1_Computer = 4;
22pub const LM_HB1_Printer = 8;
23pub const LM_HB1_Modem = 16;
24pub const LM_HB1_Fax = 32;
25pub const LM_HB1_LANAccess = 64;
26pub const LM_HB2_Telephony = 1;
27pub const LM_HB2_FileServer = 2;
28pub const ATMPROTO_AALUSER = 0;
29pub const ATMPROTO_AAL1 = 1;
30pub const ATMPROTO_AAL2 = 2;
31pub const ATMPROTO_AAL34 = 3;
32pub const ATMPROTO_AAL5 = 5;
33pub const SAP_FIELD_ABSENT = 4294967294;
34pub const SAP_FIELD_ANY = 4294967295;
35pub const SAP_FIELD_ANY_AESA_SEL = 4294967290;
36pub const SAP_FIELD_ANY_AESA_REST = 4294967291;
37pub const ATM_E164 = 1;
38pub const ATM_NSAP = 2;
39pub const ATM_AESA = 2;
40pub const ATM_ADDR_SIZE = 20;
41pub const BLLI_L2_ISO_1745 = 1;
42pub const BLLI_L2_Q921 = 2;
43pub const BLLI_L2_X25L = 6;
44pub const BLLI_L2_X25M = 7;
45pub const BLLI_L2_ELAPB = 8;
46pub const BLLI_L2_HDLC_ARM = 9;
47pub const BLLI_L2_HDLC_NRM = 10;
48pub const BLLI_L2_HDLC_ABM = 11;
49pub const BLLI_L2_LLC = 12;
50pub const BLLI_L2_X75 = 13;
51pub const BLLI_L2_Q922 = 14;
52pub const BLLI_L2_USER_SPECIFIED = 16;
53pub const BLLI_L2_ISO_7776 = 17;
54pub const BLLI_L3_X25 = 6;
55pub const BLLI_L3_ISO_8208 = 7;
56pub const BLLI_L3_X223 = 8;
57pub const BLLI_L3_SIO_8473 = 9;
58pub const BLLI_L3_T70 = 10;
59pub const BLLI_L3_ISO_TR9577 = 11;
60pub const BLLI_L3_USER_SPECIFIED = 16;
61pub const BLLI_L3_IPI_SNAP = 128;
62pub const BLLI_L3_IPI_IP = 204;
63pub const BHLI_ISO = 0;
64pub const BHLI_UserSpecific = 1;
65pub const BHLI_HighLayerProfile = 2;
66pub const BHLI_VendorSpecificAppId = 3;
67pub const AAL5_MODE_MESSAGE = 1;
68pub const AAL5_MODE_STREAMING = 2;
69pub const AAL5_SSCS_NULL = 0;
70pub const AAL5_SSCS_SSCOP_ASSURED = 1;
71pub const AAL5_SSCS_SSCOP_NON_ASSURED = 2;
72pub const AAL5_SSCS_FRAME_RELAY = 4;
73pub const BCOB_A = 1;
74pub const BCOB_C = 3;
75pub const BCOB_X = 16;
76pub const TT_NOIND = 0;
77pub const TT_CBR = 4;
78pub const TT_VBR = 8;
79pub const TR_NOIND = 0;
80pub const TR_END_TO_END = 1;
81pub const TR_NO_END_TO_END = 2;
82pub const CLIP_NOT = 0;
83pub const CLIP_SUS = 32;
84pub const UP_P2P = 0;
85pub const UP_P2MP = 1;
86pub const BLLI_L2_MODE_NORMAL = 64;
87pub const BLLI_L2_MODE_EXT = 128;
88pub const BLLI_L3_MODE_NORMAL = 64;
89pub const BLLI_L3_MODE_EXT = 128;
90pub const BLLI_L3_PACKET_16 = 4;
91pub const BLLI_L3_PACKET_32 = 5;
92pub const BLLI_L3_PACKET_64 = 6;
93pub const BLLI_L3_PACKET_128 = 7;
94pub const BLLI_L3_PACKET_256 = 8;
95pub const BLLI_L3_PACKET_512 = 9;
96pub const BLLI_L3_PACKET_1024 = 10;
97pub const BLLI_L3_PACKET_2048 = 11;
98pub const BLLI_L3_PACKET_4096 = 12;
99pub const PI_ALLOWED = 0;
100pub const PI_RESTRICTED = 64;
101pub const PI_NUMBER_NOT_AVAILABLE = 128;
102pub const SI_USER_NOT_SCREENED = 0;
103pub const SI_USER_PASSED = 1;
104pub const SI_USER_FAILED = 2;
105pub const SI_NETWORK = 3;
106pub const CAUSE_LOC_USER = 0;
107pub const CAUSE_LOC_PRIVATE_LOCAL = 1;
108pub const CAUSE_LOC_PUBLIC_LOCAL = 2;
109pub const CAUSE_LOC_TRANSIT_NETWORK = 3;
110pub const CAUSE_LOC_PUBLIC_REMOTE = 4;
111pub const CAUSE_LOC_PRIVATE_REMOTE = 5;
112pub const CAUSE_LOC_INTERNATIONAL_NETWORK = 7;
113pub const CAUSE_LOC_BEYOND_INTERWORKING = 10;
114pub const CAUSE_UNALLOCATED_NUMBER = 1;
115pub const CAUSE_NO_ROUTE_TO_TRANSIT_NETWORK = 2;
116pub const CAUSE_NO_ROUTE_TO_DESTINATION = 3;
117pub const CAUSE_VPI_VCI_UNACCEPTABLE = 10;
118pub const CAUSE_NORMAL_CALL_CLEARING = 16;
119pub const CAUSE_USER_BUSY = 17;
120pub const CAUSE_NO_USER_RESPONDING = 18;
121pub const CAUSE_CALL_REJECTED = 21;
122pub const CAUSE_NUMBER_CHANGED = 22;
123pub const CAUSE_USER_REJECTS_CLIR = 23;
124pub const CAUSE_DESTINATION_OUT_OF_ORDER = 27;
125pub const CAUSE_INVALID_NUMBER_FORMAT = 28;
126pub const CAUSE_STATUS_ENQUIRY_RESPONSE = 30;
127pub const CAUSE_NORMAL_UNSPECIFIED = 31;
128pub const CAUSE_VPI_VCI_UNAVAILABLE = 35;
129pub const CAUSE_NETWORK_OUT_OF_ORDER = 38;
130pub const CAUSE_TEMPORARY_FAILURE = 41;
131pub const CAUSE_ACCESS_INFORMAION_DISCARDED = 43;
132pub const CAUSE_NO_VPI_VCI_AVAILABLE = 45;
133pub const CAUSE_RESOURCE_UNAVAILABLE = 47;
134pub const CAUSE_QOS_UNAVAILABLE = 49;
135pub const CAUSE_USER_CELL_RATE_UNAVAILABLE = 51;
136pub const CAUSE_BEARER_CAPABILITY_UNAUTHORIZED = 57;
137pub const CAUSE_BEARER_CAPABILITY_UNAVAILABLE = 58;
138pub const CAUSE_OPTION_UNAVAILABLE = 63;
139pub const CAUSE_BEARER_CAPABILITY_UNIMPLEMENTED = 65;
140pub const CAUSE_UNSUPPORTED_TRAFFIC_PARAMETERS = 73;
141pub const CAUSE_INVALID_CALL_REFERENCE = 81;
142pub const CAUSE_CHANNEL_NONEXISTENT = 82;
143pub const CAUSE_INCOMPATIBLE_DESTINATION = 88;
144pub const CAUSE_INVALID_ENDPOINT_REFERENCE = 89;
145pub const CAUSE_INVALID_TRANSIT_NETWORK_SELECTION = 91;
146pub const CAUSE_TOO_MANY_PENDING_ADD_PARTY = 92;
147pub const CAUSE_AAL_PARAMETERS_UNSUPPORTED = 93;
148pub const CAUSE_MANDATORY_IE_MISSING = 96;
149pub const CAUSE_UNIMPLEMENTED_MESSAGE_TYPE = 97;
150pub const CAUSE_UNIMPLEMENTED_IE = 99;
151pub const CAUSE_INVALID_IE_CONTENTS = 100;
152pub const CAUSE_INVALID_STATE_FOR_MESSAGE = 101;
153pub const CAUSE_RECOVERY_ON_TIMEOUT = 102;
154pub const CAUSE_INCORRECT_MESSAGE_LENGTH = 104;
155pub const CAUSE_PROTOCOL_ERROR = 111;
156pub const CAUSE_COND_UNKNOWN = 0;
157pub const CAUSE_COND_PERMANENT = 1;
158pub const CAUSE_COND_TRANSIENT = 2;
159pub const CAUSE_REASON_USER = 0;
160pub const CAUSE_REASON_IE_MISSING = 4;
161pub const CAUSE_REASON_IE_INSUFFICIENT = 8;
162pub const CAUSE_PU_PROVIDER = 0;
163pub const CAUSE_PU_USER = 8;
164pub const CAUSE_NA_NORMAL = 0;
165pub const CAUSE_NA_ABNORMAL = 4;
166pub const QOS_CLASS0 = 0;
167pub const QOS_CLASS1 = 1;
168pub const QOS_CLASS2 = 2;
169pub const QOS_CLASS3 = 3;
170pub const QOS_CLASS4 = 4;
171pub const TNS_TYPE_NATIONAL = 64;
172pub const TNS_PLAN_CARRIER_ID_CODE = 1;
173pub const SIO_GET_NUMBER_OF_ATM_DEVICES = 1343619073;
174pub const SIO_GET_ATM_ADDRESS = 3491102722;
175pub const SIO_ASSOCIATE_PVC = 2417360899;
176pub const SIO_GET_ATM_CONNECTION_ID = 1343619076;
177pub const RIO_MSG_DONT_NOTIFY = 1;
178pub const RIO_MSG_DEFER = 2;
179pub const RIO_MSG_WAITALL = 4;
180pub const RIO_MSG_COMMIT_ONLY = 8;
181pub const RIO_MAX_CQ_SIZE = 134217728;
182pub const RIO_CORRUPT_CQ = 4294967295;
183pub const WINDOWS_AF_IRDA = 26;
184pub const WCE_AF_IRDA = 22;
185pub const IRDA_PROTO_SOCK_STREAM = 1;
186pub const SOL_IRLMP = 255;
187pub const IRLMP_ENUMDEVICES = 16;
188pub const IRLMP_IAS_SET = 17;
189pub const IRLMP_IAS_QUERY = 18;
190pub const IRLMP_SEND_PDU_LEN = 19;
191pub const IRLMP_EXCLUSIVE_MODE = 20;
192pub const IRLMP_IRLPT_MODE = 21;
193pub const IRLMP_9WIRE_MODE = 22;
194pub const IRLMP_TINYTP_MODE = 23;
195pub const IRLMP_PARAMETERS = 24;
196pub const IRLMP_DISCOVERY_MODE = 25;
197pub const IRLMP_SHARP_MODE = 32;
198pub const IAS_ATTRIB_NO_CLASS = 16;
199pub const IAS_ATTRIB_NO_ATTRIB = 0;
200pub const IAS_ATTRIB_INT = 1;
201pub const IAS_ATTRIB_OCTETSEQ = 2;
202pub const IAS_ATTRIB_STR = 3;
203pub const IAS_MAX_USER_STRING = 256;
204pub const IAS_MAX_OCTET_STRING = 1024;
205pub const IAS_MAX_CLASSNAME = 64;
206pub const IAS_MAX_ATTRIBNAME = 256;
207pub const LmCharSetASCII = 0;
208pub const LmCharSetISO_8859_1 = 1;
209pub const LmCharSetISO_8859_2 = 2;
210pub const LmCharSetISO_8859_3 = 3;
211pub const LmCharSetISO_8859_4 = 4;
212pub const LmCharSetISO_8859_5 = 5;
213pub const LmCharSetISO_8859_6 = 6;
214pub const LmCharSetISO_8859_7 = 7;
215pub const LmCharSetISO_8859_8 = 8;
216pub const LmCharSetISO_8859_9 = 9;
217pub const LmCharSetUNICODE = 255;
218pub const LM_BAUD_1200 = 1200;
219pub const LM_BAUD_2400 = 2400;
220pub const LM_BAUD_9600 = 9600;
221pub const LM_BAUD_19200 = 19200;
222pub const LM_BAUD_38400 = 38400;
223pub const LM_BAUD_57600 = 57600;
224pub const LM_BAUD_115200 = 115200;
225pub const LM_BAUD_576K = 576000;
226pub const LM_BAUD_1152K = 1152000;
227pub const LM_BAUD_4M = 4000000;
228pub const LM_BAUD_16M = 16000000;
229pub const IPX_PTYPE = 16384;
230pub const IPX_FILTERPTYPE = 16385;
231pub const IPX_STOPFILTERPTYPE = 16387;
232pub const IPX_DSTYPE = 16386;
233pub const IPX_EXTENDED_ADDRESS = 16388;
234pub const IPX_RECVHDR = 16389;
235pub const IPX_MAXSIZE = 16390;
236pub const IPX_ADDRESS = 16391;
237pub const IPX_GETNETINFO = 16392;
238pub const IPX_GETNETINFO_NORIP = 16393;
239pub const IPX_SPXGETCONNECTIONSTATUS = 16395;
240pub const IPX_ADDRESS_NOTIFY = 16396;
241pub const IPX_MAX_ADAPTER_NUM = 16397;
242pub const IPX_RERIPNETNUMBER = 16398;
243pub const IPX_RECEIVE_BROADCAST = 16399;
244pub const IPX_IMMEDIATESPXACK = 16400;
245pub const IPPROTO_RM = 113;
246pub const MAX_MCAST_TTL = 255;
247pub const RM_OPTIONSBASE = 1000;
248pub const RM_RATE_WINDOW_SIZE = 1001;
249pub const RM_SET_MESSAGE_BOUNDARY = 1002;
250pub const RM_FLUSHCACHE = 1003;
251pub const RM_SENDER_WINDOW_ADVANCE_METHOD = 1004;
252pub const RM_SENDER_STATISTICS = 1005;
253pub const RM_LATEJOIN = 1006;
254pub const RM_SET_SEND_IF = 1007;
255pub const RM_ADD_RECEIVE_IF = 1008;
256pub const RM_DEL_RECEIVE_IF = 1009;
257pub const RM_SEND_WINDOW_ADV_RATE = 1010;
258pub const RM_USE_FEC = 1011;
259pub const RM_SET_MCAST_TTL = 1012;
260pub const RM_RECEIVER_STATISTICS = 1013;
261pub const RM_HIGH_SPEED_INTRANET_OPT = 1014;
262pub const SENDER_DEFAULT_RATE_KBITS_PER_SEC = 56;
263pub const SENDER_DEFAULT_WINDOW_ADV_PERCENTAGE = 15;
264pub const MAX_WINDOW_INCREMENT_PERCENTAGE = 25;
265pub const SENDER_DEFAULT_LATE_JOINER_PERCENTAGE = 0;
266pub const SENDER_MAX_LATE_JOINER_PERCENTAGE = 75;
267pub const BITS_PER_BYTE = 8;
268pub const LOG2_BITS_PER_BYTE = 3;
269
270pub const SOCKET_DEFAULT2_QM_POLICY = GUID.parse("{aec2ef9c-3a4d-4d3e-8842-239942e39a47}");
271pub const REAL_TIME_NOTIFICATION_CAPABILITY = GUID.parse("{6b59819a-5cae-492d-a901-2a3c2c50164f}");
272pub const REAL_TIME_NOTIFICATION_CAPABILITY_EX = GUID.parse("{6843da03-154a-4616-a508-44371295f96b}");
273pub const ASSOCIATE_NAMERES_CONTEXT = GUID.parse("{59a38b67-d4fe-46e1-ba3c-87ea74ca3049}");
274
275pub const WSAID_CONNECTEX = GUID{
276 .Data1 = 0x25a207b9,
277 .Data2 = 0xddf3,
278 .Data3 = 0x4660,
279 .Data4 = [8]u8{ 0x8e, 0xe9, 0x76, 0xe5, 0x8c, 0x74, 0x06, 0x3e },
280};
281
282pub const WSAID_ACCEPTEX = GUID{
283 .Data1 = 0xb5367df1,
284 .Data2 = 0xcbac,
285 .Data3 = 0x11cf,
286 .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 },
287};
288
289pub const WSAID_GETACCEPTEXSOCKADDRS = GUID{
290 .Data1 = 0xb5367df2,
291 .Data2 = 0xcbac,
292 .Data3 = 0x11cf,
293 .Data4 = [8]u8{ 0x95, 0xca, 0x00, 0x80, 0x5f, 0x48, 0xa1, 0x92 },
294};
295
296pub const WSAID_WSARECVMSG = GUID{
297 .Data1 = 0xf689d7c8,
298 .Data2 = 0x6f1f,
299 .Data3 = 0x436b,
300 .Data4 = [8]u8{ 0x8a, 0x53, 0xe5, 0x4f, 0xe3, 0x51, 0xc3, 0x22 },
301};
302
303pub const WSAID_WSAPOLL = GUID{
304 .Data1 = 0x18C76F85,
305 .Data2 = 0xDC66,
306 .Data3 = 0x4964,
307 .Data4 = [8]u8{ 0x97, 0x2E, 0x23, 0xC2, 0x72, 0x38, 0x31, 0x2B },
308};
309
310pub const WSAID_WSASENDMSG = GUID{
311 .Data1 = 0xa441e712,
312 .Data2 = 0x754f,
313 .Data3 = 0x43ca,
314 .Data4 = [8]u8{ 0x84, 0xa7, 0x0d, 0xee, 0x44, 0xcf, 0x60, 0x6d },
315};
316
317pub const TCP_INITIAL_RTO_DEFAULT_RTT = 0;
318pub const TCP_INITIAL_RTO_DEFAULT_MAX_SYN_RETRANSMISSIONS = 0;
319pub const SOCKET_SETTINGS_GUARANTEE_ENCRYPTION = 1;
320pub const SOCKET_SETTINGS_ALLOW_INSECURE = 2;
321pub const SOCKET_SETTINGS_IPSEC_SKIP_FILTER_INSTANTIATION = 1;
322pub const SOCKET_SETTINGS_IPSEC_OPTIONAL_PEER_NAME_VERIFICATION = 2;
323pub const SOCKET_SETTINGS_IPSEC_ALLOW_FIRST_INBOUND_PKT_UNENCRYPTED = 4;
324pub const SOCKET_SETTINGS_IPSEC_PEER_NAME_IS_RAW_FORMAT = 8;
325pub const SOCKET_QUERY_IPSEC2_ABORT_CONNECTION_ON_FIELD_CHANGE = 1;
326pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_MM_SA_ID = 1;
327pub const SOCKET_QUERY_IPSEC2_FIELD_MASK_QM_SA_ID = 2;
328pub const SOCKET_INFO_CONNECTION_SECURED = 1;
329pub const SOCKET_INFO_CONNECTION_ENCRYPTED = 2;
330pub const SOCKET_INFO_CONNECTION_IMPERSONATED = 4;
331pub const IN4ADDR_LOOPBACK = 16777343;
332pub const IN4ADDR_LOOPBACKPREFIX_LENGTH = 8;
333pub const IN4ADDR_LINKLOCALPREFIX_LENGTH = 16;
334pub const IN4ADDR_MULTICASTPREFIX_LENGTH = 4;
335pub const IFF_UP = 1;
336pub const IFF_BROADCAST = 2;
337pub const IFF_LOOPBACK = 4;
338pub const IFF_POINTTOPOINT = 8;
339pub const IFF_MULTICAST = 16;
340pub const IP_OPTIONS = 1;
341pub const IP_HDRINCL = 2;
342pub const IP_TOS = 3;
343pub const IP_TTL = 4;
344pub const IP_MULTICAST_IF = 9;
345pub const IP_MULTICAST_TTL = 10;
346pub const IP_MULTICAST_LOOP = 11;
347pub const IP_ADD_MEMBERSHIP = 12;
348pub const IP_DROP_MEMBERSHIP = 13;
349pub const IP_DONTFRAGMENT = 14;
350pub const IP_ADD_SOURCE_MEMBERSHIP = 15;
351pub const IP_DROP_SOURCE_MEMBERSHIP = 16;
352pub const IP_BLOCK_SOURCE = 17;
353pub const IP_UNBLOCK_SOURCE = 18;
354pub const IP_PKTINFO = 19;
355pub const IP_HOPLIMIT = 21;
356pub const IP_RECVTTL = 21;
357pub const IP_RECEIVE_BROADCAST = 22;
358pub const IP_RECVIF = 24;
359pub const IP_RECVDSTADDR = 25;
360pub const IP_IFLIST = 28;
361pub const IP_ADD_IFLIST = 29;
362pub const IP_DEL_IFLIST = 30;
363pub const IP_UNICAST_IF = 31;
364pub const IP_RTHDR = 32;
365pub const IP_GET_IFLIST = 33;
366pub const IP_RECVRTHDR = 38;
367pub const IP_TCLASS = 39;
368pub const IP_RECVTCLASS = 40;
369pub const IP_RECVTOS = 40;
370pub const IP_ORIGINAL_ARRIVAL_IF = 47;
371pub const IP_ECN = 50;
372pub const IP_PKTINFO_EX = 51;
373pub const IP_WFP_REDIRECT_RECORDS = 60;
374pub const IP_WFP_REDIRECT_CONTEXT = 70;
375pub const IP_MTU_DISCOVER = 71;
376pub const IP_MTU = 73;
377pub const IP_NRT_INTERFACE = 74;
378pub const IP_RECVERR = 75;
379pub const IP_USER_MTU = 76;
380pub const IP_UNSPECIFIED_TYPE_OF_SERVICE = -1;
381pub const IN6ADDR_LINKLOCALPREFIX_LENGTH = 64;
382pub const IN6ADDR_MULTICASTPREFIX_LENGTH = 8;
383pub const IN6ADDR_SOLICITEDNODEMULTICASTPREFIX_LENGTH = 104;
384pub const IN6ADDR_V4MAPPEDPREFIX_LENGTH = 96;
385pub const IN6ADDR_6TO4PREFIX_LENGTH = 16;
386pub const IN6ADDR_TEREDOPREFIX_LENGTH = 32;
387pub const MCAST_JOIN_GROUP = 41;
388pub const MCAST_LEAVE_GROUP = 42;
389pub const MCAST_BLOCK_SOURCE = 43;
390pub const MCAST_UNBLOCK_SOURCE = 44;
391pub const MCAST_JOIN_SOURCE_GROUP = 45;
392pub const MCAST_LEAVE_SOURCE_GROUP = 46;
393pub const IPV6_HOPOPTS = 1;
394pub const IPV6_HDRINCL = 2;
395pub const IPV6_UNICAST_HOPS = 4;
396pub const IPV6_MULTICAST_IF = 9;
397pub const IPV6_MULTICAST_HOPS = 10;
398pub const IPV6_MULTICAST_LOOP = 11;
399pub const IPV6_ADD_MEMBERSHIP = 12;
400pub const IPV6_DROP_MEMBERSHIP = 13;
401pub const IPV6_DONTFRAG = 14;
402pub const IPV6_PKTINFO = 19;
403pub const IPV6_HOPLIMIT = 21;
404pub const IPV6_PROTECTION_LEVEL = 23;
405pub const IPV6_RECVIF = 24;
406pub const IPV6_RECVDSTADDR = 25;
407pub const IPV6_CHECKSUM = 26;
408pub const IPV6_V6ONLY = 27;
409pub const IPV6_IFLIST = 28;
410pub const IPV6_ADD_IFLIST = 29;
411pub const IPV6_DEL_IFLIST = 30;
412pub const IPV6_UNICAST_IF = 31;
413pub const IPV6_RTHDR = 32;
414pub const IPV6_GET_IFLIST = 33;
415pub const IPV6_RECVRTHDR = 38;
416pub const IPV6_TCLASS = 39;
417pub const IPV6_RECVTCLASS = 40;
418pub const IPV6_ECN = 50;
419pub const IPV6_PKTINFO_EX = 51;
420pub const IPV6_WFP_REDIRECT_RECORDS = 60;
421pub const IPV6_WFP_REDIRECT_CONTEXT = 70;
422pub const IPV6_MTU_DISCOVER = 71;
423pub const IPV6_MTU = 72;
424pub const IPV6_NRT_INTERFACE = 74;
425pub const IPV6_RECVERR = 75;
426pub const IPV6_USER_MTU = 76;
427pub const IP_UNSPECIFIED_HOP_LIMIT = -1;
428pub const PROTECTION_LEVEL_UNRESTRICTED = 10;
429pub const PROTECTION_LEVEL_EDGERESTRICTED = 20;
430pub const PROTECTION_LEVEL_RESTRICTED = 30;
431pub const INET_ADDRSTRLEN = 22;
432pub const INET6_ADDRSTRLEN = 65;
433pub const TCP_OFFLOAD_NO_PREFERENCE = 0;
434pub const TCP_OFFLOAD_NOT_PREFERRED = 1;
435pub const TCP_OFFLOAD_PREFERRED = 2;
436pub const TCP_EXPEDITED_1122 = 2;
437pub const TCP_KEEPALIVE = 3;
438pub const TCP_MAXSEG = 4;
439pub const TCP_MAXRT = 5;
440pub const TCP_STDURG = 6;
441pub const TCP_NOURG = 7;
442pub const TCP_ATMARK = 8;
443pub const TCP_NOSYNRETRIES = 9;
444pub const TCP_TIMESTAMPS = 10;
445pub const TCP_OFFLOAD_PREFERENCE = 11;
446pub const TCP_CONGESTION_ALGORITHM = 12;
447pub const TCP_DELAY_FIN_ACK = 13;
448pub const TCP_MAXRTMS = 14;
449pub const TCP_FASTOPEN = 15;
450pub const TCP_KEEPCNT = 16;
451pub const TCP_KEEPINTVL = 17;
452pub const TCP_FAIL_CONNECT_ON_ICMP_ERROR = 18;
453pub const TCP_ICMP_ERROR_INFO = 19;
454pub const UDP_SEND_MSG_SIZE = 2;
455pub const UDP_RECV_MAX_COALESCED_SIZE = 3;
456pub const UDP_COALESCED_INFO = 3;
457pub const AF_UNSPEC = 0;
458pub const AF_UNIX = 1;
459pub const AF_INET = 2;
460pub const AF_IMPLINK = 3;
461pub const AF_PUP = 4;
462pub const AF_CHAOS = 5;
463pub const AF_NS = 6;
464pub const AF_ISO = 7;
465pub const AF_ECMA = 8;
466pub const AF_DATAKIT = 9;
467pub const AF_CCITT = 10;
468pub const AF_SNA = 11;
469pub const AF_DECnet = 12;
470pub const AF_DLI = 13;
471pub const AF_LAT = 14;
472pub const AF_HYLINK = 15;
473pub const AF_APPLETALK = 16;
474pub const AF_NETBIOS = 17;
475pub const AF_VOICEVIEW = 18;
476pub const AF_FIREFOX = 19;
477pub const AF_UNKNOWN1 = 20;
478pub const AF_BAN = 21;
479pub const AF_ATM = 22;
480pub const AF_INET6 = 23;
481pub const AF_CLUSTER = 24;
482pub const AF_12844 = 25;
483pub const AF_IRDA = 26;
484pub const AF_NETDES = 28;
485pub const AF_MAX = 29;
486pub const AF_TCNPROCESS = 29;
487pub const AF_TCNMESSAGE = 30;
488pub const AF_ICLFXBM = 31;
489pub const AF_LINK = 33;
490pub const AF_HYPERV = 34;
491pub const SOCK_STREAM = 1;
492pub const SOCK_DGRAM = 2;
493pub const SOCK_RAW = 3;
494pub const SOCK_RDM = 4;
495pub const SOCK_SEQPACKET = 5;
496pub const SOL_SOCKET = 65535;
497pub const SO_DEBUG = 1;
498pub const SO_ACCEPTCONN = 2;
499pub const SO_REUSEADDR = 4;
500pub const SO_KEEPALIVE = 8;
501pub const SO_DONTROUTE = 16;
502pub const SO_BROADCAST = 32;
503pub const SO_USELOOPBACK = 64;
504pub const SO_LINGER = 128;
505pub const SO_OOBINLINE = 256;
506pub const SO_SNDBUF = 4097;
507pub const SO_RCVBUF = 4098;
508pub const SO_SNDLOWAT = 4099;
509pub const SO_RCVLOWAT = 4100;
510pub const SO_SNDTIMEO = 4101;
511pub const SO_RCVTIMEO = 4102;
512pub const SO_ERROR = 4103;
513pub const SO_TYPE = 4104;
514pub const SO_BSP_STATE = 4105;
515pub const SO_GROUP_ID = 8193;
516pub const SO_GROUP_PRIORITY = 8194;
517pub const SO_MAX_MSG_SIZE = 8195;
518pub const SO_CONDITIONAL_ACCEPT = 12290;
519pub const SO_PAUSE_ACCEPT = 12291;
520pub const SO_COMPARTMENT_ID = 12292;
521pub const SO_RANDOMIZE_PORT = 12293;
522pub const SO_PORT_SCALABILITY = 12294;
523pub const SO_REUSE_UNICASTPORT = 12295;
524pub const SO_REUSE_MULTICASTPORT = 12296;
525pub const SO_ORIGINAL_DST = 12303;
526pub const WSK_SO_BASE = 16384;
527pub const TCP_NODELAY = 1;
528pub const IOC_UNIX = 0;
529pub const IOC_WS2 = 134217728;
530pub const IOC_PROTOCOL = 268435456;
531pub const IOC_VENDOR = 402653184;
532pub const SIO_GET_EXTENSION_FUNCTION_POINTER = IOC_OUT | IOC_IN | IOC_WS2 | 6;
533pub const SIO_BSP_HANDLE = IOC_OUT | IOC_WS2 | 27;
534pub const SIO_BSP_HANDLE_SELECT = IOC_OUT | IOC_WS2 | 28;
535pub const SIO_BSP_HANDLE_POLL = IOC_OUT | IOC_WS2 | 29;
536pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;
537pub const IPPROTO_IP = 0;
538pub const IPPORT_TCPMUX = 1;
539pub const IPPORT_ECHO = 7;
540pub const IPPORT_DISCARD = 9;
541pub const IPPORT_SYSTAT = 11;
542pub const IPPORT_DAYTIME = 13;
543pub const IPPORT_NETSTAT = 15;
544pub const IPPORT_QOTD = 17;
545pub const IPPORT_MSP = 18;
546pub const IPPORT_CHARGEN = 19;
547pub const IPPORT_FTP_DATA = 20;
548pub const IPPORT_FTP = 21;
549pub const IPPORT_TELNET = 23;
550pub const IPPORT_SMTP = 25;
551pub const IPPORT_TIMESERVER = 37;
552pub const IPPORT_NAMESERVER = 42;
553pub const IPPORT_WHOIS = 43;
554pub const IPPORT_MTP = 57;
555pub const IPPORT_TFTP = 69;
556pub const IPPORT_RJE = 77;
557pub const IPPORT_FINGER = 79;
558pub const IPPORT_TTYLINK = 87;
559pub const IPPORT_SUPDUP = 95;
560pub const IPPORT_POP3 = 110;
561pub const IPPORT_NTP = 123;
562pub const IPPORT_EPMAP = 135;
563pub const IPPORT_NETBIOS_NS = 137;
564pub const IPPORT_NETBIOS_DGM = 138;
565pub const IPPORT_NETBIOS_SSN = 139;
566pub const IPPORT_IMAP = 143;
567pub const IPPORT_SNMP = 161;
568pub const IPPORT_SNMP_TRAP = 162;
569pub const IPPORT_IMAP3 = 220;
570pub const IPPORT_LDAP = 389;
571pub const IPPORT_HTTPS = 443;
572pub const IPPORT_MICROSOFT_DS = 445;
573pub const IPPORT_EXECSERVER = 512;
574pub const IPPORT_LOGINSERVER = 513;
575pub const IPPORT_CMDSERVER = 514;
576pub const IPPORT_EFSSERVER = 520;
577pub const IPPORT_BIFFUDP = 512;
578pub const IPPORT_WHOSERVER = 513;
579pub const IPPORT_ROUTESERVER = 520;
580pub const IPPORT_RESERVED = 1024;
581pub const IPPORT_REGISTERED_MAX = 49151;
582pub const IPPORT_DYNAMIC_MIN = 49152;
583pub const IPPORT_DYNAMIC_MAX = 65535;
584pub const IN_CLASSA_NET = 4278190080;
585pub const IN_CLASSA_NSHIFT = 24;
586pub const IN_CLASSA_HOST = 16777215;
587pub const IN_CLASSA_MAX = 128;
588pub const IN_CLASSB_NET = 4294901760;
589pub const IN_CLASSB_NSHIFT = 16;
590pub const IN_CLASSB_HOST = 65535;
591pub const IN_CLASSB_MAX = 65536;
592pub const IN_CLASSC_NET = 4294967040;
593pub const IN_CLASSC_NSHIFT = 8;
594pub const IN_CLASSC_HOST = 255;
595pub const IN_CLASSD_NET = 4026531840;
596pub const IN_CLASSD_NSHIFT = 28;
597pub const IN_CLASSD_HOST = 268435455;
598pub const INADDR_LOOPBACK = 2130706433;
599pub const INADDR_NONE = 4294967295;
600pub const IOCPARM_MASK = 127;
601pub const IOC_VOID = 536870912;
602pub const IOC_OUT = 1073741824;
603pub const IOC_IN = 2147483648;
604pub const MSG_TRUNC = 256;
605pub const MSG_CTRUNC = 512;
606pub const MSG_BCAST = 1024;
607pub const MSG_MCAST = 2048;
608pub const MSG_ERRQUEUE = 4096;
609pub const AI_PASSIVE = 1;
610pub const AI_CANONNAME = 2;
611pub const AI_NUMERICHOST = 4;
612pub const AI_NUMERICSERV = 8;
613pub const AI_DNS_ONLY = 16;
614pub const AI_ALL = 256;
615pub const AI_ADDRCONFIG = 1024;
616pub const AI_V4MAPPED = 2048;
617pub const AI_NON_AUTHORITATIVE = 16384;
618pub const AI_SECURE = 32768;
619pub const AI_RETURN_PREFERRED_NAMES = 65536;
620pub const AI_FQDN = 131072;
621pub const AI_FILESERVER = 262144;
622pub const AI_DISABLE_IDN_ENCODING = 524288;
623pub const AI_EXTENDED = 2147483648;
624pub const AI_RESOLUTION_HANDLE = 1073741824;
625pub const FIONBIO = -2147195266;
626pub const ADDRINFOEX_VERSION_2 = 2;
627pub const ADDRINFOEX_VERSION_3 = 3;
628pub const ADDRINFOEX_VERSION_4 = 4;
629pub const NS_ALL = 0;
630pub const NS_SAP = 1;
631pub const NS_NDS = 2;
632pub const NS_PEER_BROWSE = 3;
633pub const NS_SLP = 5;
634pub const NS_DHCP = 6;
635pub const NS_TCPIP_LOCAL = 10;
636pub const NS_TCPIP_HOSTS = 11;
637pub const NS_DNS = 12;
638pub const NS_NETBT = 13;
639pub const NS_WINS = 14;
640pub const NS_NLA = 15;
641pub const NS_NBP = 20;
642pub const NS_MS = 30;
643pub const NS_STDA = 31;
644pub const NS_NTDS = 32;
645pub const NS_EMAIL = 37;
646pub const NS_X500 = 40;
647pub const NS_NIS = 41;
648pub const NS_NISPLUS = 42;
649pub const NS_WRQ = 50;
650pub const NS_NETDES = 60;
651pub const NI_NOFQDN = 1;
652pub const NI_NUMERICHOST = 2;
653pub const NI_NAMEREQD = 4;
654pub const NI_NUMERICSERV = 8;
655pub const NI_DGRAM = 16;
656pub const NI_MAXHOST = 1025;
657pub const NI_MAXSERV = 32;
658pub const INCL_WINSOCK_API_PROTOTYPES = 1;
659pub const INCL_WINSOCK_API_TYPEDEFS = 0;
660pub const FD_SETSIZE = 64;
661pub const IMPLINK_IP = 155;
662pub const IMPLINK_LOWEXPER = 156;
663pub const IMPLINK_HIGHEXPER = 158;
12pub const WSADESCRIPTION_LEN = 256;664pub const WSADESCRIPTION_LEN = 256;
13pub const WSASYS_STATUS_LEN = 128;665pub const WSASYS_STATUS_LEN = 128;
666pub const SOCKET_ERROR = -1;
667pub const FROM_PROTOCOL_INFO = -1;
668pub const SO_PROTOCOL_INFOA = 8196;
669pub const SO_PROTOCOL_INFOW = 8197;
670pub const PVD_CONFIG = 12289;
671pub const SOMAXCONN = 2147483647;
672pub const MSG_PEEK = 2;
673pub const MSG_WAITALL = 8;
674pub const MSG_PUSH_IMMEDIATE = 32;
675pub const MSG_PARTIAL = 32768;
676pub const MSG_INTERRUPT = 16;
677pub const MSG_MAXIOVLEN = 16;
678pub const MAXGETHOSTSTRUCT = 1024;
679pub const FD_READ_BIT = 0;
680pub const FD_WRITE_BIT = 1;
681pub const FD_OOB_BIT = 2;
682pub const FD_ACCEPT_BIT = 3;
683pub const FD_CONNECT_BIT = 4;
684pub const FD_CLOSE_BIT = 5;
685pub const FD_QOS_BIT = 6;
686pub const FD_GROUP_QOS_BIT = 7;
687pub const FD_ROUTING_INTERFACE_CHANGE_BIT = 8;
688pub const FD_ADDRESS_LIST_CHANGE_BIT = 9;
689pub const FD_MAX_EVENTS = 10;
690pub const CF_ACCEPT = 0;
691pub const CF_REJECT = 1;
692pub const CF_DEFER = 2;
693pub const SD_RECEIVE = 0;
694pub const SD_SEND = 1;
695pub const SD_BOTH = 2;
696pub const SG_UNCONSTRAINED_GROUP = 1;
697pub const SG_CONSTRAINED_GROUP = 2;
698pub const MAX_PROTOCOL_CHAIN = 7;
699pub const BASE_PROTOCOL = 1;
700pub const LAYERED_PROTOCOL = 0;
701pub const WSAPROTOCOL_LEN = 255;
702pub const PFL_MULTIPLE_PROTO_ENTRIES = 1;
703pub const PFL_RECOMMENDED_PROTO_ENTRY = 2;
704pub const PFL_HIDDEN = 4;
705pub const PFL_MATCHES_PROTOCOL_ZERO = 8;
706pub const PFL_NETWORKDIRECT_PROVIDER = 16;
707pub const XP1_CONNECTIONLESS = 1;
708pub const XP1_GUARANTEED_DELIVERY = 2;
709pub const XP1_GUARANTEED_ORDER = 4;
710pub const XP1_MESSAGE_ORIENTED = 8;
711pub const XP1_PSEUDO_STREAM = 16;
712pub const XP1_GRACEFUL_CLOSE = 32;
713pub const XP1_EXPEDITED_DATA = 64;
714pub const XP1_CONNECT_DATA = 128;
715pub const XP1_DISCONNECT_DATA = 256;
716pub const XP1_SUPPORT_BROADCAST = 512;
717pub const XP1_SUPPORT_MULTIPOINT = 1024;
718pub const XP1_MULTIPOINT_CONTROL_PLANE = 2048;
719pub const XP1_MULTIPOINT_DATA_PLANE = 4096;
720pub const XP1_QOS_SUPPORTED = 8192;
721pub const XP1_INTERRUPT = 16384;
722pub const XP1_UNI_SEND = 32768;
723pub const XP1_UNI_RECV = 65536;
724pub const XP1_IFS_HANDLES = 131072;
725pub const XP1_PARTIAL_MESSAGE = 262144;
726pub const XP1_SAN_SUPPORT_SDP = 524288;
727pub const BIGENDIAN = 0;
728pub const LITTLEENDIAN = 1;
729pub const SECURITY_PROTOCOL_NONE = 0;
730pub const JL_SENDER_ONLY = 1;
731pub const JL_RECEIVER_ONLY = 2;
732pub const JL_BOTH = 4;
733pub const WSA_FLAG_OVERLAPPED = 1;
734pub const WSA_FLAG_MULTIPOINT_C_ROOT = 2;
735pub const WSA_FLAG_MULTIPOINT_C_LEAF = 4;
736pub const WSA_FLAG_MULTIPOINT_D_ROOT = 8;
737pub const WSA_FLAG_MULTIPOINT_D_LEAF = 16;
738pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 64;
739pub const WSA_FLAG_NO_HANDLE_INHERIT = 128;
740pub const WSA_FLAG_REGISTERED_IO = 256;
741pub const TH_NETDEV = 1;
742pub const TH_TAPI = 2;
743pub const SERVICE_MULTIPLE = 1;
744pub const NS_LOCALNAME = 19;
745pub const RES_UNUSED_1 = 1;
746pub const RES_FLUSH_CACHE = 2;
747pub const RES_SERVICE = 4;
748pub const LUP_DEEP = 1;
749pub const LUP_CONTAINERS = 2;
750pub const LUP_NOCONTAINERS = 4;
751pub const LUP_NEAREST = 8;
752pub const LUP_RETURN_NAME = 16;
753pub const LUP_RETURN_TYPE = 32;
754pub const LUP_RETURN_VERSION = 64;
755pub const LUP_RETURN_COMMENT = 128;
756pub const LUP_RETURN_ADDR = 256;
757pub const LUP_RETURN_BLOB = 512;
758pub const LUP_RETURN_ALIASES = 1024;
759pub const LUP_RETURN_QUERY_STRING = 2048;
760pub const LUP_RETURN_ALL = 4080;
761pub const LUP_RES_SERVICE = 32768;
762pub const LUP_FLUSHCACHE = 4096;
763pub const LUP_FLUSHPREVIOUS = 8192;
764pub const LUP_NON_AUTHORITATIVE = 16384;
765pub const LUP_SECURE = 32768;
766pub const LUP_RETURN_PREFERRED_NAMES = 65536;
767pub const LUP_DNS_ONLY = 131072;
768pub const LUP_ADDRCONFIG = 1048576;
769pub const LUP_DUAL_ADDR = 2097152;
770pub const LUP_FILESERVER = 4194304;
771pub const LUP_DISABLE_IDN_ENCODING = 8388608;
772pub const LUP_API_ANSI = 16777216;
773pub const LUP_RESOLUTION_HANDLE = 2147483648;
774pub const RESULT_IS_ALIAS = 1;
775pub const RESULT_IS_ADDED = 16;
776pub const RESULT_IS_CHANGED = 32;
777pub const RESULT_IS_DELETED = 64;
778pub const POLLRDNORM = 256;
779pub const POLLRDBAND = 512;
780pub const POLLPRI = 1024;
781pub const POLLWRNORM = 16;
782pub const POLLWRBAND = 32;
783pub const POLLERR = 1;
784pub const POLLHUP = 2;
785pub const POLLNVAL = 4;
786pub const SO_CONNDATA = 28672;
787pub const SO_CONNOPT = 28673;
788pub const SO_DISCDATA = 28674;
789pub const SO_DISCOPT = 28675;
790pub const SO_CONNDATALEN = 28676;
791pub const SO_CONNOPTLEN = 28677;
792pub const SO_DISCDATALEN = 28678;
793pub const SO_DISCOPTLEN = 28679;
794pub const SO_OPENTYPE = 28680;
795pub const SO_SYNCHRONOUS_ALERT = 16;
796pub const SO_SYNCHRONOUS_NONALERT = 32;
797pub const SO_MAXDG = 28681;
798pub const SO_MAXPATHDG = 28682;
799pub const SO_UPDATE_ACCEPT_CONTEXT = 28683;
800pub const SO_CONNECT_TIME = 28684;
801pub const SO_UPDATE_CONNECT_CONTEXT = 28688;
802pub const TCP_BSDURGENT = 28672;
803pub const TF_DISCONNECT = 1;
804pub const TF_REUSE_SOCKET = 2;
805pub const TF_WRITE_BEHIND = 4;
806pub const TF_USE_DEFAULT_WORKER = 0;
807pub const TF_USE_SYSTEM_THREAD = 16;
808pub const TF_USE_KERNEL_APC = 32;
809pub const TP_ELEMENT_MEMORY = 1;
810pub const TP_ELEMENT_FILE = 2;
811pub const TP_ELEMENT_EOP = 4;
812pub const NLA_ALLUSERS_NETWORK = 1;
813pub const NLA_FRIENDLY_NAME = 2;
814pub const WSPDESCRIPTION_LEN = 255;
815pub const WSS_OPERATION_IN_PROGRESS = 259;
816pub const LSP_SYSTEM = 2147483648;
817pub const LSP_INSPECTOR = 1;
818pub const LSP_REDIRECTOR = 2;
819pub const LSP_PROXY = 4;
820pub const LSP_FIREWALL = 8;
821pub const LSP_INBOUND_MODIFY = 16;
822pub const LSP_OUTBOUND_MODIFY = 32;
823pub const LSP_CRYPTO_COMPRESS = 64;
824pub const LSP_LOCAL_CACHE = 128;
825pub const IPPROTO_ICMP = 1;
826pub const IPPROTO_IGMP = 2;
827pub const IPPROTO_GGP = 3;
828pub const IPPROTO_TCP = 6;
829pub const IPPROTO_PUP = 12;
830pub const IPPROTO_UDP = 17;
831pub const IPPROTO_IDP = 22;
832pub const IPPROTO_ND = 77;
833pub const IPPROTO_RAW = 255;
834pub const IPPROTO_MAX = 256;
835pub const IP_DEFAULT_MULTICAST_TTL = 1;
836pub const IP_DEFAULT_MULTICAST_LOOP = 1;
837pub const IP_MAX_MEMBERSHIPS = 20;
838pub const AF_IPX = 6;
839pub const FD_READ = 1;
840pub const FD_WRITE = 2;
841pub const FD_OOB = 4;
842pub const FD_ACCEPT = 8;
843pub const FD_CONNECT = 16;
844pub const FD_CLOSE = 32;
845pub const SERVICE_RESOURCE = 1;
846pub const SERVICE_SERVICE = 2;
847pub const SERVICE_LOCAL = 4;
848pub const SERVICE_FLAG_DEFER = 1;
849pub const SERVICE_FLAG_HARD = 2;
850pub const PROP_COMMENT = 1;
851pub const PROP_LOCALE = 2;
852pub const PROP_DISPLAY_HINT = 4;
853pub const PROP_VERSION = 8;
854pub const PROP_START_TIME = 16;
855pub const PROP_MACHINE = 32;
856pub const PROP_ADDRESSES = 256;
857pub const PROP_SD = 512;
858pub const PROP_ALL = 2147483648;
859pub const SERVICE_ADDRESS_FLAG_RPC_CN = 1;
860pub const SERVICE_ADDRESS_FLAG_RPC_DG = 2;
861pub const SERVICE_ADDRESS_FLAG_RPC_NB = 4;
862pub const NS_DEFAULT = 0;
863pub const NS_VNS = 50;
864pub const NSTYPE_HIERARCHICAL = 1;
865pub const NSTYPE_DYNAMIC = 2;
866pub const NSTYPE_ENUMERABLE = 4;
867pub const NSTYPE_WORKGROUP = 8;
868pub const XP_CONNECTIONLESS = 1;
869pub const XP_GUARANTEED_DELIVERY = 2;
870pub const XP_GUARANTEED_ORDER = 4;
871pub const XP_MESSAGE_ORIENTED = 8;
872pub const XP_PSEUDO_STREAM = 16;
873pub const XP_GRACEFUL_CLOSE = 32;
874pub const XP_EXPEDITED_DATA = 64;
875pub const XP_CONNECT_DATA = 128;
876pub const XP_DISCONNECT_DATA = 256;
877pub const XP_SUPPORTS_BROADCAST = 512;
878pub const XP_SUPPORTS_MULTICAST = 1024;
879pub const XP_BANDWIDTH_ALLOCATION = 2048;
880pub const XP_FRAGMENTATION = 4096;
881pub const XP_ENCRYPTS = 8192;
882pub const RES_SOFT_SEARCH = 1;
883pub const RES_FIND_MULTIPLE = 2;
884pub const SET_SERVICE_PARTIAL_SUCCESS = 1;
885pub const UDP_NOCHECKSUM = 1;
886pub const UDP_CHECKSUM_COVERAGE = 20;
887pub const GAI_STRERROR_BUFFER_SIZE = 1024;
888
889pub const LPCONDITIONPROC = fn (
890 lpCallerId: *WSABUF,
891 lpCallerData: *WSABUF,
892 lpSQOS: *QOS,
893 lpGQOS: *QOS,
894 lpCalleeId: *WSABUF,
895 lpCalleeData: *WSABUF,
896 g: *u32,
897 dwCallbackData: usize,
898) callconv(WINAPI) i32;
899
900pub const LPWSAOVERLAPPED_COMPLETION_ROUTINE = fn (
901 dwError: u32,
902 cbTransferred: u32,
903 lpOverlapped: *OVERLAPPED,
904 dwFlags: u32,
905) callconv(WINAPI) void;
906
907pub const FLOWSPEC = extern struct {
908 TokenRate: u32,
909 TokenBucketSize: u32,
910 PeakBandwidth: u32,
911 Latency: u32,
912 DelayVariation: u32,
913 ServiceType: u32,
914 MaxSduSize: u32,
915 MinimumPolicedSize: u32,
916};
917
918pub const QOS = extern struct {
919 SendingFlowspec: FLOWSPEC,
920 ReceivingFlowspec: FLOWSPEC,
921 ProviderSpecific: WSABUF,
922};
923
924pub const SOCKET_ADDRESS = extern struct {
925 lpSockaddr: *sockaddr,
926 iSockaddrLength: i32,
927};
928
929pub const SOCKET_ADDRESS_LIST = extern struct {
930 iAddressCount: i32,
931 Address: [1]SOCKET_ADDRESS,
932};
14933
15pub const WSADATA = if (@sizeOf(usize) == @sizeOf(u64))934pub const WSADATA = if (@sizeOf(usize) == @sizeOf(u64))
16 extern struct {935 extern struct {
...@@ -33,15 +952,11 @@ else...@@ -33,15 +952,11 @@ else
33 lpVendorInfo: *u8,952 lpVendorInfo: *u8,
34 };953 };
35954
36pub const MAX_PROTOCOL_CHAIN = 7;
37
38pub const WSAPROTOCOLCHAIN = extern struct {955pub const WSAPROTOCOLCHAIN = extern struct {
39 ChainLen: c_int,956 ChainLen: c_int,
40 ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD,957 ChainEntries: [MAX_PROTOCOL_CHAIN]DWORD,
41};958};
42959
43pub const WSAPROTOCOL_LEN = 255;
44
45pub const WSAPROTOCOL_INFOA = extern struct {960pub const WSAPROTOCOL_INFOA = extern struct {
46 dwServiceFlags1: DWORD,961 dwServiceFlags1: DWORD,
47 dwServiceFlags2: DWORD,962 dwServiceFlags2: DWORD,
...@@ -88,20 +1003,20 @@ pub const WSAPROTOCOL_INFOW = extern struct {...@@ -88,20 +1003,20 @@ pub const WSAPROTOCOL_INFOW = extern struct {
88 szProtocol: [WSAPROTOCOL_LEN + 1]WCHAR,1003 szProtocol: [WSAPROTOCOL_LEN + 1]WCHAR,
89};1004};
901005
91pub const GROUP = u32;1006pub const sockproto = extern struct {
921007 sp_family: u16,
93pub const SG_UNCONSTRAINED_GROUP = 0x1;1008 sp_protocol: u16,
94pub const SG_CONSTRAINED_GROUP = 0x2;1009};
951010
96pub const WSA_FLAG_OVERLAPPED = 0x01;1011pub const linger = extern struct {
97pub const WSA_FLAG_MULTIPOINT_C_ROOT = 0x02;1012 l_onoff: u16,
98pub const WSA_FLAG_MULTIPOINT_C_LEAF = 0x04;1013 l_linger: u16,
99pub const WSA_FLAG_MULTIPOINT_D_ROOT = 0x08;1014};
100pub const WSA_FLAG_MULTIPOINT_D_LEAF = 0x10;
101pub const WSA_FLAG_ACCESS_SYSTEM_SECURITY = 0x40;
102pub const WSA_FLAG_NO_HANDLE_INHERIT = 0x80;
1031015
104pub const WSAEVENT = HANDLE;1016pub const WSANETWORKEVENTS = extern struct {
1017 lNetworkEvents: i32,
1018 iErrorCode: [10]i32,
1019};
1051020
106pub const WSAOVERLAPPED = extern struct {1021pub const WSAOVERLAPPED = extern struct {
107 Internal: DWORD,1022 Internal: DWORD,
...@@ -111,82 +1026,9 @@ pub const WSAOVERLAPPED = extern struct {...@@ -111,82 +1026,9 @@ pub const WSAOVERLAPPED = extern struct {
111 hEvent: ?WSAEVENT,1026 hEvent: ?WSAEVENT,
112};1027};
1131028
114pub const WSAOVERLAPPED_COMPLETION_ROUTINE = fn (dwError: DWORD, cbTransferred: DWORD, lpOverlapped: *WSAOVERLAPPED, dwFlags: DWORD) callconv(.C) void;1029pub const addrinfo = addrinfoa;
115
116pub const ADDRESS_FAMILY = u16;
117
118// Microsoft use the signed c_int for this, but it should never be negative
119pub const socklen_t = u32;
1201030
121pub const AF_UNSPEC = 0;1031pub const addrinfoa = extern struct {
122pub const AF_UNIX = 1;
123pub const AF_INET = 2;
124pub const AF_IMPLINK = 3;
125pub const AF_PUP = 4;
126pub const AF_CHAOS = 5;
127pub const AF_NS = 6;
128pub const AF_IPX = AF_NS;
129pub const AF_ISO = 7;
130pub const AF_OSI = AF_ISO;
131pub const AF_ECMA = 8;
132pub const AF_DATAKIT = 9;
133pub const AF_CCITT = 10;
134pub const AF_SNA = 11;
135pub const AF_DECnet = 12;
136pub const AF_DLI = 13;
137pub const AF_LAT = 14;
138pub const AF_HYLINK = 15;
139pub const AF_APPLETALK = 16;
140pub const AF_NETBIOS = 17;
141pub const AF_VOICEVIEW = 18;
142pub const AF_FIREFOX = 19;
143pub const AF_UNKNOWN1 = 20;
144pub const AF_BAN = 21;
145pub const AF_ATM = 22;
146pub const AF_INET6 = 23;
147pub const AF_CLUSTER = 24;
148pub const AF_12844 = 25;
149pub const AF_IRDA = 26;
150pub const AF_NETDES = 28;
151pub const AF_TCNPROCESS = 29;
152pub const AF_TCNMESSAGE = 30;
153pub const AF_ICLFXBM = 31;
154pub const AF_BTH = 32;
155pub const AF_MAX = 33;
156
157pub const SOCK_STREAM = 1;
158pub const SOCK_DGRAM = 2;
159pub const SOCK_RAW = 3;
160pub const SOCK_RDM = 4;
161pub const SOCK_SEQPACKET = 5;
162
163pub const IPPROTO_ICMP = 1;
164pub const IPPROTO_IGMP = 2;
165pub const BTHPROTO_RFCOMM = 3;
166pub const IPPROTO_TCP = 6;
167pub const IPPROTO_UDP = 17;
168pub const IPPROTO_ICMPV6 = 58;
169pub const IPPROTO_RM = 113;
170
171pub const AI_PASSIVE = 0x00001;
172pub const AI_CANONNAME = 0x00002;
173pub const AI_NUMERICHOST = 0x00004;
174pub const AI_NUMERICSERV = 0x00008;
175pub const AI_ADDRCONFIG = 0x00400;
176pub const AI_V4MAPPED = 0x00800;
177pub const AI_NON_AUTHORITATIVE = 0x04000;
178pub const AI_SECURE = 0x08000;
179pub const AI_RETURN_PREFERRED_NAMES = 0x10000;
180pub const AI_DISABLE_IDN_ENCODING = 0x80000;
181
182pub const FIONBIO = -2147195266;
183
184pub const sockaddr = extern struct {
185 family: ADDRESS_FAMILY,
186 data: [14]u8,
187};
188
189pub const addrinfo = extern struct {
190 flags: i32,1032 flags: i32,
191 family: i32,1033 family: i32,
192 socktype: i32,1034 socktype: i32,
...@@ -197,6 +1039,32 @@ pub const addrinfo = extern struct {...@@ -197,6 +1039,32 @@ pub const addrinfo = extern struct {
197 next: ?*addrinfo,1039 next: ?*addrinfo,
198};1040};
1991041
1042pub const addrinfoexA = extern struct {
1043 ai_flags: i32,
1044 ai_family: i32,
1045 ai_socktype: i32,
1046 ai_protocol: i32,
1047 ai_addrlen: usize,
1048 ai_canonname: [*:0]u8,
1049 ai_addr: *sockaddr,
1050 ai_blob: *c_void,
1051 ai_bloblen: usize,
1052 ai_provider: *GUID,
1053 ai_next: *addrinfoexA,
1054};
1055
1056pub const sockaddr = extern struct {
1057 family: ADDRESS_FAMILY,
1058 data: [14]u8,
1059};
1060
1061pub const sockaddr_storage = extern struct {
1062 family: ADDRESS_FAMILY,
1063 __pad1: [6]u8,
1064 __align: i64,
1065 __pad2: [112]u8,
1066};
1067
200/// IPv4 socket address1068/// IPv4 socket address
201pub const sockaddr_in = extern struct {1069pub const sockaddr_in = extern struct {
202 family: ADDRESS_FAMILY = AF_INET,1070 family: ADDRESS_FAMILY = AF_INET,
...@@ -225,7 +1093,10 @@ pub const WSABUF = extern struct {...@@ -225,7 +1093,10 @@ pub const WSABUF = extern struct {
225 buf: [*]u8,1093 buf: [*]u8,
226};1094};
2271095
228pub const WSAMSG = extern struct {1096pub const msghdr = WSAMSG;
1097pub const msghdr_const = WSAMSG_const;
1098
1099pub const WSAMSG_const = extern struct {
229 name: *const sockaddr,1100 name: *const sockaddr,
230 namelen: INT,1101 namelen: INT,
231 lpBuffers: [*]WSABUF,1102 lpBuffers: [*]WSABUF,
...@@ -234,26 +1105,108 @@ pub const WSAMSG = extern struct {...@@ -234,26 +1105,108 @@ pub const WSAMSG = extern struct {
234 dwFlags: DWORD,1105 dwFlags: DWORD,
235};1106};
2361107
1108pub const WSAMSG = extern struct {
1109 name: *sockaddr,
1110 namelen: INT,
1111 lpBuffers: [*]WSABUF,
1112 dwBufferCount: DWORD,
1113 Control: WSABUF,
1114 dwFlags: DWORD,
1115};
1116
1117pub const WSAPOLLFD = pollfd;
1118
237pub const pollfd = extern struct {1119pub const pollfd = extern struct {
238 fd: SOCKET,1120 fd: SOCKET,
239 events: SHORT,1121 events: SHORT,
240 revents: SHORT,1122 revents: SHORT,
241};1123};
2421124
243// Event flag definitions for WSAPoll().1125pub const TRANSMIT_FILE_BUFFERS = extern struct {
1126 Head: *c_void,
1127 HeadLength: u32,
1128 Tail: *c_void,
1129 TailLength: u32,
1130};
1131
1132pub const LPFN_TRANSMITFILE = fn (
1133 hSocket: SOCKET,
1134 hFile: HANDLE,
1135 nNumberOfBytesToWrite: u32,
1136 nNumberOfBytesPerSend: u32,
1137 lpOverlapped: ?*OVERLAPPED,
1138 lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS,
1139 dwReserved: u32,
1140) callconv(WINAPI) BOOL;
1141
1142pub const LPFN_ACCEPTEX = fn (
1143 sListenSocket: SOCKET,
1144 sAcceptSocket: SOCKET,
1145 lpOutputBuffer: *c_void,
1146 dwReceiveDataLength: u32,
1147 dwLocalAddressLength: u32,
1148 dwRemoteAddressLength: u32,
1149 lpdwBytesReceived: *u32,
1150 lpOverlapped: *OVERLAPPED,
1151) callconv(WINAPI) BOOL;
1152
1153pub const LPFN_GETACCEPTEXSOCKADDRS = fn (
1154 lpOutputBuffer: *c_void,
1155 dwReceiveDataLength: u32,
1156 dwLocalAddressLength: u32,
1157 dwRemoteAddressLength: u32,
1158 LocalSockaddr: **sockaddr,
1159 LocalSockaddrLength: *i32,
1160 RemoteSockaddr: **sockaddr,
1161 RemoteSockaddrLength: *i32,
1162) callconv(WINAPI) void;
1163
1164pub const LPFN_WSASENDMSG = fn (
1165 s: SOCKET,
1166 lpMsg: *const WSAMSG_const,
1167 dwFlags: u32,
1168 lpNumberOfBytesSent: ?*u32,
1169 lpOverlapped: ?*OVERLAPPED,
1170 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
1171) callconv(WINAPI) i32;
2441172
245pub const POLLRDNORM = 0x0100;1173pub const LPFN_WSARECVMSG = fn (
246pub const POLLRDBAND = 0x0200;1174 s: SOCKET,
247pub const POLLIN = (POLLRDNORM | POLLRDBAND);1175 lpMsg: *WSAMSG,
248pub const POLLPRI = 0x0400;1176 lpdwNumberOfBytesRecv: ?*u32,
1177 lpOverlapped: ?*OVERLAPPED,
1178 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
1179) callconv(WINAPI) i32;
2491180
250pub const POLLWRNORM = 0x0010;1181pub const LPSERVICE_CALLBACK_PROC = fn (
251pub const POLLOUT = (POLLWRNORM);1182 lParam: LPARAM,
252pub const POLLWRBAND = 0x0020;1183 hAsyncTaskHandle: HANDLE,
1184) callconv(WINAPI) void;
2531185
254pub const POLLERR = 0x0001;1186pub const SERVICE_ASYNC_INFO = extern struct {
255pub const POLLHUP = 0x0002;1187 lpServiceCallbackProc: LPSERVICE_CALLBACK_PROC,
256pub const POLLNVAL = 0x0004;1188 lParam: LPARAM,
1189 hAsyncTaskHandle: HANDLE,
1190};
1191
1192pub const LPLOOKUPSERVICE_COMPLETION_ROUTINE = fn (
1193 dwError: u32,
1194 dwBytes: u32,
1195 lpOverlapped: *OVERLAPPED,
1196) callconv(WINAPI) void;
1197
1198pub const fd_set = extern struct {
1199 fd_count: u32,
1200 fd_array: [64]SOCKET,
1201};
1202
1203pub const hostent = extern struct {
1204 h_name: [*]u8,
1205 h_aliases: **i8,
1206 h_addrtype: i16,
1207 h_length: i16,
1208 h_addr_list: **i8,
1209};
2571210
258// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-21211// https://docs.microsoft.com/en-au/windows/win32/winsock/windows-sockets-error-codes-2
259pub const WinsockError = enum(u16) {1212pub const WinsockError = enum(u16) {
...@@ -704,180 +1657,649 @@ pub const WinsockError = enum(u16) {...@@ -704,180 +1657,649 @@ pub const WinsockError = enum(u16) {
704 _,1657 _,
705};1658};
7061659
707/// no parameters1660pub extern "ws2_32" fn accept(
708const IOC_VOID = 0x80000000;1661 s: SOCKET,
1662 addr: ?*sockaddr,
1663 addrlen: ?*i32,
1664) callconv(WINAPI) SOCKET;
7091665
710/// copy out parameters1666pub extern "ws2_32" fn bind(
711const IOC_OUT = 0x40000000;1667 s: SOCKET,
1668 name: *const sockaddr,
1669 namelen: i32,
1670) callconv(WINAPI) i32;
7121671
713/// copy in parameters1672pub extern "ws2_32" fn closesocket(
714const IOC_IN = 0x80000000;1673 s: SOCKET,
1674) callconv(WINAPI) i32;
7151675
716/// The IOCTL is a generic Windows Sockets 2 IOCTL code. New IOCTL codes defined for Windows Sockets 2 will have T == 1.1676pub extern "ws2_32" fn connect(
717const IOC_WS2 = 0x08000000;1677 s: SOCKET,
1678 name: *const sockaddr,
1679 namelen: i32,
1680) callconv(WINAPI) i32;
7181681
719pub const SIO_BASE_HANDLE = IOC_OUT | IOC_WS2 | 34;1682pub extern "ws2_32" fn ioctlsocket(
1683 s: SOCKET,
1684 cmd: i32,
1685 argp: *u32,
1686) callconv(WINAPI) i32;
1687
1688pub extern "ws2_32" fn getpeername(
1689 s: SOCKET,
1690 name: *sockaddr,
1691 namelen: *i32,
1692) callconv(WINAPI) i32;
7201693
721pub const SOL_SOCKET = 0xffff;1694pub extern "ws2_32" fn getsockname(
7221695 s: SOCKET,
723pub const SO_DEBUG = 0x0001;1696 name: *sockaddr,
724pub const SO_ACCEPTCONN = 0x0002;1697 namelen: *i32,
725pub const SO_REUSEADDR = 0x0004;1698) callconv(WINAPI) i32;
726pub const SO_KEEPALIVE = 0x0008;1699
727pub const SO_DONTROUTE = 0x0010;1700pub extern "ws2_32" fn getsockopt(
728pub const SO_BROADCAST = 0x0020;1701 s: SOCKET,
729pub const SO_USELOOPBACK = 0x0040;1702 level: i32,
730pub const SO_LINGER = 0x0080;1703 optname: i32,
731pub const SO_OOBINLINE = 0x0100;1704 optval: [*]u8,
7321705 optlen: *i32,
733pub const SO_DONTLINGER = ~@as(u32, SO_LINGER);1706) callconv(WINAPI) i32;
734pub const SO_EXCLUSIVEADDRUSE = ~@as(u32, SO_REUSEADDR);1707
7351708pub extern "ws2_32" fn htonl(
736pub const SO_SNDBUF = 0x1001;1709 hostlong: u32,
737pub const SO_RCVBUF = 0x1002;1710) callconv(WINAPI) u32;
738pub const SO_SNDLOWAT = 0x1003;1711
739pub const SO_RCVLOWAT = 0x1004;1712pub extern "ws2_32" fn htons(
740pub const SO_SNDTIMEO = 0x1005;1713 hostshort: u16,
741pub const SO_RCVTIMEO = 0x1006;1714) callconv(WINAPI) u16;
742pub const SO_ERROR = 0x1007;1715
743pub const SO_TYPE = 0x1008;1716pub extern "ws2_32" fn inet_addr(
7441717 cp: ?[*]const u8,
745pub const SO_GROUP_ID = 0x2001;1718) callconv(WINAPI) u32;
746pub const SO_GROUP_PRIORITY = 0x2002;1719
747pub const SO_MAX_MSG_SIZE = 0x2003;1720pub extern "ws2_32" fn listen(
748pub const SO_PROTOCOL_INFOA = 0x2004;1721 s: SOCKET,
749pub const SO_PROTOCOL_INFOW = 0x2005;1722 backlog: i32,
7501723) callconv(WINAPI) i32;
751pub const PVD_CONFIG = 0x3001;1724
752pub const SO_CONDITIONAL_ACCEPT = 0x3002;1725pub extern "ws2_32" fn ntohl(
7531726 netlong: u32,
754pub const TCP_NODELAY = 0x0001;1727) callconv(WINAPI) u32;
1728
1729pub extern "ws2_32" fn ntohs(
1730 netshort: u16,
1731) callconv(WINAPI) u16;
1732
1733pub extern "ws2_32" fn recv(
1734 s: SOCKET,
1735 buf: [*]u8,
1736 len: i32,
1737 flags: i32,
1738) callconv(WINAPI) i32;
1739
1740pub extern "ws2_32" fn recvfrom(
1741 s: SOCKET,
1742 buf: [*]u8,
1743 len: i32,
1744 flags: i32,
1745 from: ?*sockaddr,
1746 fromlen: ?*i32,
1747) callconv(WINAPI) i32;
1748
1749pub extern "ws2_32" fn select(
1750 nfds: i32,
1751 readfds: ?*fd_set,
1752 writefds: ?*fd_set,
1753 exceptfds: ?*fd_set,
1754 timeout: ?*const timeval,
1755) callconv(WINAPI) i32;
1756
1757pub extern "ws2_32" fn send(
1758 s: SOCKET,
1759 buf: [*]const u8,
1760 len: i32,
1761 flags: u32,
1762) callconv(WINAPI) i32;
1763
1764pub extern "ws2_32" fn sendto(
1765 s: SOCKET,
1766 buf: [*]const u8,
1767 len: i32,
1768 flags: i32,
1769 to: *const sockaddr,
1770 tolen: i32,
1771) callconv(WINAPI) i32;
1772
1773pub extern "ws2_32" fn setsockopt(
1774 s: SOCKET,
1775 level: i32,
1776 optname: i32,
1777 optval: ?[*]const u8,
1778 optlen: i32,
1779) callconv(WINAPI) i32;
1780
1781pub extern "ws2_32" fn shutdown(
1782 s: SOCKET,
1783 how: i32,
1784) callconv(WINAPI) i32;
1785
1786pub extern "ws2_32" fn socket(
1787 af: i32,
1788 @"type": i32,
1789 protocol: i32,
1790) callconv(WINAPI) SOCKET;
7551791
756pub extern "ws2_32" fn WSAStartup(1792pub extern "ws2_32" fn WSAStartup(
757 wVersionRequired: WORD,1793 wVersionRequired: WORD,
758 lpWSAData: *WSADATA,1794 lpWSAData: *WSADATA,
759) callconv(WINAPI) c_int;1795) callconv(WINAPI) i32;
760pub extern "ws2_32" fn WSACleanup() callconv(WINAPI) c_int;1796
1797pub extern "ws2_32" fn WSACleanup() callconv(WINAPI) i32;
1798
1799pub extern "ws2_32" fn WSASetLastError(iError: i32) callconv(WINAPI) void;
1800
761pub extern "ws2_32" fn WSAGetLastError() callconv(WINAPI) WinsockError;1801pub extern "ws2_32" fn WSAGetLastError() callconv(WINAPI) WinsockError;
762pub extern "ws2_32" fn WSASocketA(1802
763 af: c_int,1803pub extern "ws2_32" fn WSAIsBlocking() callconv(WINAPI) BOOL;
764 type: c_int,1804
765 protocol: c_int,1805pub extern "ws2_32" fn WSAUnhookBlockingHook() callconv(WINAPI) i32;
766 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,1806
767 g: GROUP,1807pub extern "ws2_32" fn WSASetBlockingHook(lpBlockFunc: FARPROC) callconv(WINAPI) FARPROC;
768 dwFlags: DWORD,1808
769) callconv(WINAPI) SOCKET;1809pub extern "ws2_32" fn WSACancelBlockingCall() callconv(WINAPI) i32;
770pub extern "ws2_32" fn WSASocketW(1810
771 af: c_int,1811pub extern "ws2_32" fn WSAAsyncGetServByName(
772 type: c_int,1812 hWnd: HWND,
773 protocol: c_int,1813 wMsg: u32,
774 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,1814 name: [*:0]const u8,
775 g: GROUP,1815 proto: ?[*:0]const u8,
776 dwFlags: DWORD,1816 buf: [*]u8,
777) callconv(WINAPI) SOCKET;1817 buflen: i32,
778pub extern "ws2_32" fn closesocket(s: SOCKET) callconv(WINAPI) c_int;1818) callconv(WINAPI) HANDLE;
779pub extern "ws2_32" fn WSAIoctl(1819
1820pub extern "ws2_32" fn WSAAsyncGetServByPort(
1821 hWnd: HWND,
1822 wMsg: u32,
1823 port: i32,
1824 proto: ?[*:0]const u8,
1825 buf: [*]u8,
1826 buflen: i32,
1827) callconv(WINAPI) HANDLE;
1828
1829pub extern "ws2_32" fn WSAAsyncGetProtoByName(
1830 hWnd: HWND,
1831 wMsg: u32,
1832 name: [*:0]const u8,
1833 buf: [*]u8,
1834 buflen: i32,
1835) callconv(WINAPI) HANDLE;
1836
1837pub extern "ws2_32" fn WSAAsyncGetProtoByNumber(
1838 hWnd: HWND,
1839 wMsg: u32,
1840 number: i32,
1841 buf: [*]u8,
1842 buflen: i32,
1843) callconv(WINAPI) HANDLE;
1844
1845pub extern "ws2_32" fn WSACancelAsyncRequest(hAsyncTaskHandle: HANDLE) callconv(WINAPI) i32;
1846
1847pub extern "ws2_32" fn WSAAsyncSelect(
780 s: SOCKET,1848 s: SOCKET,
781 dwIoControlCode: DWORD,1849 hWnd: HWND,
782 lpvInBuffer: ?*const c_void,1850 wMsg: u32,
783 cbInBuffer: DWORD,1851 lEvent: i32,
784 lpvOutBuffer: ?LPVOID,1852) callconv(WINAPI) i32;
785 cbOutBuffer: DWORD,1853
786 lpcbBytesReturned: LPDWORD,1854pub extern "ws2_32" fn WSAAccept(
787 lpOverlapped: ?*WSAOVERLAPPED,
788 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,
789) callconv(WINAPI) c_int;
790pub extern "ws2_32" fn accept(
791 s: SOCKET,1855 s: SOCKET,
792 addr: ?*sockaddr,1856 addr: ?*sockaddr,
793 addrlen: ?*c_int,1857 addrlen: ?*i32,
1858 lpfnCondition: ?LPCONDITIONPROC,
1859 dwCallbackData: usize,
794) callconv(WINAPI) SOCKET;1860) callconv(WINAPI) SOCKET;
795pub extern "ws2_32" fn bind(1861
1862pub extern "ws2_32" fn WSACloseEvent(hEvent: HANDLE) callconv(WINAPI) BOOL;
1863
1864pub extern "ws2_32" fn WSAConnect(
796 s: SOCKET,1865 s: SOCKET,
797 addr: ?*const sockaddr,1866 name: *const sockaddr,
798 addrlen: c_int,1867 namelen: i32,
799) callconv(WINAPI) c_int;1868 lpCallerData: ?*WSABUF,
800pub extern "ws2_32" fn connect(1869 lpCalleeData: ?*WSABUF,
1870 lpSQOS: ?*QOS,
1871 lpGQOS: ?*QOS,
1872) callconv(WINAPI) i32;
1873
1874pub extern "ws2_32" fn WSAConnectByNameW(
1875 s: SOCKET,
1876 nodename: [*:0]const u16,
1877 servicename: [*:0]const u16,
1878 LocalAddressLength: ?*u32,
1879 LocalAddress: ?*sockaddr,
1880 RemoteAddressLength: ?*u32,
1881 RemoteAddress: ?*sockaddr,
1882 timeout: ?*const timeval,
1883 Reserved: *OVERLAPPED,
1884) callconv(WINAPI) BOOL;
1885
1886pub extern "ws2_32" fn WSAConnectByNameA(
1887 s: SOCKET,
1888 nodename: [*:0]const u8,
1889 servicename: [*:0]const u8,
1890 LocalAddressLength: ?*u32,
1891 LocalAddress: ?*sockaddr,
1892 RemoteAddressLength: ?*u32,
1893 RemoteAddress: ?*sockaddr,
1894 timeout: ?*const timeval,
1895 Reserved: *OVERLAPPED,
1896) callconv(WINAPI) BOOL;
1897
1898pub extern "ws2_32" fn WSAConnectByList(
1899 s: SOCKET,
1900 SocketAddress: *SOCKET_ADDRESS_LIST,
1901 LocalAddressLength: ?*u32,
1902 LocalAddress: ?*sockaddr,
1903 RemoteAddressLength: ?*u32,
1904 RemoteAddress: ?*sockaddr,
1905 timeout: ?*const timeval,
1906 Reserved: *OVERLAPPED,
1907) callconv(WINAPI) BOOL;
1908
1909pub extern "ws2_32" fn WSACreateEvent() callconv(WINAPI) HANDLE;
1910
1911pub extern "ws2_32" fn WSADuplicateSocketA(
1912 s: SOCKET,
1913 dwProcessId: u32,
1914 lpProtocolInfo: *WSAPROTOCOL_INFOA,
1915) callconv(WINAPI) i32;
1916
1917pub extern "ws2_32" fn WSADuplicateSocketW(
1918 s: SOCKET,
1919 dwProcessId: u32,
1920 lpProtocolInfo: *WSAPROTOCOL_INFOW,
1921) callconv(WINAPI) i32;
1922
1923pub extern "ws2_32" fn WSAEnumNetworkEvents(
1924 s: SOCKET,
1925 hEventObject: HANDLE,
1926 lpNetworkEvents: *WSANETWORKEVENTS,
1927) callconv(WINAPI) i32;
1928
1929pub extern "ws2_32" fn WSAEnumProtocolsA(
1930 lpiProtocols: ?*i32,
1931 lpProtocolBuffer: ?*WSAPROTOCOL_INFOA,
1932 lpdwBufferLength: *u32,
1933) callconv(WINAPI) i32;
1934
1935pub extern "ws2_32" fn WSAEnumProtocolsW(
1936 lpiProtocols: ?*i32,
1937 lpProtocolBuffer: ?*WSAPROTOCOL_INFOW,
1938 lpdwBufferLength: *u32,
1939) callconv(WINAPI) i32;
1940
1941pub extern "ws2_32" fn WSAEventSelect(
1942 s: SOCKET,
1943 hEventObject: HANDLE,
1944 lNetworkEvents: i32,
1945) callconv(WINAPI) i32;
1946
1947pub extern "ws2_32" fn WSAGetOverlappedResult(
1948 s: SOCKET,
1949 lpOverlapped: *OVERLAPPED,
1950 lpcbTransfer: *u32,
1951 fWait: BOOL,
1952 lpdwFlags: *u32,
1953) callconv(WINAPI) BOOL;
1954
1955pub extern "ws2_32" fn WSAGetQOSByName(
1956 s: SOCKET,
1957 lpQOSName: *WSABUF,
1958 lpQOS: *QOS,
1959) callconv(WINAPI) BOOL;
1960
1961pub extern "ws2_32" fn WSAHtonl(
1962 s: SOCKET,
1963 hostlong: u32,
1964 lpnetlong: *u32,
1965) callconv(WINAPI) i32;
1966
1967pub extern "ws2_32" fn WSAHtons(
1968 s: SOCKET,
1969 hostshort: u16,
1970 lpnetshort: *u16,
1971) callconv(WINAPI) i32;
1972
1973pub extern "ws2_32" fn WSAIoctl(
1974 s: SOCKET,
1975 dwIoControlCode: u32,
1976 lpvInBuffer: ?*const c_void,
1977 cbInBuffer: u32,
1978 lpvOutbuffer: ?*c_void,
1979 cbOutbuffer: u32,
1980 lpcbBytesReturned: *u32,
1981 lpOverlapped: ?*OVERLAPPED,
1982 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
1983) callconv(WINAPI) i32;
1984
1985pub extern "ws2_32" fn WSAJoinLeaf(
801 s: SOCKET,1986 s: SOCKET,
802 name: *const sockaddr,1987 name: *const sockaddr,
803 namelen: c_int,1988 namelen: i32,
804) callconv(WINAPI) c_int;1989 lpCallerdata: ?*WSABUF,
805pub extern "ws2_32" fn listen(1990 lpCalleeData: ?*WSABUF,
1991 lpSQOS: ?*QOS,
1992 lpGQOS: ?*QOS,
1993 dwFlags: u32,
1994) callconv(WINAPI) SOCKET;
1995
1996pub extern "ws2_32" fn WSANtohl(
1997 s: SOCKET,
1998 netlong: u32,
1999 lphostlong: *u32,
2000) callconv(WINAPI) u32;
2001
2002pub extern "ws2_32" fn WSANtohs(
806 s: SOCKET,2003 s: SOCKET,
807 backlog: c_int,2004 netshort: u16,
808) callconv(WINAPI) c_int;2005 lphostshort: *u16,
2006) callconv(WINAPI) i32;
2007
809pub extern "ws2_32" fn WSARecv(2008pub extern "ws2_32" fn WSARecv(
810 s: SOCKET,2009 s: SOCKET,
811 lpBuffers: [*]const WSABUF,2010 lpBuffers: [*]WSABUF,
812 dwBufferCount: DWORD,2011 dwBufferCouynt: u32,
813 lpNumberOfBytesRecvd: ?*DWORD,2012 lpNumberOfBytesRecv: ?*u32,
814 lpFlags: *DWORD,2013 lpFlags: *u32,
815 lpOverlapped: ?*WSAOVERLAPPED,2014 lpOverlapped: ?*OVERLAPPED,
816 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,2015 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
817) callconv(WINAPI) c_int;2016) callconv(WINAPI) i32;
2017
2018pub extern "ws2_32" fn WSARecvDisconnect(
2019 s: SOCKET,
2020 lpInboundDisconnectData: ?*WSABUF,
2021) callconv(WINAPI) i32;
2022
818pub extern "ws2_32" fn WSARecvFrom(2023pub extern "ws2_32" fn WSARecvFrom(
819 s: SOCKET,2024 s: SOCKET,
820 lpBuffers: [*]const WSABUF,2025 lpBuffers: [*]WSABUF,
821 dwBufferCount: DWORD,2026 dwBuffercount: u32,
822 lpNumberOfBytesRecvd: ?*DWORD,2027 lpNumberOfBytesRecvd: ?*u32,
823 lpFlags: *DWORD,2028 lpFlags: *u32,
824 lpFrom: ?*sockaddr,2029 lpFrom: ?*sockaddr,
825 lpFromlen: ?*socklen_t,2030 lpFromlen: ?*i32,
826 lpOverlapped: ?*WSAOVERLAPPED,2031 lpOverlapped: ?*OVERLAPPED,
827 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,2032 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
828) callconv(WINAPI) c_int;2033) callconv(WINAPI) i32;
2034
2035pub extern "ws2_32" fn WSAResetEvent(hEvent: HANDLE) callconv(WINAPI) i32;
2036
829pub extern "ws2_32" fn WSASend(2037pub extern "ws2_32" fn WSASend(
830 s: SOCKET,2038 s: SOCKET,
831 lpBuffers: [*]WSABUF,2039 lpBuffers: [*]WSABUF,
832 dwBufferCount: DWORD,2040 dwBufferCount: u32,
833 lpNumberOfBytesSent: ?*DWORD,2041 lpNumberOfBytesSent: ?*u32,
834 dwFlags: DWORD,2042 dwFlags: u32,
835 lpOverlapped: ?*WSAOVERLAPPED,2043 lpOverlapped: ?*OVERLAPPED,
836 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,2044 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
837) callconv(WINAPI) c_int;2045) callconv(WINAPI) i32;
2046
2047pub extern "ws2_32" fn WSASendMsg(
2048 s: SOCKET,
2049 lpMsg: *const WSAMSG_const,
2050 dwFlags: u32,
2051 lpNumberOfBytesSent: ?*u32,
2052 lpOverlapped: ?*OVERLAPPED,
2053 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2054) callconv(WINAPI) i32;
2055
2056pub extern "ws2_32" fn WSARecvMsg(
2057 s: SOCKET,
2058 lpMsg: *WSAMSG,
2059 lpdwNumberOfBytesRecv: ?*u32,
2060 lpOverlapped: ?*OVERLAPPED,
2061 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2062) callconv(WINAPI) i32;
2063
2064pub extern "ws2_32" fn WSASendDisconnect(
2065 s: SOCKET,
2066 lpOutboundDisconnectData: ?*WSABUF,
2067) callconv(WINAPI) i32;
2068
838pub extern "ws2_32" fn WSASendTo(2069pub extern "ws2_32" fn WSASendTo(
839 s: SOCKET,2070 s: SOCKET,
840 lpBuffers: [*]WSABUF,2071 lpBuffers: [*]WSABUF,
841 dwBufferCount: DWORD,2072 dwBufferCount: u32,
842 lpNumberOfBytesSent: ?*DWORD,2073 lpNumberOfBytesSent: ?*u32,
843 dwFlags: DWORD,2074 dwFlags: u32,
844 lpTo: ?*const sockaddr,2075 lpTo: ?*const sockaddr,
845 iTolen: c_int,2076 iToLen: i32,
846 lpOverlapped: ?*WSAOVERLAPPED,2077 lpOverlapped: ?*OVERLAPPED,
847 lpCompletionRoutine: ?WSAOVERLAPPED_COMPLETION_ROUTINE,2078 lpCompletionRounte: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
848) callconv(WINAPI) c_int;2079) callconv(WINAPI) i32;
2080
2081pub extern "ws2_32" fn WSASetEvent(
2082 hEvent: HANDLE,
2083) callconv(WINAPI) BOOL;
2084
2085pub extern "ws2_32" fn WSASocketA(
2086 af: i32,
2087 @"type": i32,
2088 protocol: i32,
2089 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
2090 g: u32,
2091 dwFlags: u32,
2092) callconv(WINAPI) SOCKET;
2093
2094pub extern "ws2_32" fn WSASocketW(
2095 af: i32,
2096 @"type": i32,
2097 protocol: i32,
2098 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
2099 g: u32,
2100 dwFlags: u32,
2101) callconv(WINAPI) SOCKET;
2102
2103pub extern "ws2_32" fn WSAWaitForMultipleEvents(
2104 cEvents: u32,
2105 lphEvents: [*]const HANDLE,
2106 fWaitAll: BOOL,
2107 dwTimeout: u32,
2108 fAlertable: BOOL,
2109) callconv(WINAPI) u32;
2110
2111pub extern "ws2_32" fn WSAAddressToStringA(
2112 lpsaAddress: *sockaddr,
2113 dwAddressLength: u32,
2114 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
2115 lpszAddressString: [*]u8,
2116 lpdwAddressStringLength: *u32,
2117) callconv(WINAPI) i32;
2118
2119pub extern "ws2_32" fn WSAAddressToStringW(
2120 lpsaAddress: *sockaddr,
2121 dwAddressLength: u32,
2122 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
2123 lpszAddressString: [*]u16,
2124 lpdwAddressStringLength: *u32,
2125) callconv(WINAPI) i32;
2126
2127pub extern "ws2_32" fn WSAStringToAddressA(
2128 AddressString: [*:0]const u8,
2129 AddressFamily: i32,
2130 lpProtocolInfo: ?*WSAPROTOCOL_INFOA,
2131 lpAddress: *sockaddr,
2132 lpAddressLength: *i32,
2133) callconv(WINAPI) i32;
2134
2135pub extern "ws2_32" fn WSAStringToAddressW(
2136 AddressString: [*:0]const u16,
2137 AddressFamily: i32,
2138 lpProtocolInfo: ?*WSAPROTOCOL_INFOW,
2139 lpAddrses: *sockaddr,
2140 lpAddressLength: *i32,
2141) callconv(WINAPI) i32;
2142
2143pub extern "ws2_32" fn WSAProviderConfigChange(
2144 lpNotificationHandle: *HANDLE,
2145 lpOverlapped: ?*OVERLAPPED,
2146 lpCompletionRoutine: ?LPWSAOVERLAPPED_COMPLETION_ROUTINE,
2147) callconv(WINAPI) i32;
2148
849pub extern "ws2_32" fn WSAPoll(2149pub extern "ws2_32" fn WSAPoll(
850 fdArray: [*]pollfd,2150 fdArray: [*]WSAPOLLFD,
851 fds: c_ulong,2151 fds: u32,
852 timeout: c_int,2152 timeout: i32,
853) callconv(WINAPI) c_int;2153) callconv(WINAPI) i32;
2154
2155pub extern "mswsock" fn WSARecvEx(
2156 s: SOCKET,
2157 buf: [*]u8,
2158 len: i32,
2159 flags: *i32,
2160) callconv(WINAPI) i32;
2161
2162pub extern "mswsock" fn TransmitFile(
2163 hSocket: SOCKET,
2164 hFile: HANDLE,
2165 nNumberOfBytesToWrite: u32,
2166 nNumberOfBytesPerSend: u32,
2167 lpOverlapped: ?*OVERLAPPED,
2168 lpTransmitBuffers: ?*TRANSMIT_FILE_BUFFERS,
2169 dwReserved: u32,
2170) callconv(WINAPI) BOOL;
2171
2172pub extern "mswsock" fn AcceptEx(
2173 sListenSocket: SOCKET,
2174 sAcceptSocket: SOCKET,
2175 lpOutputBuffer: *c_void,
2176 dwReceiveDataLength: u32,
2177 dwLocalAddressLength: u32,
2178 dwRemoteAddressLength: u32,
2179 lpdwBytesReceived: *u32,
2180 lpOverlapped: *OVERLAPPED,
2181) callconv(WINAPI) BOOL;
2182
2183pub extern "mswsock" fn GetAcceptExSockaddrs(
2184 lpOutputBuffer: *c_void,
2185 dwReceiveDataLength: u32,
2186 dwLocalAddressLength: u32,
2187 dwRemoteAddressLength: u32,
2188 LocalSockaddr: **sockaddr,
2189 LocalSockaddrLength: *i32,
2190 RemoteSockaddr: **sockaddr,
2191 RemoteSockaddrLength: *i32,
2192) callconv(WINAPI) void;
2193
2194pub extern "ws2_32" fn WSAProviderCompleteAsyncCall(
2195 hAsyncCall: HANDLE,
2196 iRetCode: i32,
2197) callconv(WINAPI) i32;
2198
2199pub extern "mswsock" fn EnumProtocolsA(
2200 lpiProtocols: ?*i32,
2201 lpProtocolBuffer: *c_void,
2202 lpdwBufferLength: *u32,
2203) callconv(WINAPI) i32;
2204
2205pub extern "mswsock" fn EnumProtocolsW(
2206 lpiProtocols: ?*i32,
2207 lpProtocolBuffer: *c_void,
2208 lpdwBufferLength: *u32,
2209) callconv(WINAPI) i32;
2210
2211pub extern "mswsock" fn GetAddressByNameA(
2212 dwNameSpace: u32,
2213 lpServiceType: *GUID,
2214 lpServiceName: ?[*:0]u8,
2215 lpiProtocols: ?*i32,
2216 dwResolution: u32,
2217 lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO,
2218 lpCsaddrBuffer: *c_void,
2219 lpAliasBuffer: ?[*:0]const u8,
2220 lpdwAliasBufferLength: *u32,
2221) callconv(WINAPI) i32;
2222
2223pub extern "mswsock" fn GetAddressByNameW(
2224 dwNameSpace: u32,
2225 lpServiceType: *GUID,
2226 lpServiceName: ?[*:0]u16,
2227 lpiProtocols: ?*i32,
2228 dwResolution: u32,
2229 lpServiceAsyncInfo: ?*SERVICE_ASYNC_INFO,
2230 lpCsaddrBuffer: *c_void,
2231 ldwBufferLEngth: *u32,
2232 lpAliasBuffer: ?[*:0]u16,
2233 lpdwAliasBufferLength: *u32,
2234) callconv(WINAPI) i32;
2235
2236pub extern "mswsock" fn GetTypeByNameA(
2237 lpServiceName: [*:0]u8,
2238 lpServiceType: *GUID,
2239) callconv(WINAPI) i32;
2240
2241pub extern "mswsock" fn GetTypeByNameW(
2242 lpServiceName: [*:0]u16,
2243 lpServiceType: *GUID,
2244) callconv(WINAPI) i32;
2245
2246pub extern "mswsock" fn GetNameByTypeA(
2247 lpServiceType: *GUID,
2248 lpServiceName: [*:0]u8,
2249 dwNameLength: u32,
2250) callconv(WINAPI) i32;
2251
2252pub extern "mswsock" fn GetNameByTypeW(
2253 lpServiceType: *GUID,
2254 lpServiceName: [*:0]u16,
2255 dwNameLength: u32,
2256) callconv(WINAPI) i32;
2257
854pub extern "ws2_32" fn getaddrinfo(2258pub extern "ws2_32" fn getaddrinfo(
855 pNodeName: [*:0]const u8,2259 pNodeName: ?[*:0]const u8,
856 pServiceName: [*:0]const u8,2260 pServiceName: ?[*:0]const u8,
857 pHints: *const addrinfo,2261 pHints: ?*const addrinfoa,
858 ppResult: **addrinfo,2262 ppResult: **addrinfoa,
2263) callconv(WINAPI) i32;
2264
2265pub extern "ws2_32" fn GetAddrInfoExA(
2266 pName: ?[*:0]const u8,
2267 pServiceName: ?[*:0]const u8,
2268 dwNameSapce: u32,
2269 lpNspId: ?*GUID,
2270 hints: ?*const addrinfoexA,
2271 ppResult: **addrinfoexA,
2272 timeout: ?*timeval,
2273 lpOverlapped: ?*OVERLAPPED,
2274 lpCompletionRoutine: ?LPLOOKUPSERVICE_COMPLETION_ROUTINE,
859) callconv(WINAPI) i32;2275) callconv(WINAPI) i32;
2276
2277pub extern "ws2_32" fn GetAddrInfoExCancel(
2278 lpHandle: *HANDLE,
2279) callconv(WINAPI) i32;
2280
2281pub extern "ws2_32" fn GetAddrInfoExOverlappedResult(
2282 lpOverlapped: *OVERLAPPED,
2283) callconv(WINAPI) i32;
2284
860pub extern "ws2_32" fn freeaddrinfo(2285pub extern "ws2_32" fn freeaddrinfo(
861 pAddrInfo: *addrinfo,2286 pAddrInfo: ?*addrinfoa,
862) callconv(WINAPI) void;2287) callconv(WINAPI) void;
863pub extern "ws2_32" fn ioctlsocket(2288
864 s: SOCKET,2289pub extern "ws2_32" fn FreeAddrInfoEx(
865 cmd: c_long,2290 pAddrInfoEx: ?*addrinfoexA,
866 argp: *c_ulong,2291) callconv(WINAPI) void;
867) callconv(WINAPI) c_int;2292
868pub extern "ws2_32" fn getsockname(2293pub extern "ws2_32" fn getnameinfo(
869 s: SOCKET,2294 pSockaddr: *const sockaddr,
870 name: *sockaddr,2295 SockaddrLength: i32,
871 namelen: *c_int,2296 pNodeBuffer: ?[*]u8,
872) callconv(WINAPI) c_int;2297 NodeBufferSize: u32,
873pub extern "ws2_32" fn setsockopt(2298 pServiceBuffer: ?[*]u8,
874 s: SOCKET,2299 ServiceBufferName: u32,
875 level: u32,2300 Flags: i32,
876 optname: u32,2301) callconv(WINAPI) i32;
877 optval: ?*const c_void,2302
878 optlen: socklen_t,2303pub extern "IPHLPAPI" fn if_nametoindex(
879) callconv(WINAPI) c_int;2304 InterfaceName: [*:0]const u8,
880pub extern "ws2_32" fn shutdown(2305) callconv(WINAPI) u32;
881 s: SOCKET,
882 how: c_int,
883) callconv(WINAPI) c_int;
lib/std/priority_dequeue.zig+1-16
...@@ -387,17 +387,6 @@ pub fn PriorityDequeue(comptime T: type) type {...@@ -387,17 +387,6 @@ pub fn PriorityDequeue(comptime T: type) type {
387 return;387 return;
388 },388 },
389 };389 };
390 self.len = new_len;
391 }
392
393 /// Reduce length to `new_len`.
394 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
395 assert(new_len <= self.items.len);
396
397 // Cannot shrink to smaller than the current queue size without invalidating the heap property
398 assert(new_len >= self.len);
399
400 self.len = new_len;
401 }390 }
402391
403 pub fn update(self: *Self, elem: T, new_elem: T) !void {392 pub fn update(self: *Self, elem: T, new_elem: T) !void {
...@@ -836,7 +825,7 @@ test "std.PriorityDequeue: iterator while empty" {...@@ -836,7 +825,7 @@ test "std.PriorityDequeue: iterator while empty" {
836 try expectEqual(it.next(), null);825 try expectEqual(it.next(), null);
837}826}
838827
839test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" {828test "std.PriorityDequeue: shrinkAndFree" {
840 var queue = PDQ.init(testing.allocator, lessThanComparison);829 var queue = PDQ.init(testing.allocator, lessThanComparison);
841 defer queue.deinit();830 defer queue.deinit();
842831
...@@ -849,10 +838,6 @@ test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" {...@@ -849,10 +838,6 @@ test "std.PriorityDequeue: shrinkRetainingCapacity and shrinkAndFree" {
849 try expect(queue.capacity() >= 4);838 try expect(queue.capacity() >= 4);
850 try expectEqual(@as(usize, 3), queue.len);839 try expectEqual(@as(usize, 3), queue.len);
851840
852 queue.shrinkRetainingCapacity(3);
853 try expect(queue.capacity() >= 4);
854 try expectEqual(@as(usize, 3), queue.len);
855
856 queue.shrinkAndFree(3);841 queue.shrinkAndFree(3);
857 try expectEqual(@as(usize, 3), queue.capacity());842 try expectEqual(@as(usize, 3), queue.capacity());
858 try expectEqual(@as(usize, 3), queue.len);843 try expectEqual(@as(usize, 3), queue.len);
lib/std/priority_queue.zig+1-16
...@@ -203,17 +203,6 @@ pub fn PriorityQueue(comptime T: type) type {...@@ -203,17 +203,6 @@ pub fn PriorityQueue(comptime T: type) type {
203 return;203 return;
204 },204 },
205 };205 };
206 self.len = new_len;
207 }
208
209 /// Reduce length to `new_len`.
210 pub fn shrinkRetainingCapacity(self: *Self, new_len: usize) void {
211 assert(new_len <= self.items.len);
212
213 // Cannot shrink to smaller than the current queue size without invalidating the heap property
214 assert(new_len >= self.len);
215
216 self.len = new_len;
217 }206 }
218207
219 pub fn update(self: *Self, elem: T, new_elem: T) !void {208 pub fn update(self: *Self, elem: T, new_elem: T) !void {
...@@ -495,7 +484,7 @@ test "std.PriorityQueue: iterator while empty" {...@@ -495,7 +484,7 @@ test "std.PriorityQueue: iterator while empty" {
495 try expectEqual(it.next(), null);484 try expectEqual(it.next(), null);
496}485}
497486
498test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" {487test "std.PriorityQueue: shrinkAndFree" {
499 var queue = PQ.init(testing.allocator, lessThan);488 var queue = PQ.init(testing.allocator, lessThan);
500 defer queue.deinit();489 defer queue.deinit();
501490
...@@ -508,10 +497,6 @@ test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" {...@@ -508,10 +497,6 @@ test "std.PriorityQueue: shrinkRetainingCapacity and shrinkAndFree" {
508 try expect(queue.capacity() >= 4);497 try expect(queue.capacity() >= 4);
509 try expectEqual(@as(usize, 3), queue.len);498 try expectEqual(@as(usize, 3), queue.len);
510499
511 queue.shrinkRetainingCapacity(3);
512 try expect(queue.capacity() >= 4);
513 try expectEqual(@as(usize, 3), queue.len);
514
515 queue.shrinkAndFree(3);500 queue.shrinkAndFree(3);
516 try expectEqual(@as(usize, 3), queue.capacity());501 try expectEqual(@as(usize, 3), queue.capacity());
517 try expectEqual(@as(usize, 3), queue.len);502 try expectEqual(@as(usize, 3), queue.len);
lib/std/special/c.zig+2-2
...@@ -228,7 +228,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8...@@ -228,7 +228,7 @@ export fn memmove(dest: ?[*]u8, src: ?[*]const u8, n: usize) callconv(.C) ?[*]u8
228 return dest;228 return dest;
229}229}
230230
231export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) isize {231export fn memcmp(vl: ?[*]const u8, vr: ?[*]const u8, n: usize) callconv(.C) c_int {
232 @setRuntimeSafety(false);232 @setRuntimeSafety(false);
233233
234 var index: usize = 0;234 var index: usize = 0;
...@@ -253,7 +253,7 @@ test "memcmp" {...@@ -253,7 +253,7 @@ test "memcmp" {
253 try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);253 try std.testing.expect(memcmp(base_arr[0..], arr3[0..], base_arr.len) < 0);
254}254}
255255
256export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) isize {256export fn bcmp(vl: [*]allowzero const u8, vr: [*]allowzero const u8, n: usize) callconv(.C) c_int {
257 @setRuntimeSafety(false);257 @setRuntimeSafety(false);
258258
259 var index: usize = 0;259 var index: usize = 0;
lib/std/special/test_runner.zig+7-1
...@@ -14,12 +14,15 @@ var log_err_count: usize = 0;...@@ -14,12 +14,15 @@ var log_err_count: usize = 0;
14var args_buffer: [std.fs.MAX_PATH_BYTES + std.mem.page_size]u8 = undefined;14var args_buffer: [std.fs.MAX_PATH_BYTES + std.mem.page_size]u8 = undefined;
15var args_allocator = std.heap.FixedBufferAllocator.init(&args_buffer);15var args_allocator = std.heap.FixedBufferAllocator.init(&args_buffer);
1616
17pub fn main() anyerror!void {17fn processArgs() void {
18 const args = std.process.argsAlloc(&args_allocator.allocator) catch {18 const args = std.process.argsAlloc(&args_allocator.allocator) catch {
19 @panic("Too many bytes passed over the CLI to the test runner");19 @panic("Too many bytes passed over the CLI to the test runner");
20 };20 };
21 std.testing.zig_exe_path = args[1];21 std.testing.zig_exe_path = args[1];
22}
2223
24pub fn main() anyerror!void {
25 processArgs();
23 const test_fn_list = builtin.test_functions;26 const test_fn_list = builtin.test_functions;
24 var ok_count: usize = 0;27 var ok_count: usize = 0;
25 var skip_count: usize = 0;28 var skip_count: usize = 0;
...@@ -84,6 +87,9 @@ pub fn main() anyerror!void {...@@ -84,6 +87,9 @@ pub fn main() anyerror!void {
84 test_node.end();87 test_node.end();
85 progress.log("{s}... FAIL ({s})\n", .{ test_fn.name, @errorName(err) });88 progress.log("{s}... FAIL ({s})\n", .{ test_fn.name, @errorName(err) });
86 if (progress.terminal == null) std.debug.print("FAIL ({s})\n", .{@errorName(err)});89 if (progress.terminal == null) std.debug.print("FAIL ({s})\n", .{@errorName(err)});
90 if (@errorReturnTrace()) |trace| {
91 std.debug.dumpStackTrace(trace.*);
92 }
87 },93 },
88 }94 }
89 }95 }
lib/std/target.zig+4-4
...@@ -267,7 +267,7 @@ pub const Target = struct {...@@ -267,7 +267,7 @@ pub const Target = struct {
267 .macos => return .{267 .macos => return .{
268 .semver = .{268 .semver = .{
269 .min = .{ .major = 10, .minor = 13 },269 .min = .{ .major = 10, .minor = 13 },
270 .max = .{ .major = 11, .minor = 1 },270 .max = .{ .major = 11, .minor = 2 },
271 },271 },
272 },272 },
273 .ios => return .{273 .ios => return .{
...@@ -291,19 +291,19 @@ pub const Target = struct {...@@ -291,19 +291,19 @@ pub const Target = struct {
291 .netbsd => return .{291 .netbsd => return .{
292 .semver = .{292 .semver = .{
293 .min = .{ .major = 8, .minor = 0 },293 .min = .{ .major = 8, .minor = 0 },
294 .max = .{ .major = 9, .minor = 0 },294 .max = .{ .major = 9, .minor = 1 },
295 },295 },
296 },296 },
297 .openbsd => return .{297 .openbsd => return .{
298 .semver = .{298 .semver = .{
299 .min = .{ .major = 6, .minor = 8 },299 .min = .{ .major = 6, .minor = 8 },
300 .max = .{ .major = 6, .minor = 8 },300 .max = .{ .major = 6, .minor = 9 },
301 },301 },
302 },302 },
303 .dragonfly => return .{303 .dragonfly => return .{
304 .semver = .{304 .semver = .{
305 .min = .{ .major = 5, .minor = 8 },305 .min = .{ .major = 5, .minor = 8 },
306 .max = .{ .major = 5, .minor = 8 },306 .max = .{ .major = 6, .minor = 0 },
307 },307 },
308 },308 },
309309
lib/std/x.zig+1-1
...@@ -7,7 +7,7 @@...@@ -7,7 +7,7 @@
7const std = @import("std.zig");7const std = @import("std.zig");
88
9pub const os = struct {9pub const os = struct {
10 pub const Socket = @import("x/os/Socket.zig");10 pub const Socket = @import("x/os/socket.zig").Socket;
11 pub usingnamespace @import("x/os/net.zig");11 pub usingnamespace @import("x/os/net.zig");
12};12};
1313
lib/std/x/net/tcp.zig+82-34
...@@ -6,6 +6,7 @@...@@ -6,6 +6,7 @@
66
7const std = @import("../../std.zig");7const std = @import("../../std.zig");
88
9const io = std.io;
9const os = std.os;10const os = std.os;
10const ip = std.x.net.ip;11const ip = std.x.net.ip;
1112
...@@ -58,6 +59,28 @@ pub const Domain = enum(u16) {...@@ -58,6 +59,28 @@ pub const Domain = enum(u16) {
58pub const Client = struct {59pub const Client = struct {
59 socket: Socket,60 socket: Socket,
6061
62 /// Implements `std.io.Reader`.
63 pub const Reader = struct {
64 client: Client,
65 flags: u32,
66
67 /// Implements `readFn` for `std.io.Reader`.
68 pub fn read(self: Client.Reader, buffer: []u8) !usize {
69 return self.client.read(buffer, self.flags);
70 }
71 };
72
73 /// Implements `std.io.Writer`.
74 pub const Writer = struct {
75 client: Client,
76 flags: u32,
77
78 /// Implements `writeFn` for `std.io.Writer`.
79 pub fn write(self: Client.Writer, buffer: []const u8) !usize {
80 return self.client.write(buffer, self.flags);
81 }
82 };
83
61 /// Opens a new client.84 /// Opens a new client.
62 pub fn init(domain: tcp.Domain, flags: u32) !Client {85 pub fn init(domain: tcp.Domain, flags: u32) !Client {
63 return Client{86 return Client{
...@@ -89,41 +112,46 @@ pub const Client = struct {...@@ -89,41 +112,46 @@ pub const Client = struct {
89 return self.socket.connect(address.into());112 return self.socket.connect(address.into());
90 }113 }
91114
92 /// Read data from the socket into the buffer provided. It returns the115 /// Extracts the error set of a function.
93 /// number of bytes read into the buffer provided.116 /// TODO: remove after Socket.{read, write} error unions are well-defined across different platforms
94 pub fn read(self: Client, buf: []u8) !usize {117 fn ErrorSetOf(comptime Function: anytype) type {
95 return self.socket.read(buf);118 return @typeInfo(@typeInfo(@TypeOf(Function)).Fn.return_type.?).ErrorUnion.error_set;
96 }119 }
97120
98 /// Read data from the socket into the buffer provided with a set of flags121 /// Wrap `tcp.Client` into `std.io.Reader`.
99 /// specified. It returns the number of bytes read into the buffer provided.122 pub fn reader(self: Client, flags: u32) io.Reader(Client.Reader, ErrorSetOf(Client.Reader.read), Client.Reader.read) {
100 pub fn recv(self: Client, buf: []u8, flags: u32) !usize {123 return .{ .context = .{ .client = self, .flags = flags } };
101 return self.socket.recv(buf, flags);
102 }124 }
103125
104 /// Write a buffer of data provided to the socket. It returns the number126 /// Wrap `tcp.Client` into `std.io.Writer`.
105 /// of bytes that are written to the socket.127 pub fn writer(self: Client, flags: u32) io.Writer(Client.Writer, ErrorSetOf(Client.Writer.write), Client.Writer.write) {
106 pub fn write(self: Client, buf: []const u8) !usize {128 return .{ .context = .{ .client = self, .flags = flags } };
107 return self.socket.write(buf);
108 }129 }
109130
110 /// Writes multiple I/O vectors to the socket. It returns the number131 /// Read data from the socket into the buffer provided with a set of flags
111 /// of bytes that are written to the socket.132 /// specified. It returns the number of bytes read into the buffer provided.
112 pub fn writev(self: Client, buffers: []const os.iovec_const) !usize {133 pub fn read(self: Client, buf: []u8, flags: u32) !usize {
113 return self.socket.writev(buffers);134 return self.socket.read(buf, flags);
114 }135 }
115136
116 /// Write a buffer of data provided to the socket with a set of flags specified.137 /// Write a buffer of data provided to the socket with a set of flags specified.
117 /// It returns the number of bytes that are written to the socket.138 /// It returns the number of bytes that are written to the socket.
118 pub fn send(self: Client, buf: []const u8, flags: u32) !usize {139 pub fn write(self: Client, buf: []const u8, flags: u32) !usize {
119 return self.socket.send(buf, flags);140 return self.socket.write(buf, flags);
120 }141 }
121142
122 /// Writes multiple I/O vectors with a prepended message header to the socket143 /// Writes multiple I/O vectors with a prepended message header to the socket
123 /// with a set of flags specified. It returns the number of bytes that are144 /// with a set of flags specified. It returns the number of bytes that are
124 /// written to the socket.145 /// written to the socket.
125 pub fn sendmsg(self: Client, msg: os.msghdr_const, flags: u32) !usize {146 pub fn writeVectorized(self: Client, msg: os.msghdr_const, flags: u32) !usize {
126 return self.socket.sendmsg(msg, flags);147 return self.socket.writeVectorized(msg, flags);
148 }
149
150 /// Read multiple I/O vectors with a prepended message header from the socket
151 /// with a set of flags specified. It returns the number of bytes that were
152 /// read into the buffer provided.
153 pub fn readVectorized(self: Client, msg: *os.msghdr, flags: u32) !usize {
154 return self.socket.readVectorized(msg, flags);
127 }155 }
128156
129 /// Query and return the latest cached error on the client's underlying socket.157 /// Query and return the latest cached error on the client's underlying socket.
...@@ -146,12 +174,41 @@ pub const Client = struct {...@@ -146,12 +174,41 @@ pub const Client = struct {
146 return ip.Address.from(try self.socket.getLocalAddress());174 return ip.Address.from(try self.socket.getLocalAddress());
147 }175 }
148176
177 /// Query the address that the socket is connected to.
178 pub fn getRemoteAddress(self: Client) !ip.Address {
179 return ip.Address.from(try self.socket.getRemoteAddress());
180 }
181
182 /// Have close() or shutdown() syscalls block until all queued messages in the client have been successfully
183 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
184 /// if the host does not support the option for a socket to linger around up until a timeout specified in
185 /// seconds.
186 pub fn setLinger(self: Client, timeout_seconds: ?u16) !void {
187 return self.socket.setLinger(timeout_seconds);
188 }
189
190 /// Have keep-alive messages be sent periodically. The timing in which keep-alive messages are sent are
191 /// dependant on operating system settings. It returns `error.UnsupportedSocketOption` if the host does
192 /// not support periodically sending keep-alive messages on connection-oriented sockets.
193 pub fn setKeepAlive(self: Client, enabled: bool) !void {
194 return self.socket.setKeepAlive(enabled);
195 }
196
149 /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if197 /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if
150 /// the host does not support sockets disabling Nagle's algorithm.198 /// the host does not support sockets disabling Nagle's algorithm.
151 pub fn setNoDelay(self: Client, enabled: bool) !void {199 pub fn setNoDelay(self: Client, enabled: bool) !void {
152 if (comptime @hasDecl(os, "TCP_NODELAY")) {200 if (comptime @hasDecl(os, "TCP_NODELAY")) {
153 const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled)));201 const bytes = mem.asBytes(&@as(usize, @boolToInt(enabled)));
154 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_NODELAY, bytes);202 return self.socket.setOption(os.IPPROTO_TCP, os.TCP_NODELAY, bytes);
203 }
204 return error.UnsupportedSocketOption;
205 }
206
207 /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
208 /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
209 pub fn setQuickACK(self: Client, enabled: bool) !void {
210 if (comptime @hasDecl(os, "TCP_QUICKACK")) {
211 return self.socket.setOption(os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(u32, @boolToInt(enabled))));
155 }212 }
156 return error.UnsupportedSocketOption;213 return error.UnsupportedSocketOption;
157 }214 }
...@@ -169,7 +226,7 @@ pub const Client = struct {...@@ -169,7 +226,7 @@ pub const Client = struct {
169 /// Set a timeout on the socket that is to occur if no messages are successfully written226 /// Set a timeout on the socket that is to occur if no messages are successfully written
170 /// to its bound destination after a specified number of milliseconds. A subsequent write227 /// to its bound destination after a specified number of milliseconds. A subsequent write
171 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.228 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
172 pub fn setWriteTimeout(self: Client, milliseconds: usize) !void {229 pub fn setWriteTimeout(self: Client, milliseconds: u32) !void {
173 return self.socket.setWriteTimeout(milliseconds);230 return self.socket.setWriteTimeout(milliseconds);
174 }231 }
175232
...@@ -177,7 +234,7 @@ pub const Client = struct {...@@ -177,7 +234,7 @@ pub const Client = struct {
177 /// from its bound destination after a specified number of milliseconds. A subsequent234 /// from its bound destination after a specified number of milliseconds. A subsequent
178 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be235 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
179 /// exceeded.236 /// exceeded.
180 pub fn setReadTimeout(self: Client, milliseconds: usize) !void {237 pub fn setReadTimeout(self: Client, milliseconds: u32) !void {
181 return self.socket.setReadTimeout(milliseconds);238 return self.socket.setReadTimeout(milliseconds);
182 }239 }
183};240};
...@@ -251,16 +308,7 @@ pub const Listener = struct {...@@ -251,16 +308,7 @@ pub const Listener = struct {
251 /// support TCP Fast Open.308 /// support TCP Fast Open.
252 pub fn setFastOpen(self: Listener, enabled: bool) !void {309 pub fn setFastOpen(self: Listener, enabled: bool) !void {
253 if (comptime @hasDecl(os, "TCP_FASTOPEN")) {310 if (comptime @hasDecl(os, "TCP_FASTOPEN")) {
254 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled))));311 return self.socket.setOption(os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(u32, @boolToInt(enabled))));
255 }
256 return error.UnsupportedSocketOption;
257 }
258
259 /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns
260 /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK.
261 pub fn setQuickACK(self: Listener, enabled: bool) !void {
262 if (comptime @hasDecl(os, "TCP_QUICKACK")) {
263 return os.setsockopt(self.socket.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled))));
264 }312 }
265 return error.UnsupportedSocketOption;313 return error.UnsupportedSocketOption;
266 }314 }
...@@ -322,7 +370,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" {...@@ -322,7 +370,7 @@ test "tcp/client: set read timeout of 1 millisecond on blocking client" {
322 defer conn.deinit();370 defer conn.deinit();
323371
324 var buf: [1]u8 = undefined;372 var buf: [1]u8 = undefined;
325 try testing.expectError(error.WouldBlock, client.read(&buf));373 try testing.expectError(error.WouldBlock, client.reader(0).read(&buf));
326}374}
327375
328test "tcp/listener: bind to unspecified ipv4 address" {376test "tcp/listener: bind to unspecified ipv4 address" {
lib/std/x/os/Socket.zig deleted-295
...@@ -1,295 +0,0 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8const net = @import("net.zig");
9
10const os = std.os;
11const fmt = std.fmt;
12const mem = std.mem;
13const time = std.time;
14
15/// A generic socket abstraction.
16const Socket = @This();
17
18/// A socket-address pair.
19pub const Connection = struct {
20 socket: Socket,
21 address: Socket.Address,
22
23 /// Enclose a socket and address into a socket-address pair.
24 pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
25 return .{ .socket = socket, .address = address };
26 }
27};
28
29/// A generic socket address abstraction. It is safe to directly access and modify
30/// the fields of a `Socket.Address`.
31pub const Address = union(enum) {
32 ipv4: net.IPv4.Address,
33 ipv6: net.IPv6.Address,
34
35 /// Instantiate a new address with a IPv4 host and port.
36 pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
37 return .{ .ipv4 = .{ .host = host, .port = port } };
38 }
39
40 /// Instantiate a new address with a IPv6 host and port.
41 pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
42 return .{ .ipv6 = .{ .host = host, .port = port } };
43 }
44
45 /// Parses a `sockaddr` into a generic socket address.
46 pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
47 switch (address.family) {
48 os.AF_INET => {
49 const info = @ptrCast(*const os.sockaddr_in, address);
50 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
51 const port = mem.bigToNative(u16, info.port);
52 return Socket.Address.initIPv4(host, port);
53 },
54 os.AF_INET6 => {
55 const info = @ptrCast(*const os.sockaddr_in6, address);
56 const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
57 const port = mem.bigToNative(u16, info.port);
58 return Socket.Address.initIPv6(host, port);
59 },
60 else => unreachable,
61 }
62 }
63
64 /// Encodes a generic socket address into an extern union that may be reliably
65 /// casted into a `sockaddr` which may be passed into socket syscalls.
66 pub fn toNative(self: Socket.Address) extern union {
67 ipv4: os.sockaddr_in,
68 ipv6: os.sockaddr_in6,
69 } {
70 return switch (self) {
71 .ipv4 => |address| .{
72 .ipv4 = .{
73 .addr = @bitCast(u32, address.host.octets),
74 .port = mem.nativeToBig(u16, address.port),
75 },
76 },
77 .ipv6 => |address| .{
78 .ipv6 = .{
79 .addr = address.host.octets,
80 .port = mem.nativeToBig(u16, address.port),
81 .scope_id = address.host.scope_id,
82 .flowinfo = 0,
83 },
84 },
85 };
86 }
87
88 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
89 pub fn getNativeSize(self: Socket.Address) u32 {
90 return switch (self) {
91 .ipv4 => @sizeOf(os.sockaddr_in),
92 .ipv6 => @sizeOf(os.sockaddr_in6),
93 };
94 }
95
96 /// Implements the `std.fmt.format` API.
97 pub fn format(
98 self: Socket.Address,
99 comptime layout: []const u8,
100 opts: fmt.FormatOptions,
101 writer: anytype,
102 ) !void {
103 switch (self) {
104 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
105 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
106 }
107 }
108};
109
110/// The underlying handle of a socket.
111fd: os.socket_t,
112
113/// Open a new socket.
114pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
115 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
116}
117
118/// Enclose a socket abstraction over an existing socket file descriptor.
119pub fn from(fd: os.socket_t) Socket {
120 return Socket{ .fd = fd };
121}
122
123/// Closes the socket.
124pub fn deinit(self: Socket) void {
125 os.closeSocket(self.fd);
126}
127
128/// Shutdown either the read side, write side, or all side of the socket.
129pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
130 return os.shutdown(self.fd, how);
131}
132
133/// Binds the socket to an address.
134pub fn bind(self: Socket, address: Socket.Address) !void {
135 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
136}
137
138/// Start listening for incoming connections on the socket.
139pub fn listen(self: Socket, max_backlog_size: u31) !void {
140 return os.listen(self.fd, max_backlog_size);
141}
142
143/// Have the socket attempt to the connect to an address.
144pub fn connect(self: Socket, address: Socket.Address) !void {
145 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
146}
147
148/// Accept a pending incoming connection queued to the kernel backlog
149/// of the socket.
150pub fn accept(self: Socket, flags: u32) !Socket.Connection {
151 var address: os.sockaddr = undefined;
152 var address_len: u32 = @sizeOf(os.sockaddr);
153
154 const socket = Socket{ .fd = try os.accept(self.fd, &address, &address_len, flags) };
155 const socket_address = Socket.Address.fromNative(@alignCast(4, &address));
156
157 return Socket.Connection.from(socket, socket_address);
158}
159
160/// Read data from the socket into the buffer provided. It returns the
161/// number of bytes read into the buffer provided.
162pub fn read(self: Socket, buf: []u8) !usize {
163 return os.read(self.fd, buf);
164}
165
166/// Read data from the socket into the buffer provided with a set of flags
167/// specified. It returns the number of bytes read into the buffer provided.
168pub fn recv(self: Socket, buf: []u8, flags: u32) !usize {
169 return os.recv(self.fd, buf, flags);
170}
171
172/// Write a buffer of data provided to the socket. It returns the number
173/// of bytes that are written to the socket.
174pub fn write(self: Socket, buf: []const u8) !usize {
175 return os.write(self.fd, buf);
176}
177
178/// Writes multiple I/O vectors to the socket. It returns the number
179/// of bytes that are written to the socket.
180pub fn writev(self: Socket, buffers: []const os.iovec_const) !usize {
181 return os.writev(self.fd, buffers);
182}
183
184/// Write a buffer of data provided to the socket with a set of flags specified.
185/// It returns the number of bytes that are written to the socket.
186pub fn send(self: Socket, buf: []const u8, flags: u32) !usize {
187 return os.send(self.fd, buf, flags);
188}
189
190/// Writes multiple I/O vectors with a prepended message header to the socket
191/// with a set of flags specified. It returns the number of bytes that are
192/// written to the socket.
193pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
194 return os.sendmsg(self.fd, msg, flags);
195}
196
197/// Query the address that the socket is locally bounded to.
198pub fn getLocalAddress(self: Socket) !Socket.Address {
199 var address: os.sockaddr = undefined;
200 var address_len: u32 = @sizeOf(os.sockaddr);
201 try os.getsockname(self.fd, &address, &address_len);
202 return Socket.Address.fromNative(@alignCast(4, &address));
203}
204
205/// Query and return the latest cached error on the socket.
206pub fn getError(self: Socket) !void {
207 return os.getsockoptError(self.fd);
208}
209
210/// Query the read buffer size of the socket.
211pub fn getReadBufferSize(self: Socket) !u32 {
212 var value: u32 = undefined;
213 var value_len: u32 = @sizeOf(u32);
214
215 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
216 return switch (os.errno(rc)) {
217 0 => value,
218 os.EBADF => error.BadFileDescriptor,
219 os.EFAULT => error.InvalidAddressSpace,
220 os.EINVAL => error.InvalidSocketOption,
221 os.ENOPROTOOPT => error.UnknownSocketOption,
222 os.ENOTSOCK => error.NotASocket,
223 else => |err| os.unexpectedErrno(err),
224 };
225}
226
227/// Query the write buffer size of the socket.
228pub fn getWriteBufferSize(self: Socket) !u32 {
229 var value: u32 = undefined;
230 var value_len: u32 = @sizeOf(u32);
231
232 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);
233 return switch (os.errno(rc)) {
234 0 => value,
235 os.EBADF => error.BadFileDescriptor,
236 os.EFAULT => error.InvalidAddressSpace,
237 os.EINVAL => error.InvalidSocketOption,
238 os.ENOPROTOOPT => error.UnknownSocketOption,
239 os.ENOTSOCK => error.NotASocket,
240 else => |err| os.unexpectedErrno(err),
241 };
242}
243
244/// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
245/// the host does not support sockets listening the same address.
246pub fn setReuseAddress(self: Socket, enabled: bool) !void {
247 if (comptime @hasDecl(os, "SO_REUSEADDR")) {
248 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(usize, @boolToInt(enabled))));
249 }
250 return error.UnsupportedSocketOption;
251}
252
253/// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
254/// the host does not supports sockets listening on the same port.
255pub fn setReusePort(self: Socket, enabled: bool) !void {
256 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
257 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(usize, @boolToInt(enabled))));
258 }
259 return error.UnsupportedSocketOption;
260}
261
262/// Set the write buffer size of the socket.
263pub fn setWriteBufferSize(self: Socket, size: u32) !void {
264 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
265}
266
267/// Set the read buffer size of the socket.
268pub fn setReadBufferSize(self: Socket, size: u32) !void {
269 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
270}
271
272/// Set a timeout on the socket that is to occur if no messages are successfully written
273/// to its bound destination after a specified number of milliseconds. A subsequent write
274/// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
275pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
276 const timeout = os.timeval{
277 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
278 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
279 };
280
281 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
282}
283
284/// Set a timeout on the socket that is to occur if no messages are successfully read
285/// from its bound destination after a specified number of milliseconds. A subsequent
286/// read from the socket will thereafter return `error.WouldBlock` should the timeout be
287/// exceeded.
288pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
289 const timeout = os.timeval{
290 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
291 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
292 };
293
294 return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
295}
lib/std/x/os/net.zig+9
...@@ -20,6 +20,14 @@ pub fn resolveScopeID(name: []const u8) !u32 {...@@ -20,6 +20,14 @@ pub fn resolveScopeID(name: []const u8) !u32 {
20 if (comptime @hasDecl(os, "IFNAMESIZE")) {20 if (comptime @hasDecl(os, "IFNAMESIZE")) {
21 if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong;21 if (name.len >= os.IFNAMESIZE - 1) return error.NameTooLong;
2222
23 if (comptime builtin.os.tag == .windows) {
24 var interface_name: [os.IFNAMESIZE]u8 = undefined;
25 mem.copy(u8, &interface_name, name);
26 interface_name[name.len] = 0;
27
28 return os.windows.ws2_32.if_nametoindex(@ptrCast([*:0]const u8, &interface_name));
29 }
30
23 const fd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM, 0);31 const fd = try os.socket(os.AF_UNIX, os.SOCK_DGRAM, 0);
24 defer os.closeSocket(fd);32 defer os.closeSocket(fd);
2533
...@@ -31,6 +39,7 @@ pub fn resolveScopeID(name: []const u8) !u32 {...@@ -31,6 +39,7 @@ pub fn resolveScopeID(name: []const u8) !u32 {
3139
32 return @bitCast(u32, f.ifru.ivalue);40 return @bitCast(u32, f.ifru.ivalue);
33 }41 }
42
34 return error.Unsupported;43 return error.Unsupported;
35}44}
3645
lib/std/x/os/socket.zig created+123
...@@ -0,0 +1,123 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8const net = @import("net.zig");
9
10const os = std.os;
11const fmt = std.fmt;
12const mem = std.mem;
13const time = std.time;
14const builtin = std.builtin;
15
16/// A generic, cross-platform socket abstraction.
17pub const Socket = struct {
18 /// A socket-address pair.
19 pub const Connection = struct {
20 socket: Socket,
21 address: Socket.Address,
22
23 /// Enclose a socket and address into a socket-address pair.
24 pub fn from(socket: Socket, address: Socket.Address) Socket.Connection {
25 return .{ .socket = socket, .address = address };
26 }
27 };
28
29 /// A generic socket address abstraction. It is safe to directly access and modify
30 /// the fields of a `Socket.Address`.
31 pub const Address = union(enum) {
32 ipv4: net.IPv4.Address,
33 ipv6: net.IPv6.Address,
34
35 /// Instantiate a new address with a IPv4 host and port.
36 pub fn initIPv4(host: net.IPv4, port: u16) Socket.Address {
37 return .{ .ipv4 = .{ .host = host, .port = port } };
38 }
39
40 /// Instantiate a new address with a IPv6 host and port.
41 pub fn initIPv6(host: net.IPv6, port: u16) Socket.Address {
42 return .{ .ipv6 = .{ .host = host, .port = port } };
43 }
44
45 /// Parses a `sockaddr` into a generic socket address.
46 pub fn fromNative(address: *align(4) const os.sockaddr) Socket.Address {
47 switch (address.family) {
48 os.AF_INET => {
49 const info = @ptrCast(*const os.sockaddr_in, address);
50 const host = net.IPv4{ .octets = @bitCast([4]u8, info.addr) };
51 const port = mem.bigToNative(u16, info.port);
52 return Socket.Address.initIPv4(host, port);
53 },
54 os.AF_INET6 => {
55 const info = @ptrCast(*const os.sockaddr_in6, address);
56 const host = net.IPv6{ .octets = info.addr, .scope_id = info.scope_id };
57 const port = mem.bigToNative(u16, info.port);
58 return Socket.Address.initIPv6(host, port);
59 },
60 else => unreachable,
61 }
62 }
63
64 /// Encodes a generic socket address into an extern union that may be reliably
65 /// casted into a `sockaddr` which may be passed into socket syscalls.
66 pub fn toNative(self: Socket.Address) extern union {
67 ipv4: os.sockaddr_in,
68 ipv6: os.sockaddr_in6,
69 } {
70 return switch (self) {
71 .ipv4 => |address| .{
72 .ipv4 = .{
73 .addr = @bitCast(u32, address.host.octets),
74 .port = mem.nativeToBig(u16, address.port),
75 },
76 },
77 .ipv6 => |address| .{
78 .ipv6 = .{
79 .addr = address.host.octets,
80 .port = mem.nativeToBig(u16, address.port),
81 .scope_id = address.host.scope_id,
82 .flowinfo = 0,
83 },
84 },
85 };
86 }
87
88 /// Returns the number of bytes that make up the `sockaddr` equivalent to the address.
89 pub fn getNativeSize(self: Socket.Address) u32 {
90 return switch (self) {
91 .ipv4 => @sizeOf(os.sockaddr_in),
92 .ipv6 => @sizeOf(os.sockaddr_in6),
93 };
94 }
95
96 /// Implements the `std.fmt.format` API.
97 pub fn format(
98 self: Socket.Address,
99 comptime layout: []const u8,
100 opts: fmt.FormatOptions,
101 writer: anytype,
102 ) !void {
103 switch (self) {
104 .ipv4 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
105 .ipv6 => |address| try fmt.format(writer, "{}:{}", .{ address.host, address.port }),
106 }
107 }
108 };
109
110 /// The underlying handle of a socket.
111 fd: os.socket_t,
112
113 /// Enclose a socket abstraction over an existing socket file descriptor.
114 pub fn from(fd: os.socket_t) Socket {
115 return Socket{ .fd = fd };
116 }
117
118 /// Mix in socket syscalls depending on the platform we are compiling against.
119 pub usingnamespace switch (builtin.os.tag) {
120 .windows => @import("socket_windows.zig"),
121 else => @import("socket_posix.zig"),
122 }.Mixin(Socket);
123};
lib/std/x/os/socket_posix.zig created+251
...@@ -0,0 +1,251 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8
9const os = std.os;
10const mem = std.mem;
11const time = std.time;
12
13pub fn Mixin(comptime Socket: type) type {
14 return struct {
15 /// Open a new socket.
16 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
17 return Socket{ .fd = try os.socket(domain, socket_type, protocol) };
18 }
19
20 /// Closes the socket.
21 pub fn deinit(self: Socket) void {
22 os.closeSocket(self.fd);
23 }
24
25 /// Shutdown either the read side, write side, or all side of the socket.
26 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
27 return os.shutdown(self.fd, how);
28 }
29
30 /// Binds the socket to an address.
31 pub fn bind(self: Socket, address: Socket.Address) !void {
32 return os.bind(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
33 }
34
35 /// Start listening for incoming connections on the socket.
36 pub fn listen(self: Socket, max_backlog_size: u31) !void {
37 return os.listen(self.fd, max_backlog_size);
38 }
39
40 /// Have the socket attempt to the connect to an address.
41 pub fn connect(self: Socket, address: Socket.Address) !void {
42 return os.connect(self.fd, @ptrCast(*const os.sockaddr, &address.toNative()), address.getNativeSize());
43 }
44
45 /// Accept a pending incoming connection queued to the kernel backlog
46 /// of the socket.
47 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
48 var address: os.sockaddr_storage = undefined;
49 var address_len: u32 = @sizeOf(os.sockaddr_storage);
50
51 const socket = Socket{ .fd = try os.accept(self.fd, @ptrCast(*os.sockaddr, &address), &address_len, flags) };
52 const socket_address = Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
53
54 return Socket.Connection.from(socket, socket_address);
55 }
56
57 /// Read data from the socket into the buffer provided with a set of flags
58 /// specified. It returns the number of bytes read into the buffer provided.
59 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
60 return os.recv(self.fd, buf, flags);
61 }
62
63 /// Write a buffer of data provided to the socket with a set of flags specified.
64 /// It returns the number of bytes that are written to the socket.
65 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
66 return os.send(self.fd, buf, flags);
67 }
68
69 /// Writes multiple I/O vectors with a prepended message header to the socket
70 /// with a set of flags specified. It returns the number of bytes that are
71 /// written to the socket.
72 pub fn writeVectorized(self: Socket, msg: os.msghdr_const, flags: u32) !usize {
73 return os.sendmsg(self.fd, msg, flags);
74 }
75
76 /// Read multiple I/O vectors with a prepended message header from the socket
77 /// with a set of flags specified. It returns the number of bytes that were
78 /// read into the buffer provided.
79 pub fn readVectorized(self: Socket, msg: *os.msghdr, flags: u32) !usize {
80 if (comptime @hasDecl(os.system, "recvmsg")) {
81 while (true) {
82 const rc = os.system.recvmsg(self.fd, msg, flags);
83 return switch (os.errno(rc)) {
84 0 => @intCast(usize, rc),
85 os.EBADF => unreachable, // always a race condition
86 os.EFAULT => unreachable,
87 os.EINVAL => unreachable,
88 os.ENOTCONN => unreachable,
89 os.ENOTSOCK => unreachable,
90 os.EINTR => continue,
91 os.EAGAIN => error.WouldBlock,
92 os.ENOMEM => error.SystemResources,
93 os.ECONNREFUSED => error.ConnectionRefused,
94 os.ECONNRESET => error.ConnectionResetByPeer,
95 else => |err| os.unexpectedErrno(err),
96 };
97 }
98 }
99 return error.NotSupported;
100 }
101
102 /// Query the address that the socket is locally bounded to.
103 pub fn getLocalAddress(self: Socket) !Socket.Address {
104 var address: os.sockaddr_storage = undefined;
105 var address_len: u32 = @sizeOf(os.sockaddr_storage);
106 try os.getsockname(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
107 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
108 }
109
110 /// Query the address that the socket is connected to.
111 pub fn getRemoteAddress(self: Socket) !Socket.Address {
112 var address: os.sockaddr_storage = undefined;
113 var address_len: u32 = @sizeOf(os.sockaddr_storage);
114 try os.getpeername(self.fd, @ptrCast(*os.sockaddr, &address), &address_len);
115 return Socket.Address.fromNative(@ptrCast(*os.sockaddr, &address));
116 }
117
118 /// Query and return the latest cached error on the socket.
119 pub fn getError(self: Socket) !void {
120 return os.getsockoptError(self.fd);
121 }
122
123 /// Query the read buffer size of the socket.
124 pub fn getReadBufferSize(self: Socket) !u32 {
125 var value: u32 = undefined;
126 var value_len: u32 = @sizeOf(u32);
127
128 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len);
129 return switch (os.errno(rc)) {
130 0 => value,
131 os.EBADF => error.BadFileDescriptor,
132 os.EFAULT => error.InvalidAddressSpace,
133 os.EINVAL => error.InvalidSocketOption,
134 os.ENOPROTOOPT => error.UnknownSocketOption,
135 os.ENOTSOCK => error.NotASocket,
136 else => |err| os.unexpectedErrno(err),
137 };
138 }
139
140 /// Query the write buffer size of the socket.
141 pub fn getWriteBufferSize(self: Socket) !u32 {
142 var value: u32 = undefined;
143 var value_len: u32 = @sizeOf(u32);
144
145 const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len);
146 return switch (os.errno(rc)) {
147 0 => value,
148 os.EBADF => error.BadFileDescriptor,
149 os.EFAULT => error.InvalidAddressSpace,
150 os.EINVAL => error.InvalidSocketOption,
151 os.ENOPROTOOPT => error.UnknownSocketOption,
152 os.ENOTSOCK => error.NotASocket,
153 else => |err| os.unexpectedErrno(err),
154 };
155 }
156
157 /// Set a socket option.
158 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
159 return os.setsockopt(self.fd, level, code, value);
160 }
161
162 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
163 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
164 /// if the host does not support the option for a socket to linger around up until a timeout specified in
165 /// seconds.
166 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
167 if (comptime @hasDecl(os, "SO_LINGER")) {
168 const settings = extern struct {
169 l_onoff: c_int,
170 l_linger: c_int,
171 }{
172 .l_onoff = @intCast(c_int, @boolToInt(timeout_seconds != null)),
173 .l_linger = if (timeout_seconds) |seconds| @intCast(c_int, seconds) else 0,
174 };
175
176 return self.setOption(os.SOL_SOCKET, os.SO_LINGER, mem.asBytes(&settings));
177 }
178
179 return error.UnsupportedSocketOption;
180 }
181
182 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
183 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
184 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
185 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
186 if (comptime @hasDecl(os, "SO_KEEPALIVE")) {
187 return self.setOption(os.SOL_SOCKET, os.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
188 }
189 return error.UnsupportedSocketOption;
190 }
191
192 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
193 /// the host does not support sockets listening the same address.
194 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
195 if (comptime @hasDecl(os, "SO_REUSEADDR")) {
196 return self.setOption(os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
197 }
198 return error.UnsupportedSocketOption;
199 }
200
201 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
202 /// the host does not supports sockets listening on the same port.
203 pub fn setReusePort(self: Socket, enabled: bool) !void {
204 if (comptime @hasDecl(os, "SO_REUSEPORT")) {
205 return self.setOption(os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(u32, @boolToInt(enabled))));
206 }
207 return error.UnsupportedSocketOption;
208 }
209
210 /// Set the write buffer size of the socket.
211 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
212 return self.setOption(os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size));
213 }
214
215 /// Set the read buffer size of the socket.
216 pub fn setReadBufferSize(self: Socket, size: u32) !void {
217 return self.setOption(os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size));
218 }
219
220 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
221 /// set on a non-blocking socket.
222 ///
223 /// Set a timeout on the socket that is to occur if no messages are successfully written
224 /// to its bound destination after a specified number of milliseconds. A subsequent write
225 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
226 pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void {
227 const timeout = os.timeval{
228 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
229 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
230 };
231
232 return self.setOption(os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout));
233 }
234
235 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
236 /// set on a non-blocking socket.
237 ///
238 /// Set a timeout on the socket that is to occur if no messages are successfully read
239 /// from its bound destination after a specified number of milliseconds. A subsequent
240 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
241 /// exceeded.
242 pub fn setReadTimeout(self: Socket, milliseconds: usize) !void {
243 const timeout = os.timeval{
244 .tv_sec = @intCast(i32, milliseconds / time.ms_per_s),
245 .tv_usec = @intCast(i32, (milliseconds % time.ms_per_s) * time.us_per_ms),
246 };
247
248 return self.setOption(os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout));
249 }
250 };
251}
lib/std/x/os/socket_windows.zig created+448
...@@ -0,0 +1,448 @@
1// SPDX-License-Identifier: MIT
2// Copyright (c) 2015-2021 Zig Contributors
3// This file is part of [zig](https://ziglang.org/), which is MIT licensed.
4// The MIT license requires this copyright notice to be included in all copies
5// and substantial portions of the software.
6
7const std = @import("../../std.zig");
8const net = @import("net.zig");
9
10const os = std.os;
11const mem = std.mem;
12
13const windows = std.os.windows;
14const ws2_32 = windows.ws2_32;
15
16pub fn Mixin(comptime Socket: type) type {
17 return struct {
18 /// Open a new socket.
19 pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket {
20 var filtered_socket_type = socket_type & ~@as(u32, os.SOCK_CLOEXEC);
21
22 var filtered_flags: u32 = ws2_32.WSA_FLAG_OVERLAPPED;
23 if (socket_type & os.SOCK_CLOEXEC != 0) {
24 filtered_flags |= ws2_32.WSA_FLAG_NO_HANDLE_INHERIT;
25 }
26
27 const fd = ws2_32.WSASocketW(
28 @intCast(i32, domain),
29 @intCast(i32, filtered_socket_type),
30 @intCast(i32, protocol),
31 null,
32 0,
33 filtered_flags,
34 );
35 if (fd == ws2_32.INVALID_SOCKET) {
36 return switch (ws2_32.WSAGetLastError()) {
37 .WSANOTINITIALISED => {
38 _ = try windows.WSAStartup(2, 2);
39 return Socket.init(domain, socket_type, protocol);
40 },
41 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
42 .WSAEMFILE => error.ProcessFdQuotaExceeded,
43 .WSAENOBUFS => error.SystemResources,
44 .WSAEPROTONOSUPPORT => error.ProtocolNotSupported,
45 else => |err| windows.unexpectedWSAError(err),
46 };
47 }
48
49 return Socket{ .fd = fd };
50 }
51
52 /// Closes the socket.
53 pub fn deinit(self: Socket) void {
54 _ = ws2_32.closesocket(self.fd);
55 }
56
57 /// Shutdown either the read side, write side, or all side of the socket.
58 pub fn shutdown(self: Socket, how: os.ShutdownHow) !void {
59 const rc = ws2_32.shutdown(self.fd, switch (how) {
60 .recv => ws2_32.SD_RECEIVE,
61 .send => ws2_32.SD_SEND,
62 .both => ws2_32.SD_BOTH,
63 });
64 if (rc == ws2_32.SOCKET_ERROR) {
65 return switch (ws2_32.WSAGetLastError()) {
66 .WSAECONNABORTED => return error.ConnectionAborted,
67 .WSAECONNRESET => return error.ConnectionResetByPeer,
68 .WSAEINPROGRESS => return error.BlockingOperationInProgress,
69 .WSAEINVAL => unreachable,
70 .WSAENETDOWN => return error.NetworkSubsystemFailed,
71 .WSAENOTCONN => return error.SocketNotConnected,
72 .WSAENOTSOCK => unreachable,
73 .WSANOTINITIALISED => unreachable,
74 else => |err| return windows.unexpectedWSAError(err),
75 };
76 }
77 }
78
79 /// Binds the socket to an address.
80 pub fn bind(self: Socket, address: Socket.Address) !void {
81 const rc = ws2_32.bind(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
82 if (rc == ws2_32.SOCKET_ERROR) {
83 return switch (ws2_32.WSAGetLastError()) {
84 .WSAENETDOWN => error.NetworkSubsystemFailed,
85 .WSAEACCES => error.AccessDenied,
86 .WSAEADDRINUSE => error.AddressInUse,
87 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
88 .WSAEFAULT => error.BadAddress,
89 .WSAEINPROGRESS => error.WouldBlock,
90 .WSAEINVAL => error.AlreadyBound,
91 .WSAENOBUFS => error.NoEphemeralPortsAvailable,
92 .WSAENOTSOCK => error.NotASocket,
93 else => |err| windows.unexpectedWSAError(err),
94 };
95 }
96 }
97
98 /// Start listening for incoming connections on the socket.
99 pub fn listen(self: Socket, max_backlog_size: u31) !void {
100 const rc = ws2_32.listen(self.fd, max_backlog_size);
101 if (rc == ws2_32.SOCKET_ERROR) {
102 return switch (ws2_32.WSAGetLastError()) {
103 .WSAENETDOWN => error.NetworkSubsystemFailed,
104 .WSAEADDRINUSE => error.AddressInUse,
105 .WSAEISCONN => error.AlreadyConnected,
106 .WSAEINVAL => error.SocketNotBound,
107 .WSAEMFILE, .WSAENOBUFS => error.SystemResources,
108 .WSAENOTSOCK => error.FileDescriptorNotASocket,
109 .WSAEOPNOTSUPP => error.OperationNotSupported,
110 .WSAEINPROGRESS => error.WouldBlock,
111 else => |err| windows.unexpectedWSAError(err),
112 };
113 }
114 }
115
116 /// Have the socket attempt to the connect to an address.
117 pub fn connect(self: Socket, address: Socket.Address) !void {
118 const rc = ws2_32.connect(self.fd, @ptrCast(*const ws2_32.sockaddr, &address.toNative()), @intCast(c_int, address.getNativeSize()));
119 if (rc == ws2_32.SOCKET_ERROR) {
120 return switch (ws2_32.WSAGetLastError()) {
121 .WSAEADDRINUSE => error.AddressInUse,
122 .WSAEADDRNOTAVAIL => error.AddressNotAvailable,
123 .WSAECONNREFUSED => error.ConnectionRefused,
124 .WSAETIMEDOUT => error.ConnectionTimedOut,
125 .WSAEFAULT => error.BadAddress,
126 .WSAEINVAL => error.ListeningSocket,
127 .WSAEISCONN => error.AlreadyConnected,
128 .WSAENOTSOCK => error.NotASocket,
129 .WSAEACCES => error.BroadcastNotEnabled,
130 .WSAENOBUFS => error.SystemResources,
131 .WSAEAFNOSUPPORT => error.AddressFamilyNotSupported,
132 .WSAEINPROGRESS, .WSAEWOULDBLOCK => error.WouldBlock,
133 .WSAEHOSTUNREACH, .WSAENETUNREACH => error.NetworkUnreachable,
134 else => |err| windows.unexpectedWSAError(err),
135 };
136 }
137 }
138
139 /// Accept a pending incoming connection queued to the kernel backlog
140 /// of the socket.
141 pub fn accept(self: Socket, flags: u32) !Socket.Connection {
142 var address: ws2_32.sockaddr_storage = undefined;
143 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
144
145 const rc = ws2_32.accept(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
146 if (rc == ws2_32.INVALID_SOCKET) {
147 return switch (ws2_32.WSAGetLastError()) {
148 .WSANOTINITIALISED => unreachable,
149 .WSAECONNRESET => error.ConnectionResetByPeer,
150 .WSAEFAULT => unreachable,
151 .WSAEINVAL => error.SocketNotListening,
152 .WSAEMFILE => error.ProcessFdQuotaExceeded,
153 .WSAENETDOWN => error.NetworkSubsystemFailed,
154 .WSAENOBUFS => error.FileDescriptorNotASocket,
155 .WSAEOPNOTSUPP => error.OperationNotSupported,
156 .WSAEWOULDBLOCK => error.WouldBlock,
157 else => |err| windows.unexpectedWSAError(err),
158 };
159 }
160
161 const socket = Socket.from(rc);
162 const socket_address = Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
163
164 return Socket.Connection.from(socket, socket_address);
165 }
166
167 /// Read data from the socket into the buffer provided with a set of flags
168 /// specified. It returns the number of bytes read into the buffer provided.
169 pub fn read(self: Socket, buf: []u8, flags: u32) !usize {
170 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = buf.ptr }};
171 var num_bytes: u32 = undefined;
172 var flags_ = flags;
173
174 const rc = ws2_32.WSARecv(self.fd, bufs, 1, &num_bytes, &flags_, null, null);
175 if (rc == ws2_32.SOCKET_ERROR) {
176 return switch (ws2_32.WSAGetLastError()) {
177 .WSAECONNABORTED => error.ConnectionAborted,
178 .WSAECONNRESET => error.ConnectionResetByPeer,
179 .WSAEDISCON => error.ConnectionClosedByPeer,
180 .WSAEFAULT => error.BadBuffer,
181 .WSAEINPROGRESS,
182 .WSAEWOULDBLOCK,
183 .WSA_IO_PENDING,
184 .WSAETIMEDOUT,
185 => error.WouldBlock,
186 .WSAEINTR => error.Cancelled,
187 .WSAEINVAL => error.SocketNotBound,
188 .WSAEMSGSIZE => error.MessageTooLarge,
189 .WSAENETDOWN => error.NetworkSubsystemFailed,
190 .WSAENETRESET => error.NetworkReset,
191 .WSAENOTCONN => error.SocketNotConnected,
192 .WSAENOTSOCK => error.FileDescriptorNotASocket,
193 .WSAEOPNOTSUPP => error.OperationNotSupported,
194 .WSAESHUTDOWN => error.AlreadyShutdown,
195 .WSA_OPERATION_ABORTED => error.OperationAborted,
196 else => |err| windows.unexpectedWSAError(err),
197 };
198 }
199
200 return @intCast(usize, num_bytes);
201 }
202
203 /// Write a buffer of data provided to the socket with a set of flags specified.
204 /// It returns the number of bytes that are written to the socket.
205 pub fn write(self: Socket, buf: []const u8, flags: u32) !usize {
206 var bufs = &[_]ws2_32.WSABUF{.{ .len = @intCast(u32, buf.len), .buf = @intToPtr([*]u8, @ptrToInt(buf.ptr)) }};
207 var num_bytes: u32 = undefined;
208
209 const rc = ws2_32.WSASend(self.fd, bufs, 1, &num_bytes, flags, null, null);
210 if (rc == ws2_32.SOCKET_ERROR) {
211 return switch (ws2_32.WSAGetLastError()) {
212 .WSAECONNABORTED => error.ConnectionAborted,
213 .WSAECONNRESET => error.ConnectionResetByPeer,
214 .WSAEFAULT => error.BadBuffer,
215 .WSAEINPROGRESS,
216 .WSAEWOULDBLOCK,
217 .WSA_IO_PENDING,
218 .WSAETIMEDOUT,
219 => error.WouldBlock,
220 .WSAEINTR => error.Cancelled,
221 .WSAEINVAL => error.SocketNotBound,
222 .WSAEMSGSIZE => error.MessageTooLarge,
223 .WSAENETDOWN => error.NetworkSubsystemFailed,
224 .WSAENETRESET => error.NetworkReset,
225 .WSAENOBUFS => error.BufferDeadlock,
226 .WSAENOTCONN => error.SocketNotConnected,
227 .WSAENOTSOCK => error.FileDescriptorNotASocket,
228 .WSAEOPNOTSUPP => error.OperationNotSupported,
229 .WSAESHUTDOWN => error.AlreadyShutdown,
230 .WSA_OPERATION_ABORTED => error.OperationAborted,
231 else => |err| windows.unexpectedWSAError(err),
232 };
233 }
234
235 return @intCast(usize, num_bytes);
236 }
237
238 /// Writes multiple I/O vectors with a prepended message header to the socket
239 /// with a set of flags specified. It returns the number of bytes that are
240 /// written to the socket.
241 pub fn writeVectorized(self: Socket, msg: ws2_32.msghdr_const, flags: u32) !usize {
242 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSASENDMSG, self.fd, ws2_32.WSAID_WSASENDMSG);
243
244 var num_bytes: u32 = undefined;
245
246 const rc = call(self.fd, &msg, flags, &num_bytes, null, null);
247 if (rc == ws2_32.SOCKET_ERROR) {
248 return switch (ws2_32.WSAGetLastError()) {
249 .WSAECONNABORTED => error.ConnectionAborted,
250 .WSAECONNRESET => error.ConnectionResetByPeer,
251 .WSAEFAULT => error.BadBuffer,
252 .WSAEINPROGRESS,
253 .WSAEWOULDBLOCK,
254 .WSA_IO_PENDING,
255 .WSAETIMEDOUT,
256 => error.WouldBlock,
257 .WSAEINTR => error.Cancelled,
258 .WSAEINVAL => error.SocketNotBound,
259 .WSAEMSGSIZE => error.MessageTooLarge,
260 .WSAENETDOWN => error.NetworkSubsystemFailed,
261 .WSAENETRESET => error.NetworkReset,
262 .WSAENOBUFS => error.BufferDeadlock,
263 .WSAENOTCONN => error.SocketNotConnected,
264 .WSAENOTSOCK => error.FileDescriptorNotASocket,
265 .WSAEOPNOTSUPP => error.OperationNotSupported,
266 .WSAESHUTDOWN => error.AlreadyShutdown,
267 .WSA_OPERATION_ABORTED => error.OperationAborted,
268 else => |err| windows.unexpectedWSAError(err),
269 };
270 }
271
272 return @intCast(usize, num_bytes);
273 }
274
275 /// Read multiple I/O vectors with a prepended message header from the socket
276 /// with a set of flags specified. It returns the number of bytes that were
277 /// read into the buffer provided.
278 pub fn readVectorized(self: Socket, msg: *ws2_32.msghdr, flags: u32) !usize {
279 const call = try windows.loadWinsockExtensionFunction(ws2_32.LPFN_WSARECVMSG, self.fd, ws2_32.WSAID_WSARECVMSG);
280
281 var num_bytes: u32 = undefined;
282
283 const rc = call(self.fd, msg, &num_bytes, null, null);
284 if (rc == ws2_32.SOCKET_ERROR) {
285 return switch (ws2_32.WSAGetLastError()) {
286 .WSAECONNABORTED => error.ConnectionAborted,
287 .WSAECONNRESET => error.ConnectionResetByPeer,
288 .WSAEDISCON => error.ConnectionClosedByPeer,
289 .WSAEFAULT => error.BadBuffer,
290 .WSAEINPROGRESS,
291 .WSAEWOULDBLOCK,
292 .WSA_IO_PENDING,
293 .WSAETIMEDOUT,
294 => error.WouldBlock,
295 .WSAEINTR => error.Cancelled,
296 .WSAEINVAL => error.SocketNotBound,
297 .WSAEMSGSIZE => error.MessageTooLarge,
298 .WSAENETDOWN => error.NetworkSubsystemFailed,
299 .WSAENETRESET => error.NetworkReset,
300 .WSAENOTCONN => error.SocketNotConnected,
301 .WSAENOTSOCK => error.FileDescriptorNotASocket,
302 .WSAEOPNOTSUPP => error.OperationNotSupported,
303 .WSAESHUTDOWN => error.AlreadyShutdown,
304 .WSA_OPERATION_ABORTED => error.OperationAborted,
305 else => |err| windows.unexpectedWSAError(err),
306 };
307 }
308
309 return @intCast(usize, num_bytes);
310 }
311
312 /// Query the address that the socket is locally bounded to.
313 pub fn getLocalAddress(self: Socket) !Socket.Address {
314 var address: ws2_32.sockaddr_storage = undefined;
315 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
316
317 const rc = ws2_32.getsockname(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
318 if (rc == ws2_32.SOCKET_ERROR) {
319 return switch (ws2_32.WSAGetLastError()) {
320 .WSANOTINITIALISED => unreachable,
321 .WSAEFAULT => unreachable,
322 .WSAENETDOWN => error.NetworkSubsystemFailed,
323 .WSAENOTSOCK => error.FileDescriptorNotASocket,
324 .WSAEINVAL => error.SocketNotBound,
325 else => |err| windows.unexpectedWSAError(err),
326 };
327 }
328
329 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
330 }
331
332 /// Query the address that the socket is connected to.
333 pub fn getRemoteAddress(self: Socket) !Socket.Address {
334 var address: ws2_32.sockaddr_storage = undefined;
335 var address_len: c_int = @sizeOf(ws2_32.sockaddr_storage);
336
337 const rc = ws2_32.getpeername(self.fd, @ptrCast(*ws2_32.sockaddr, &address), &address_len);
338 if (rc == ws2_32.SOCKET_ERROR) {
339 return switch (ws2_32.WSAGetLastError()) {
340 .WSANOTINITIALISED => unreachable,
341 .WSAEFAULT => unreachable,
342 .WSAENETDOWN => error.NetworkSubsystemFailed,
343 .WSAENOTSOCK => error.FileDescriptorNotASocket,
344 .WSAEINVAL => error.SocketNotBound,
345 else => |err| windows.unexpectedWSAError(err),
346 };
347 }
348
349 return Socket.Address.fromNative(@ptrCast(*ws2_32.sockaddr, &address));
350 }
351
352 /// Query and return the latest cached error on the socket.
353 pub fn getError(self: Socket) !void {
354 return {};
355 }
356
357 /// Query the read buffer size of the socket.
358 pub fn getReadBufferSize(self: Socket) !u32 {
359 return 0;
360 }
361
362 /// Query the write buffer size of the socket.
363 pub fn getWriteBufferSize(self: Socket) !u32 {
364 return 0;
365 }
366
367 /// Set a socket option.
368 pub fn setOption(self: Socket, level: u32, code: u32, value: []const u8) !void {
369 const rc = ws2_32.setsockopt(self.fd, @intCast(i32, level), @intCast(i32, code), value.ptr, @intCast(i32, value.len));
370 if (rc == ws2_32.SOCKET_ERROR) {
371 return switch (ws2_32.WSAGetLastError()) {
372 .WSANOTINITIALISED => unreachable,
373 .WSAENETDOWN => return error.NetworkSubsystemFailed,
374 .WSAEFAULT => unreachable,
375 .WSAENOTSOCK => return error.FileDescriptorNotASocket,
376 .WSAEINVAL => return error.SocketNotBound,
377 else => |err| windows.unexpectedWSAError(err),
378 };
379 }
380 }
381
382 /// Have close() or shutdown() syscalls block until all queued messages in the socket have been successfully
383 /// sent, or if the timeout specified in seconds has been reached. It returns `error.UnsupportedSocketOption`
384 /// if the host does not support the option for a socket to linger around up until a timeout specified in
385 /// seconds.
386 pub fn setLinger(self: Socket, timeout_seconds: ?u16) !void {
387 const settings = ws2_32.linger{
388 .l_onoff = @as(u16, @boolToInt(timeout_seconds != null)),
389 .l_linger = if (timeout_seconds) |seconds| seconds else 0,
390 };
391
392 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_LINGER, mem.asBytes(&settings));
393 }
394
395 /// On connection-oriented sockets, have keep-alive messages be sent periodically. The timing in which keep-alive
396 /// messages are sent are dependant on operating system settings. It returns `error.UnsupportedSocketOption` if
397 /// the host does not support periodically sending keep-alive messages on connection-oriented sockets.
398 pub fn setKeepAlive(self: Socket, enabled: bool) !void {
399 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_KEEPALIVE, mem.asBytes(&@as(u32, @boolToInt(enabled))));
400 }
401
402 /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if
403 /// the host does not support sockets listening the same address.
404 pub fn setReuseAddress(self: Socket, enabled: bool) !void {
405 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_REUSEADDR, mem.asBytes(&@as(u32, @boolToInt(enabled))));
406 }
407
408 /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if
409 /// the host does not supports sockets listening on the same port.
410 ///
411 /// TODO: verify if this truly mimicks SO_REUSEPORT behavior, or if SO_REUSE_UNICASTPORT provides the correct behavior
412 pub fn setReusePort(self: Socket, enabled: bool) !void {
413 try self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_BROADCAST, mem.asBytes(&@as(u32, @boolToInt(enabled))));
414 try self.setReuseAddress(enabled);
415 }
416
417 /// Set the write buffer size of the socket.
418 pub fn setWriteBufferSize(self: Socket, size: u32) !void {
419 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDBUF, mem.asBytes(&size));
420 }
421
422 /// Set the read buffer size of the socket.
423 pub fn setReadBufferSize(self: Socket, size: u32) !void {
424 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVBUF, mem.asBytes(&size));
425 }
426
427 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
428 /// set on a non-blocking socket.
429 ///
430 /// Set a timeout on the socket that is to occur if no messages are successfully written
431 /// to its bound destination after a specified number of milliseconds. A subsequent write
432 /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded.
433 pub fn setWriteTimeout(self: Socket, milliseconds: u32) !void {
434 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_SNDTIMEO, mem.asBytes(&milliseconds));
435 }
436
437 /// WARNING: Timeouts only affect blocking sockets. It is undefined behavior if a timeout is
438 /// set on a non-blocking socket.
439 ///
440 /// Set a timeout on the socket that is to occur if no messages are successfully read
441 /// from its bound destination after a specified number of milliseconds. A subsequent
442 /// read from the socket will thereafter return `error.WouldBlock` should the timeout be
443 /// exceeded.
444 pub fn setReadTimeout(self: Socket, milliseconds: u32) !void {
445 return self.setOption(ws2_32.SOL_SOCKET, ws2_32.SO_RCVTIMEO, mem.asBytes(&milliseconds));
446 }
447 };
448}
lib/std/zig/parse.zig+1-1
...@@ -639,7 +639,7 @@ const Parser = struct {...@@ -639,7 +639,7 @@ const Parser = struct {
639 };639 };
640 }640 }
641641
642 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? (Keyword_anytype / TypeExpr)642 /// FnProto <- KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? CallConv? EXCLAMATIONMARK? TypeExpr
643 fn parseFnProto(p: *Parser) !Node.Index {643 fn parseFnProto(p: *Parser) !Node.Index {
644 const fn_token = p.eatToken(.keyword_fn) orelse return null_node;644 const fn_token = p.eatToken(.keyword_fn) orelse return null_node;
645645
lib/std/zig/system.zig+80-28
...@@ -209,11 +209,6 @@ pub const NativeTargetInfo = struct {...@@ -209,11 +209,6 @@ pub const NativeTargetInfo = struct {
209209
210 dynamic_linker: DynamicLinker = DynamicLinker{},210 dynamic_linker: DynamicLinker = DynamicLinker{},
211211
212 /// Only some architectures have CPU detection implemented. This field reveals whether
213 /// CPU detection actually occurred. When this is `true` it means that the reported
214 /// CPU is baseline only because of a missing implementation for that architecture.
215 cpu_detection_unimplemented: bool = false,
216
217 pub const DynamicLinker = Target.DynamicLinker;212 pub const DynamicLinker = Target.DynamicLinker;
218213
219 pub const DetectError = error{214 pub const DetectError = error{
...@@ -258,28 +253,86 @@ pub const NativeTargetInfo = struct {...@@ -258,28 +253,86 @@ pub const NativeTargetInfo = struct {
258 os.version_range.windows.max = detected_version;253 os.version_range.windows.max = detected_version;
259 },254 },
260 .macos => try macos.detect(&os),255 .macos => try macos.detect(&os),
261 .freebsd => {256 .freebsd, .netbsd, .dragonfly => {
262 var osreldate: u32 = undefined;257 const key = switch (Target.current.os.tag) {
263 var len: usize = undefined;258 .freebsd => "kern.osreldate",
259 .netbsd, .dragonfly => "kern.osrevision",
260 else => unreachable,
261 };
262 var value: u32 = undefined;
263 var len: usize = @sizeOf(@TypeOf(value));
264
265 std.os.sysctlbynameZ(key, &value, &len, null, 0) catch |err| switch (err) {
266 error.NameTooLong => unreachable, // constant, known good value
267 error.PermissionDenied => unreachable, // only when setting values,
268 error.SystemResources => unreachable, // memory already on the stack
269 error.UnknownName => unreachable, // constant, known good value
270 error.Unexpected => return error.OSVersionDetectionFail,
271 };
272
273 switch (Target.current.os.tag) {
274 .freebsd => {
275 // https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html
276 // Major * 100,000 has been convention since FreeBSD 2.2 (1997)
277 // Minor * 1(0),000 summed has been convention since FreeBSD 2.2 (1997)
278 // e.g. 492101 = 4.11-STABLE = 4.(9+2)
279 const major = value / 100_000;
280 const minor1 = value % 100_000 / 10_000; // usually 0 since 5.1
281 const minor2 = value % 10_000 / 1_000; // 0 before 5.1, minor version since
282 const patch = value % 1_000;
283 os.version_range.semver.min = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
284 os.version_range.semver.max = os.version_range.semver.min;
285 },
286 .netbsd => {
287 // #define __NetBSD_Version__ MMmmrrpp00
288 //
289 // M = major version
290 // m = minor version; a minor number of 99 indicates current.
291 // r = 0 (*)
292 // p = patchlevel
293 const major = value / 100_000_000;
294 const minor = value % 100_000_000 / 1_000_000;
295 const patch = value % 10_000 / 100;
296 os.version_range.semver.min = .{ .major = major, .minor = minor, .patch = patch };
297 os.version_range.semver.max = os.version_range.semver.min;
298 },
299 .dragonfly => {
300 // https://github.com/DragonFlyBSD/DragonFlyBSD/blob/cb2cde83771754aeef9bb3251ee48959138dec87/Makefile.inc1#L15-L17
301 // flat base10 format: Mmmmpp
302 // M = major
303 // m = minor; odd-numbers indicate current dev branch
304 // p = patch
305 const major = value / 100_000;
306 const minor = value % 100_000 / 100;
307 const patch = value % 100;
308 os.version_range.semver.min = .{ .major = major, .minor = minor, .patch = patch };
309 os.version_range.semver.max = os.version_range.semver.min;
310 },
311 else => unreachable,
312 }
313 },
314 .openbsd => {
315 const mib: [2]c_int = [_]c_int{
316 std.os.CTL_KERN,
317 std.os.KERN_OSRELEASE,
318 };
319 var buf: [64]u8 = undefined;
320 var len: usize = buf.len;
264321
265 std.os.sysctlbynameZ("kern.osreldate", &osreldate, &len, null, 0) catch |err| switch (err) {322 std.os.sysctl(&mib, &buf, &len, null, 0) catch |err| switch (err) {
266 error.NameTooLong => unreachable, // constant, known good value323 error.NameTooLong => unreachable, // constant, known good value
267 error.PermissionDenied => unreachable, // only when setting values,324 error.PermissionDenied => unreachable, // only when setting values,
268 error.SystemResources => unreachable, // memory already on the stack325 error.SystemResources => unreachable, // memory already on the stack
269 error.UnknownName => unreachable, // constant, known good value326 error.UnknownName => unreachable, // constant, known good value
270 error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value327 error.Unexpected => return error.OSVersionDetectionFail,
271 };328 };
272329
273 // https://www.freebsd.org/doc/en_US.ISO8859-1/books/porters-handbook/versions.html330 if (std.builtin.Version.parse(buf[0 .. len - 1])) |ver| {
274 // Major * 100,000 has been convention since FreeBSD 2.2 (1997)331 os.version_range.semver.min = ver;
275 // Minor * 1(0),000 summed has been convention since FreeBSD 2.2 (1997)332 os.version_range.semver.max = ver;
276 // e.g. 492101 = 4.11-STABLE = 4.(9+2)333 } else |err| {
277 const major = osreldate / 100_000;334 return error.OSVersionDetectionFail;
278 const minor1 = osreldate % 100_000 / 10_000; // usually 0 since 5.1335 }
279 const minor2 = osreldate % 10_000 / 1_000; // 0 before 5.1, minor version since
280 const patch = osreldate % 1_000;
281 os.version_range.semver.min = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
282 os.version_range.semver.max = .{ .major = major, .minor = minor1 + minor2, .patch = patch };
283 },336 },
284 else => {337 else => {
285 // Unimplemented, fall back to default version range.338 // Unimplemented, fall back to default version range.
...@@ -310,8 +363,6 @@ pub const NativeTargetInfo = struct {...@@ -310,8 +363,6 @@ pub const NativeTargetInfo = struct {
310 os.version_range.linux.glibc = glibc;363 os.version_range.linux.glibc = glibc;
311 }364 }
312365
313 var cpu_detection_unimplemented = false;
314
315 // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the366 // Until https://github.com/ziglang/zig/issues/4592 is implemented (support detecting the
316 // native CPU architecture as being different than the current target), we use this:367 // native CPU architecture as being different than the current target), we use this:
317 const cpu_arch = cross_target.getCpuArch();368 const cpu_arch = cross_target.getCpuArch();
...@@ -325,7 +376,6 @@ pub const NativeTargetInfo = struct {...@@ -325,7 +376,6 @@ pub const NativeTargetInfo = struct {
325 Target.Cpu.baseline(cpu_arch),376 Target.Cpu.baseline(cpu_arch),
326 .explicit => |model| model.toCpu(cpu_arch),377 .explicit => |model| model.toCpu(cpu_arch),
327 } orelse backup_cpu_detection: {378 } orelse backup_cpu_detection: {
328 cpu_detection_unimplemented = true;
329 break :backup_cpu_detection Target.Cpu.baseline(cpu_arch);379 break :backup_cpu_detection Target.Cpu.baseline(cpu_arch);
330 };380 };
331 var result = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);381 var result = try detectAbiAndDynamicLinker(allocator, cpu, os, cross_target);
...@@ -362,7 +412,6 @@ pub const NativeTargetInfo = struct {...@@ -362,7 +412,6 @@ pub const NativeTargetInfo = struct {
362 else => {},412 else => {},
363 }413 }
364 cross_target.updateCpuFeatures(&result.target.cpu.features);414 cross_target.updateCpuFeatures(&result.target.cpu.features);
365 result.cpu_detection_unimplemented = cpu_detection_unimplemented;
366 return result;415 return result;
367 }416 }
368417
...@@ -925,12 +974,15 @@ pub const NativeTargetInfo = struct {...@@ -925,12 +974,15 @@ pub const NativeTargetInfo = struct {
925 else => {},974 else => {},
926 }975 }
927976
977 switch (std.Target.current.os.tag) {
978 .linux => return linux.detectNativeCpuAndFeatures(),
979 .macos => return macos.detectNativeCpuAndFeatures(),
980 else => {},
981 }
982
928 // This architecture does not have CPU model & feature detection yet.983 // This architecture does not have CPU model & feature detection yet.
929 // See https://github.com/ziglang/zig/issues/4591984 // See https://github.com/ziglang/zig/issues/4591
930 if (std.Target.current.os.tag != .linux)985 return null;
931 return null;
932
933 return linux.detectNativeCpuAndFeatures();
934 }986 }
935};987};
936988
lib/std/zig/system/macos.zig+46-5
...@@ -7,10 +7,13 @@ const std = @import("std");...@@ -7,10 +7,13 @@ const std = @import("std");
7const assert = std.debug.assert;7const assert = std.debug.assert;
8const mem = std.mem;8const mem = std.mem;
9const testing = std.testing;9const testing = std.testing;
10const os = std.os;
11
12const Target = std.Target;
1013
11/// Detect macOS version.14/// Detect macOS version.
12/// `os` is not modified in case of error.15/// `target_os` is not modified in case of error.
13pub fn detect(os: *std.Target.Os) !void {16pub fn detect(target_os: *Target.Os) !void {
14 // Drop use of osproductversion sysctl because:17 // Drop use of osproductversion sysctl because:
15 // 1. only available 10.13.4 High Sierra and later18 // 1. only available 10.13.4 High Sierra and later
16 // 2. when used from a binary built against < SDK 11.0 it returns 10.16 and masks Big Sur 11.x version19 // 2. when used from a binary built against < SDK 11.0 it returns 10.16 and masks Big Sur 11.x version
...@@ -60,8 +63,8 @@ pub fn detect(os: *std.Target.Os) !void {...@@ -60,8 +63,8 @@ pub fn detect(os: *std.Target.Os) !void {
60 if (parseSystemVersion(bytes)) |ver| {63 if (parseSystemVersion(bytes)) |ver| {
61 // never return non-canonical `10.(16+)`64 // never return non-canonical `10.(16+)`
62 if (!(ver.major == 10 and ver.minor >= 16)) {65 if (!(ver.major == 10 and ver.minor >= 16)) {
63 os.version_range.semver.min = ver;66 target_os.version_range.semver.min = ver;
64 os.version_range.semver.max = ver;67 target_os.version_range.semver.max = ver;
65 return;68 return;
66 }69 }
67 continue;70 continue;
...@@ -410,7 +413,7 @@ fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version)...@@ -410,7 +413,7 @@ fn testVersionEquality(expected: std.builtin.Version, got: std.builtin.Version)
410/// `-syslibroot` param of the linker.413/// `-syslibroot` param of the linker.
411/// The caller needs to free the resulting path slice.414/// The caller needs to free the resulting path slice.
412pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {415pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {
413 assert(std.Target.current.isDarwin());416 assert(Target.current.isDarwin());
414 const argv = &[_][]const u8{ "xcrun", "--show-sdk-path" };417 const argv = &[_][]const u8{ "xcrun", "--show-sdk-path" };
415 const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });418 const result = try std.ChildProcess.exec(.{ .allocator = allocator, .argv = argv });
416 defer {419 defer {
...@@ -426,3 +429,41 @@ pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {...@@ -426,3 +429,41 @@ pub fn getSDKPath(allocator: *mem.Allocator) ![]u8 {
426 const syslibroot = mem.trimRight(u8, result.stdout, "\r\n");429 const syslibroot = mem.trimRight(u8, result.stdout, "\r\n");
427 return mem.dupe(allocator, u8, syslibroot);430 return mem.dupe(allocator, u8, syslibroot);
428}431}
432
433pub fn detectNativeCpuAndFeatures() ?Target.Cpu {
434 var cpu_family: os.CPUFAMILY = undefined;
435 var len: usize = @sizeOf(os.CPUFAMILY);
436 os.sysctlbynameZ("hw.cpufamily", &cpu_family, &len, null, 0) catch |err| switch (err) {
437 error.NameTooLong => unreachable, // constant, known good value
438 error.PermissionDenied => unreachable, // only when setting values,
439 error.SystemResources => unreachable, // memory already on the stack
440 error.UnknownName => unreachable, // constant, known good value
441 error.Unexpected => unreachable, // EFAULT: stack should be safe, EISDIR/ENOTDIR: constant, known good value
442 };
443
444 const current_arch = Target.current.cpu.arch;
445 switch (current_arch) {
446 .aarch64, .aarch64_be, .aarch64_32 => {
447 const model = switch (cpu_family) {
448 .ARM_FIRESTORM_ICESTORM => &Target.aarch64.cpu.apple_a14,
449 .ARM_LIGHTNING_THUNDER => &Target.aarch64.cpu.apple_a13,
450 .ARM_VORTEX_TEMPEST => &Target.aarch64.cpu.apple_a12,
451 .ARM_MONSOON_MISTRAL => &Target.aarch64.cpu.apple_a11,
452 .ARM_HURRICANE => &Target.aarch64.cpu.apple_a10,
453 .ARM_TWISTER => &Target.aarch64.cpu.apple_a9,
454 .ARM_TYPHOON => &Target.aarch64.cpu.apple_a8,
455 .ARM_CYCLONE => &Target.aarch64.cpu.cyclone,
456 else => return null,
457 };
458
459 return Target.Cpu{
460 .arch = current_arch,
461 .model = model,
462 .features = model.features,
463 };
464 },
465 else => {},
466 }
467
468 return null;
469}
src/Cache.zig+20-1
...@@ -11,6 +11,7 @@ const testing = std.testing;...@@ -11,6 +11,7 @@ const testing = std.testing;
11const mem = std.mem;11const mem = std.mem;
12const fmt = std.fmt;12const fmt = std.fmt;
13const Allocator = std.mem.Allocator;13const Allocator = std.mem.Allocator;
14const Compilation = @import("Compilation.zig");
1415
15/// Be sure to call `Manifest.deinit` after successful initialization.16/// Be sure to call `Manifest.deinit` after successful initialization.
16pub fn obtain(cache: *const Cache) Manifest {17pub fn obtain(cache: *const Cache) Manifest {
...@@ -61,7 +62,7 @@ pub const File = struct {...@@ -61,7 +62,7 @@ pub const File = struct {
61pub const HashHelper = struct {62pub const HashHelper = struct {
62 hasher: Hasher = hasher_init,63 hasher: Hasher = hasher_init,
6364
64 const EmitLoc = @import("Compilation.zig").EmitLoc;65 const EmitLoc = Compilation.EmitLoc;
6566
66 /// Record a slice of bytes as an dependency of the process being cached67 /// Record a slice of bytes as an dependency of the process being cached
67 pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {68 pub fn addBytes(hh: *HashHelper, bytes: []const u8) void {
...@@ -220,6 +221,24 @@ pub const Manifest = struct {...@@ -220,6 +221,24 @@ pub const Manifest = struct {
220 return idx;221 return idx;
221 }222 }
222223
224 pub fn hashCSource(self: *Manifest, c_source: Compilation.CSourceFile) !void {
225 _ = try self.addFile(c_source.src_path, null);
226 // Hash the extra flags, with special care to call addFile for file parameters.
227 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
228 const file_args = [_][]const u8{"-include"};
229 var arg_i: usize = 0;
230 while (arg_i < c_source.extra_flags.len) : (arg_i += 1) {
231 const arg = c_source.extra_flags[arg_i];
232 self.hash.addBytes(arg);
233 for (file_args) |file_arg| {
234 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_source.extra_flags.len) {
235 arg_i += 1;
236 _ = try self.addFile(c_source.extra_flags[arg_i], null);
237 }
238 }
239 }
240 }
241
223 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {242 pub fn addOptionalFile(self: *Manifest, optional_file_path: ?[]const u8) !void {
224 self.hash.add(optional_file_path != null);243 self.hash.add(optional_file_path != null);
225 const file_path = optional_file_path orelse return;244 const file_path = optional_file_path orelse return;
src/Compilation.zig+24-26
...@@ -942,7 +942,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {...@@ -942,7 +942,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
942 arena,942 arena,
943 options.zig_lib_directory.path.?,943 options.zig_lib_directory.path.?,
944 options.target,944 options.target,
945 options.is_native_os,945 options.is_native_abi,
946 link_libc,946 link_libc,
947 options.libc_installation,947 options.libc_installation,
948 );948 );
...@@ -2514,23 +2514,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P...@@ -2514,23 +2514,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject, c_obj_prog_node: *std.P
25142514
2515 man.hash.add(comp.clang_preprocessor_mode);2515 man.hash.add(comp.clang_preprocessor_mode);
25162516
2517 _ = try man.addFile(c_object.src.src_path, null);2517 try man.hashCSource(c_object.src);
2518 {
2519 // Hash the extra flags, with special care to call addFile for file parameters.
2520 // TODO this logic can likely be improved by utilizing clang_options_data.zig.
2521 const file_args = [_][]const u8{"-include"};
2522 var arg_i: usize = 0;
2523 while (arg_i < c_object.src.extra_flags.len) : (arg_i += 1) {
2524 const arg = c_object.src.extra_flags[arg_i];
2525 man.hash.addBytes(arg);
2526 for (file_args) |file_arg| {
2527 if (mem.eql(u8, file_arg, arg) and arg_i + 1 < c_object.src.extra_flags.len) {
2528 arg_i += 1;
2529 _ = try man.addFile(c_object.src.extra_flags[arg_i], null);
2530 }
2531 }
2532 }
2533 }
25342518
2535 {2519 {
2536 const is_collision = blk: {2520 const is_collision = blk: {
...@@ -2862,6 +2846,10 @@ pub fn addCCArgs(...@@ -2862,6 +2846,10 @@ pub fn addCCArgs(
2862 }2846 }
2863 }2847 }
28642848
2849 if (target.cpu.arch.isThumb()) {
2850 try argv.append("-mthumb");
2851 }
2852
2865 if (comp.haveFramePointer()) {2853 if (comp.haveFramePointer()) {
2866 try argv.append("-fno-omit-frame-pointer");2854 try argv.append("-fno-omit-frame-pointer");
2867 } else {2855 } else {
...@@ -3135,7 +3123,7 @@ fn detectLibCIncludeDirs(...@@ -3135,7 +3123,7 @@ fn detectLibCIncludeDirs(
3135 arena: *Allocator,3123 arena: *Allocator,
3136 zig_lib_dir: []const u8,3124 zig_lib_dir: []const u8,
3137 target: Target,3125 target: Target,
3138 is_native_os: bool,3126 is_native_abi: bool,
3139 link_libc: bool,3127 link_libc: bool,
3140 libc_installation: ?*const LibCInstallation,3128 libc_installation: ?*const LibCInstallation,
3141) !LibCDirs {3129) !LibCDirs {
...@@ -3150,10 +3138,26 @@ fn detectLibCIncludeDirs(...@@ -3150,10 +3138,26 @@ fn detectLibCIncludeDirs(
3150 return detectLibCFromLibCInstallation(arena, target, lci);3138 return detectLibCFromLibCInstallation(arena, target, lci);
3151 }3139 }
31523140
3141 if (is_native_abi) {
3142 const libc = try arena.create(LibCInstallation);
3143 libc.* = try LibCInstallation.findNative(.{ .allocator = arena });
3144 return detectLibCFromLibCInstallation(arena, target, libc);
3145 }
3146
3153 if (target_util.canBuildLibC(target)) {3147 if (target_util.canBuildLibC(target)) {
3154 const generic_name = target_util.libCGenericName(target);3148 const generic_name = target_util.libCGenericName(target);
3155 // Some architectures are handled by the same set of headers.3149 // Some architectures are handled by the same set of headers.
3156 const arch_name = if (target.abi.isMusl()) target_util.archMuslName(target.cpu.arch) else @tagName(target.cpu.arch);3150 const arch_name = if (target.abi.isMusl())
3151 target_util.archMuslName(target.cpu.arch)
3152 else if (target.cpu.arch.isThumb())
3153 // ARM headers are valid for Thumb too.
3154 switch (target.cpu.arch) {
3155 .thumb => "arm",
3156 .thumbeb => "armeb",
3157 else => unreachable,
3158 }
3159 else
3160 @tagName(target.cpu.arch);
3157 const os_name = @tagName(target.os.tag);3161 const os_name = @tagName(target.os.tag);
3158 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.3162 // Musl's headers are ABI-agnostic and so they all have the "musl" ABI name.
3159 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);3163 const abi_name = if (target.abi.isMusl()) "musl" else @tagName(target.abi);
...@@ -3190,12 +3194,6 @@ fn detectLibCIncludeDirs(...@@ -3190,12 +3194,6 @@ fn detectLibCIncludeDirs(
3190 };3194 };
3191 }3195 }
31923196
3193 if (is_native_os) {
3194 const libc = try arena.create(LibCInstallation);
3195 libc.* = try LibCInstallation.findNative(.{ .allocator = arena });
3196 return detectLibCFromLibCInstallation(arena, target, libc);
3197 }
3198
3199 return LibCDirs{3197 return LibCDirs{
3200 .libc_include_dir_list = &[0][]u8{},3198 .libc_include_dir_list = &[0][]u8{},
3201 .libc_installation = null,3199 .libc_installation = null,
src/Module.zig+60
...@@ -4151,6 +4151,33 @@ pub fn intDiv(allocator: *Allocator, lhs: Value, rhs: Value) !Value {...@@ -4151,6 +4151,33 @@ pub fn intDiv(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
4151 }4151 }
4152}4152}
41534153
4154pub fn intMul(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
4155 // TODO is this a performance issue? maybe we should try the operation without
4156 // resorting to BigInt first.
4157 var lhs_space: Value.BigIntSpace = undefined;
4158 var rhs_space: Value.BigIntSpace = undefined;
4159 const lhs_bigint = lhs.toBigInt(&lhs_space);
4160 const rhs_bigint = rhs.toBigInt(&rhs_space);
4161 const limbs = try allocator.alloc(
4162 std.math.big.Limb,
4163 lhs_bigint.limbs.len + rhs_bigint.limbs.len + 1,
4164 );
4165 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
4166 var limbs_buffer = try allocator.alloc(
4167 std.math.big.Limb,
4168 std.math.big.int.calcMulLimbsBufferLen(lhs_bigint.limbs.len, rhs_bigint.limbs.len, 1),
4169 );
4170 defer allocator.free(limbs_buffer);
4171 result_bigint.mul(lhs_bigint, rhs_bigint, limbs_buffer, allocator);
4172 const result_limbs = result_bigint.limbs[0..result_bigint.len];
4173
4174 if (result_bigint.positive) {
4175 return Value.Tag.int_big_positive.create(allocator, result_limbs);
4176 } else {
4177 return Value.Tag.int_big_negative.create(allocator, result_limbs);
4178 }
4179}
4180
4154pub fn floatAdd(4181pub fn floatAdd(
4155 arena: *Allocator,4182 arena: *Allocator,
4156 float_type: Type,4183 float_type: Type,
...@@ -4250,6 +4277,39 @@ pub fn floatDiv(...@@ -4250,6 +4277,39 @@ pub fn floatDiv(
4250 }4277 }
4251}4278}
42524279
4280pub fn floatMul(
4281 arena: *Allocator,
4282 float_type: Type,
4283 src: LazySrcLoc,
4284 lhs: Value,
4285 rhs: Value,
4286) !Value {
4287 switch (float_type.tag()) {
4288 .f16 => {
4289 @panic("TODO add __trunctfhf2 to compiler-rt");
4290 //const lhs_val = lhs.toFloat(f16);
4291 //const rhs_val = rhs.toFloat(f16);
4292 //return Value.Tag.float_16.create(arena, lhs_val * rhs_val);
4293 },
4294 .f32 => {
4295 const lhs_val = lhs.toFloat(f32);
4296 const rhs_val = rhs.toFloat(f32);
4297 return Value.Tag.float_32.create(arena, lhs_val * rhs_val);
4298 },
4299 .f64 => {
4300 const lhs_val = lhs.toFloat(f64);
4301 const rhs_val = rhs.toFloat(f64);
4302 return Value.Tag.float_64.create(arena, lhs_val * rhs_val);
4303 },
4304 .f128, .comptime_float, .c_longdouble => {
4305 const lhs_val = lhs.toFloat(f128);
4306 const rhs_val = rhs.toFloat(f128);
4307 return Value.Tag.float_128.create(arena, lhs_val * rhs_val);
4308 },
4309 else => unreachable,
4310 }
4311}
4312
4253pub fn simplePtrType(4313pub fn simplePtrType(
4254 mod: *Module,4314 mod: *Module,
4255 arena: *Allocator,4315 arena: *Allocator,
src/Sema.zig+16-4
...@@ -4606,10 +4606,15 @@ fn analyzeArithmetic(...@@ -4606,10 +4606,15 @@ fn analyzeArithmetic(
4606 // incase rhs is 0, simply return lhs without doing any calculations4606 // incase rhs is 0, simply return lhs without doing any calculations
4607 // TODO Once division is implemented we should throw an error when dividing by 0.4607 // TODO Once division is implemented we should throw an error when dividing by 0.
4608 if (rhs_val.compareWithZero(.eq)) {4608 if (rhs_val.compareWithZero(.eq)) {
4609 return sema.mod.constInst(sema.arena, src, .{4609 switch (zir_tag) {
4610 .ty = scalar_type,4610 .add, .addwrap, .sub, .subwrap => {
4611 .val = lhs_val,4611 return sema.mod.constInst(sema.arena, src, .{
4612 });4612 .ty = scalar_type,
4613 .val = lhs_val,
4614 });
4615 },
4616 else => {},
4617 }
4613 }4618 }
46144619
4615 const value = switch (zir_tag) {4620 const value = switch (zir_tag) {
...@@ -4634,6 +4639,13 @@ fn analyzeArithmetic(...@@ -4634,6 +4639,13 @@ fn analyzeArithmetic(
4634 try Module.floatDiv(sema.arena, scalar_type, src, lhs_val, rhs_val);4639 try Module.floatDiv(sema.arena, scalar_type, src, lhs_val, rhs_val);
4635 break :blk val;4640 break :blk val;
4636 },4641 },
4642 .mul => blk: {
4643 const val = if (is_int)
4644 try Module.intMul(sema.arena, lhs_val, rhs_val)
4645 else
4646 try Module.floatMul(sema.arena, scalar_type, src, lhs_val, rhs_val);
4647 break :blk val;
4648 },
4637 else => return sema.mod.fail(&block.base, src, "TODO Implement arithmetic operand '{s}'", .{@tagName(zir_tag)}),4649 else => return sema.mod.fail(&block.base, src, "TODO Implement arithmetic operand '{s}'", .{@tagName(zir_tag)}),
4638 };4650 };
46394651
src/codegen.zig+674-239
...@@ -20,6 +20,8 @@ const build_options = @import("build_options");...@@ -20,6 +20,8 @@ const build_options = @import("build_options");
20const LazySrcLoc = Module.LazySrcLoc;20const LazySrcLoc = Module.LazySrcLoc;
21const RegisterManager = @import("register_manager.zig").RegisterManager;21const RegisterManager = @import("register_manager.zig").RegisterManager;
2222
23const X8664Encoder = @import("codegen/x86_64.zig").Encoder;
24
23/// The codegen-related data that is stored in `ir.Inst.Block` instructions.25/// The codegen-related data that is stored in `ir.Inst.Block` instructions.
24pub const BlockData = struct {26pub const BlockData = struct {
25 relocs: std.ArrayListUnmanaged(Reloc) = undefined,27 relocs: std.ArrayListUnmanaged(Reloc) = undefined,
...@@ -905,7 +907,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -905,7 +907,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
905 // TODO separate architectures with registers from907 // TODO separate architectures with registers from
906 // stack-based architectures (spu_2)908 // stack-based architectures (spu_2)
907 if (callee_preserved_regs.len > 0) {909 if (callee_preserved_regs.len > 0) {
908 if (self.register_manager.tryAllocReg(inst)) |reg| {910 if (self.register_manager.tryAllocReg(inst, &.{})) |reg| {
909 return MCValue{ .register = registerAlias(reg, abi_size) };911 return MCValue{ .register = registerAlias(reg, abi_size) };
910 }912 }
911 }913 }
...@@ -917,6 +919,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -917,6 +919,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
917919
918 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: Register, inst: *ir.Inst) !void {920 pub fn spillInstruction(self: *Self, src: LazySrcLoc, reg: Register, inst: *ir.Inst) !void {
919 const stack_mcv = try self.allocRegOrMem(inst, false);921 const stack_mcv = try self.allocRegOrMem(inst, false);
922 log.debug("spilling {*} to stack mcv {any}", .{ inst, stack_mcv });
920 const reg_mcv = self.getResolvedInstValue(inst);923 const reg_mcv = self.getResolvedInstValue(inst);
921 assert(reg == toCanonicalReg(reg_mcv.register));924 assert(reg == toCanonicalReg(reg_mcv.register));
922 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];925 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
...@@ -928,7 +931,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -928,7 +931,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
928 /// allocated. A second call to `copyToTmpRegister` may return the same register.931 /// allocated. A second call to `copyToTmpRegister` may return the same register.
929 /// This can have a side effect of spilling instructions to the stack to free up a register.932 /// This can have a side effect of spilling instructions to the stack to free up a register.
930 fn copyToTmpRegister(self: *Self, src: LazySrcLoc, ty: Type, mcv: MCValue) !Register {933 fn copyToTmpRegister(self: *Self, src: LazySrcLoc, ty: Type, mcv: MCValue) !Register {
931 const reg = try self.register_manager.allocRegWithoutTracking();934 const reg = try self.register_manager.allocRegWithoutTracking(&.{});
932 try self.genSetReg(src, ty, reg, mcv);935 try self.genSetReg(src, ty, reg, mcv);
933 return reg;936 return reg;
934 }937 }
...@@ -937,7 +940,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -937,7 +940,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
937 /// `reg_owner` is the instruction that gets associated with the register in the register table.940 /// `reg_owner` is the instruction that gets associated with the register in the register table.
938 /// This can have a side effect of spilling instructions to the stack to free up a register.941 /// This can have a side effect of spilling instructions to the stack to free up a register.
939 fn copyToNewRegister(self: *Self, reg_owner: *ir.Inst, mcv: MCValue) !MCValue {942 fn copyToNewRegister(self: *Self, reg_owner: *ir.Inst, mcv: MCValue) !MCValue {
940 const reg = try self.register_manager.allocReg(reg_owner);943 const reg = try self.register_manager.allocReg(reg_owner, &.{});
941 try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv);944 try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv);
942 return MCValue{ .register = reg };945 return MCValue{ .register = reg };
943 }946 }
...@@ -1017,7 +1020,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1017,7 +1020,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1017 },1020 },
1018 .val = Value.initTag(.bool_true),1021 .val = Value.initTag(.bool_true),
1019 };1022 };
1020 return try self.genX8664BinMath(&inst.base, inst.operand, &imm.base, 6, 0x30);1023 return try self.genX8664BinMath(&inst.base, inst.operand, &imm.base);
1021 },1024 },
1022 .arm, .armeb => {1025 .arm, .armeb => {
1023 var imm = ir.Inst.Constant{1026 var imm = ir.Inst.Constant{
...@@ -1041,7 +1044,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1041,7 +1044,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1041 return MCValue.dead;1044 return MCValue.dead;
1042 switch (arch) {1045 switch (arch) {
1043 .x86_64 => {1046 .x86_64 => {
1044 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 0, 0x00);1047 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs);
1045 },1048 },
1046 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .add),1049 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .add),
1047 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),1050 else => return self.fail(inst.base.src, "TODO implement add for {}", .{self.target.cpu.arch}),
...@@ -1062,6 +1065,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1062,6 +1065,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1062 if (inst.base.isUnused())1065 if (inst.base.isUnused())
1063 return MCValue.dead;1066 return MCValue.dead;
1064 switch (arch) {1067 switch (arch) {
1068 .x86_64 => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
1065 .arm, .armeb => return try self.genArmMul(&inst.base, inst.lhs, inst.rhs),1069 .arm, .armeb => return try self.genArmMul(&inst.base, inst.lhs, inst.rhs),
1066 else => return self.fail(inst.base.src, "TODO implement mul for {}", .{self.target.cpu.arch}),1070 else => return self.fail(inst.base.src, "TODO implement mul for {}", .{self.target.cpu.arch}),
1067 }1071 }
...@@ -1340,7 +1344,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1340,7 +1344,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1340 return MCValue.dead;1344 return MCValue.dead;
1341 switch (arch) {1345 switch (arch) {
1342 .x86_64 => {1346 .x86_64 => {
1343 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 5, 0x28);1347 return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs);
1344 },1348 },
1345 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .sub),1349 .arm, .armeb => return try self.genArmBinOp(&inst.base, inst.lhs, inst.rhs, .sub),
1346 else => return self.fail(inst.base.src, "TODO implement sub for {}", .{self.target.cpu.arch}),1350 else => return self.fail(inst.base.src, "TODO implement sub for {}", .{self.target.cpu.arch}),
...@@ -1356,36 +1360,124 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1356,36 +1360,124 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1356 }1360 }
1357 }1361 }
13581362
1363 fn armOperandShouldBeRegister(self: *Self, src: LazySrcLoc, mcv: MCValue) !bool {
1364 return switch (mcv) {
1365 .none => unreachable,
1366 .undef => unreachable,
1367 .dead, .unreach => unreachable,
1368 .compare_flags_unsigned => unreachable,
1369 .compare_flags_signed => unreachable,
1370 .ptr_stack_offset => unreachable,
1371 .ptr_embedded_in_code => unreachable,
1372 .immediate => |imm| blk: {
1373 if (imm > std.math.maxInt(u32)) return self.fail(src, "TODO ARM binary arithmetic immediate larger than u32", .{});
1374
1375 // Load immediate into register if it doesn't fit
1376 // in an operand
1377 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) == null;
1378 },
1379 .register => true,
1380 .stack_offset,
1381 .embedded_in_code,
1382 .memory,
1383 => true,
1384 };
1385 }
1386
1359 fn genArmBinOp(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, op: ir.Inst.Tag) !MCValue {1387 fn genArmBinOp(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, op: ir.Inst.Tag) !MCValue {
1360 const lhs = try self.resolveInst(op_lhs);1388 const lhs = try self.resolveInst(op_lhs);
1361 const rhs = try self.resolveInst(op_rhs);1389 const rhs = try self.resolveInst(op_rhs);
13621390
1391 const lhs_is_register = lhs == .register;
1392 const rhs_is_register = rhs == .register;
1393 const lhs_should_be_register = try self.armOperandShouldBeRegister(op_lhs.src, lhs);
1394 const rhs_should_be_register = try self.armOperandShouldBeRegister(op_rhs.src, rhs);
1395 const reuse_lhs = lhs_is_register and self.reuseOperand(inst, 0, lhs);
1396 const reuse_rhs = !reuse_lhs and rhs_is_register and self.reuseOperand(inst, 1, rhs);
1397
1363 // Destination must be a register1398 // Destination must be a register
1364 var dst_mcv: MCValue = undefined;1399 var dst_mcv: MCValue = undefined;
1365 var lhs_mcv: MCValue = undefined;1400 var lhs_mcv = lhs;
1366 var rhs_mcv: MCValue = undefined;1401 var rhs_mcv = rhs;
1367 if (self.reuseOperand(inst, 0, lhs)) {1402 var swap_lhs_and_rhs = false;
1368 // LHS is the destination1403
1369 // RHS is the source1404 // Allocate registers for operands and/or destination
1370 lhs_mcv = if (lhs != .register) try self.copyToNewRegister(inst, lhs) else lhs;1405 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
1371 rhs_mcv = rhs;1406 if (reuse_lhs) {
1372 dst_mcv = lhs_mcv;1407 // Allocate 0 or 1 registers
1373 } else if (self.reuseOperand(inst, 1, rhs)) {1408 if (!rhs_is_register and rhs_should_be_register) {
1374 // RHS is the destination1409 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(op_rhs, &.{lhs.register}) };
1375 // LHS is the source1410 branch.inst_table.putAssumeCapacity(op_rhs, rhs_mcv);
1376 lhs_mcv = lhs;1411 }
1377 rhs_mcv = if (rhs != .register) try self.copyToNewRegister(inst, rhs) else rhs;1412 dst_mcv = lhs;
1378 dst_mcv = rhs_mcv;1413 } else if (reuse_rhs) {
1414 // Allocate 0 or 1 registers
1415 if (!lhs_is_register and lhs_should_be_register) {
1416 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(op_lhs, &.{rhs.register}) };
1417 branch.inst_table.putAssumeCapacity(op_lhs, lhs_mcv);
1418 }
1419 dst_mcv = rhs;
1420
1421 swap_lhs_and_rhs = true;
1379 } else {1422 } else {
1380 // TODO save 1 copy instruction by directly allocating the destination register1423 // Allocate 1 or 2 registers
1381 // LHS is the destination1424 if (lhs_should_be_register and rhs_should_be_register) {
1382 // RHS is the source1425 if (lhs_is_register and rhs_is_register) {
1383 lhs_mcv = try self.copyToNewRegister(inst, lhs);1426 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{ lhs.register, rhs.register }) };
1384 rhs_mcv = rhs;1427 } else if (lhs_is_register) {
1385 dst_mcv = lhs_mcv;1428 // Move RHS to register
1429 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) };
1430 rhs_mcv = dst_mcv;
1431 } else if (rhs_is_register) {
1432 // Move LHS to register
1433 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };
1434 lhs_mcv = dst_mcv;
1435 } else {
1436 // Move LHS and RHS to register
1437 const regs = try self.register_manager.allocRegs(2, .{ inst, op_rhs }, &.{});
1438 lhs_mcv = MCValue{ .register = regs[0] };
1439 rhs_mcv = MCValue{ .register = regs[1] };
1440 dst_mcv = lhs_mcv;
1441
1442 branch.inst_table.putAssumeCapacity(op_rhs, rhs_mcv);
1443 }
1444 } else if (lhs_should_be_register) {
1445 // RHS is immediate
1446 if (lhs_is_register) {
1447 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{lhs.register}) };
1448 } else {
1449 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1450 lhs_mcv = dst_mcv;
1451 }
1452 } else if (rhs_should_be_register) {
1453 // LHS is immediate
1454 if (rhs_is_register) {
1455 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{rhs.register}) };
1456 } else {
1457 dst_mcv = MCValue{ .register = try self.register_manager.allocReg(inst, &.{}) };
1458 rhs_mcv = dst_mcv;
1459 }
1460
1461 swap_lhs_and_rhs = true;
1462 } else unreachable; // binary operation on two immediates
1463 }
1464
1465 // Move the operands to the newly allocated registers
1466 if (lhs_mcv == .register and !lhs_is_register) {
1467 try self.genSetReg(op_lhs.src, op_lhs.ty, lhs_mcv.register, lhs);
1468 }
1469 if (rhs_mcv == .register and !rhs_is_register) {
1470 try self.genSetReg(op_rhs.src, op_rhs.ty, rhs_mcv.register, rhs);
1386 }1471 }
13871472
1388 try self.genArmBinOpCode(inst.src, dst_mcv.register, lhs_mcv, rhs_mcv, op);1473 try self.genArmBinOpCode(
1474 inst.src,
1475 dst_mcv.register,
1476 lhs_mcv,
1477 rhs_mcv,
1478 swap_lhs_and_rhs,
1479 op,
1480 );
1389 return dst_mcv;1481 return dst_mcv;
1390 }1482 }
13911483
...@@ -1395,11 +1487,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1395,11 +1487,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1395 dst_reg: Register,1487 dst_reg: Register,
1396 lhs_mcv: MCValue,1488 lhs_mcv: MCValue,
1397 rhs_mcv: MCValue,1489 rhs_mcv: MCValue,
1490 swap_lhs_and_rhs: bool,
1398 op: ir.Inst.Tag,1491 op: ir.Inst.Tag,
1399 ) !void {1492 ) !void {
1400 assert(lhs_mcv == .register or lhs_mcv == .register);1493 assert(lhs_mcv == .register or rhs_mcv == .register);
14011494
1402 const swap_lhs_and_rhs = rhs_mcv == .register and lhs_mcv != .register;
1403 const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register;1495 const op1 = if (swap_lhs_and_rhs) rhs_mcv.register else lhs_mcv.register;
1404 const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv;1496 const op2 = if (swap_lhs_and_rhs) lhs_mcv else rhs_mcv;
14051497
...@@ -1411,19 +1503,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1411,19 +1503,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1411 .compare_flags_signed => unreachable,1503 .compare_flags_signed => unreachable,
1412 .ptr_stack_offset => unreachable,1504 .ptr_stack_offset => unreachable,
1413 .ptr_embedded_in_code => unreachable,1505 .ptr_embedded_in_code => unreachable,
1414 .immediate => |imm| blk: {1506 .immediate => |imm| Instruction.Operand.fromU32(@intCast(u32, imm)).?,
1415 if (imm > std.math.maxInt(u32)) return self.fail(src, "TODO ARM binary arithmetic immediate larger than u32", .{});
1416
1417 // Load immediate into register if it doesn't fit
1418 // as an operand
1419 break :blk Instruction.Operand.fromU32(@intCast(u32, imm)) orelse
1420 Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none);
1421 },
1422 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),1507 .register => |reg| Instruction.Operand.reg(reg, Instruction.Operand.Shift.none),
1423 .stack_offset,1508 .stack_offset,
1424 .embedded_in_code,1509 .embedded_in_code,
1425 .memory,1510 .memory,
1426 => Instruction.Operand.reg(try self.copyToTmpRegister(src, Type.initTag(.u32), op2), Instruction.Operand.Shift.none),1511 => unreachable,
1427 };1512 };
14281513
1429 switch (op) {1514 switch (op) {
...@@ -1485,8 +1570,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1485,8 +1570,20 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1485 return dst_mcv;1570 return dst_mcv;
1486 }1571 }
14871572
1573 /// Perform "binary" operators, excluding comparisons.
1574 /// Currently, the following ops are supported:
1488 /// ADD, SUB, XOR, OR, AND1575 /// ADD, SUB, XOR, OR, AND
1489 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst, opx: u8, mr: u8) !MCValue {1576 fn genX8664BinMath(self: *Self, inst: *ir.Inst, op_lhs: *ir.Inst, op_rhs: *ir.Inst) !MCValue {
1577 // We'll handle these ops in two steps.
1578 // 1) Prepare an output location (register or memory)
1579 // This location will be the location of the operand that dies (if one exists)
1580 // or just a temporary register (if one doesn't exist)
1581 // 2) Perform the op with the other argument
1582 // 3) Sometimes, the output location is memory but the op doesn't support it.
1583 // In this case, copy that location to a register, then perform the op to that register instead.
1584 //
1585 // TODO: make this algorithm less bad
1586
1490 try self.code.ensureCapacity(self.code.items.len + 8);1587 try self.code.ensureCapacity(self.code.items.len + 8);
14911588
1492 const lhs = try self.resolveInst(op_lhs);1589 const lhs = try self.resolveInst(op_lhs);
...@@ -1547,18 +1644,109 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1547,18 +1644,109 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1547 else => {},1644 else => {},
1548 }1645 }
15491646
1550 try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, opx, mr);1647 // Now for step 2, we perform the actual op
1648 switch (inst.tag) {
1649 // TODO: Generate wrapping and non-wrapping versions separately
1650 .add, .addwrap => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 0, 0x00),
1651 .bool_or, .bit_or => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 1, 0x08),
1652 .bool_and, .bit_and => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 4, 0x20),
1653 .sub, .subwrap => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 5, 0x28),
1654 .xor, .not => try self.genX8664BinMathCode(inst.src, inst.ty, dst_mcv, src_mcv, 6, 0x30),
1655
1656 .mul, .mulwrap => try self.genX8664Imul(inst.src, inst.ty, dst_mcv, src_mcv),
1657 else => unreachable,
1658 }
15511659
1552 return dst_mcv;1660 return dst_mcv;
1553 }1661 }
15541662
1663 /// Wrap over Instruction.encodeInto to translate errors
1664 fn encodeX8664Instruction(
1665 self: *Self,
1666 src: LazySrcLoc,
1667 inst: Instruction,
1668 ) !void {
1669 inst.encodeInto(self.code) catch |err| {
1670 if (err == error.OutOfMemory)
1671 return error.OutOfMemory
1672 else
1673 return self.fail(src, "Instruction.encodeInto failed because {s}", .{@errorName(err)});
1674 };
1675 }
1676
1677 /// This function encodes a binary operation for x86_64
1678 /// intended for use with the following opcode ranges
1679 /// because they share the same structure.
1680 ///
1681 /// Thus not all binary operations can be used here
1682 /// -- multiplication needs to be done with imul,
1683 /// which doesn't have as convenient an interface.
1684 ///
1685 /// "opx"-style instructions use the opcode extension field to indicate which instruction to execute:
1686 ///
1687 /// opx = /0: add
1688 /// opx = /1: or
1689 /// opx = /2: adc
1690 /// opx = /3: sbb
1691 /// opx = /4: and
1692 /// opx = /5: sub
1693 /// opx = /6: xor
1694 /// opx = /7: cmp
1695 ///
1696 /// opcode | operand shape
1697 /// --------+----------------------
1698 /// 80 /opx | *r/m8*, imm8
1699 /// 81 /opx | *r/m16/32/64*, imm16/32
1700 /// 83 /opx | *r/m16/32/64*, imm8
1701 ///
1702 /// "mr"-style instructions use the low bits of opcode to indicate shape of instruction:
1703 ///
1704 /// mr = 00: add
1705 /// mr = 08: or
1706 /// mr = 10: adc
1707 /// mr = 18: sbb
1708 /// mr = 20: and
1709 /// mr = 28: sub
1710 /// mr = 30: xor
1711 /// mr = 38: cmp
1712 ///
1713 /// opcode | operand shape
1714 /// -------+-------------------------
1715 /// mr + 0 | *r/m8*, r8
1716 /// mr + 1 | *r/m16/32/64*, r16/32/64
1717 /// mr + 2 | *r8*, r/m8
1718 /// mr + 3 | *r16/32/64*, r/m16/32/64
1719 /// mr + 4 | *AL*, imm8
1720 /// mr + 5 | *rAX*, imm16/32
1721 ///
1722 /// TODO: rotates and shifts share the same structure, so we can potentially implement them
1723 /// at a later date with very similar code.
1724 /// They have "opx"-style instructions, but no "mr"-style instructions.
1725 ///
1726 /// opx = /0: rol,
1727 /// opx = /1: ror,
1728 /// opx = /2: rcl,
1729 /// opx = /3: rcr,
1730 /// opx = /4: shl sal,
1731 /// opx = /5: shr,
1732 /// opx = /6: sal shl,
1733 /// opx = /7: sar,
1734 ///
1735 /// opcode | operand shape
1736 /// --------+------------------
1737 /// c0 /opx | *r/m8*, imm8
1738 /// c1 /opx | *r/m16/32/64*, imm8
1739 /// d0 /opx | *r/m8*, 1
1740 /// d1 /opx | *r/m16/32/64*, 1
1741 /// d2 /opx | *r/m8*, CL (for context, CL is register 1)
1742 /// d3 /opx | *r/m16/32/64*, CL (for context, CL is register 1)
1555 fn genX8664BinMathCode(1743 fn genX8664BinMathCode(
1556 self: *Self,1744 self: *Self,
1557 src: LazySrcLoc,1745 src: LazySrcLoc,
1558 dst_ty: Type,1746 dst_ty: Type,
1559 dst_mcv: MCValue,1747 dst_mcv: MCValue,
1560 src_mcv: MCValue,1748 src_mcv: MCValue,
1561 opx: u8,1749 opx: u3,
1562 mr: u8,1750 mr: u8,
1563 ) !void {1751 ) !void {
1564 switch (dst_mcv) {1752 switch (dst_mcv) {
...@@ -1577,31 +1765,85 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1577,31 +1765,85 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1577 .ptr_stack_offset => unreachable,1765 .ptr_stack_offset => unreachable,
1578 .ptr_embedded_in_code => unreachable,1766 .ptr_embedded_in_code => unreachable,
1579 .register => |src_reg| {1767 .register => |src_reg| {
1580 self.rex(.{ .b = dst_reg.isExtended(), .r = src_reg.isExtended(), .w = dst_reg.size() == 64 });1768 // for register, register use mr + 1
1581 self.code.appendSliceAssumeCapacity(&[_]u8{ mr + 0x1, 0xC0 | (@as(u8, src_reg.id() & 0b111) << 3) | @as(u8, dst_reg.id() & 0b111) });1769 // addressing mode: *r/m16/32/64*, r16/32/64
1770 const abi_size = dst_ty.abiSize(self.target.*);
1771 const encoder = try X8664Encoder.init(self.code, 3);
1772 encoder.rex(.{
1773 .w = abi_size == 8,
1774 .r = src_reg.isExtended(),
1775 .b = dst_reg.isExtended(),
1776 });
1777 encoder.opcode_1byte(mr + 1);
1778 encoder.modRm_direct(
1779 src_reg.low_id(),
1780 dst_reg.low_id(),
1781 );
1582 },1782 },
1583 .immediate => |imm| {1783 .immediate => |imm| {
1584 const imm32 = @intCast(u31, imm); // This case must be handled before calling genX8664BinMathCode.1784 // register, immediate use opx = 81 or 83 addressing modes:
1585 // 81 /opx id1785 // opx = 81: r/m16/32/64, imm16/32
1586 if (imm32 <= math.maxInt(u7)) {1786 // opx = 83: r/m16/32/64, imm8
1587 self.rex(.{ .b = dst_reg.isExtended(), .w = dst_reg.size() == 64 });1787 const imm32 = @intCast(i32, imm); // This case must be handled before calling genX8664BinMathCode.
1588 self.code.appendSliceAssumeCapacity(&[_]u8{1788 if (imm32 <= math.maxInt(i8)) {
1589 0x83,1789 const abi_size = dst_ty.abiSize(self.target.*);
1590 0xC0 | (opx << 3) | @truncate(u3, dst_reg.id()),1790 const encoder = try X8664Encoder.init(self.code, 4);
1591 @intCast(u8, imm32),1791 encoder.rex(.{
1792 .w = abi_size == 8,
1793 .b = dst_reg.isExtended(),
1592 });1794 });
1795 encoder.opcode_1byte(0x83);
1796 encoder.modRm_direct(
1797 opx,
1798 dst_reg.low_id(),
1799 );
1800 encoder.imm8(@intCast(i8, imm32));
1593 } else {1801 } else {
1594 self.rex(.{ .r = dst_reg.isExtended(), .w = dst_reg.size() == 64 });1802 const abi_size = dst_ty.abiSize(self.target.*);
1595 self.code.appendSliceAssumeCapacity(&[_]u8{1803 const encoder = try X8664Encoder.init(self.code, 7);
1596 0x81,1804 encoder.rex(.{
1597 0xC0 | (opx << 3) | @truncate(u3, dst_reg.id()),1805 .w = abi_size == 8,
1806 .b = dst_reg.isExtended(),
1598 });1807 });
1599 std.mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), imm32);1808 encoder.opcode_1byte(0x81);
1809 encoder.modRm_direct(
1810 opx,
1811 dst_reg.low_id(),
1812 );
1813 encoder.imm32(@intCast(i32, imm32));
1600 }1814 }
1601 },1815 },
1602 .embedded_in_code, .memory, .stack_offset => {1816 .embedded_in_code, .memory => {
1603 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source memory", .{});1817 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source memory", .{});
1604 },1818 },
1819 .stack_offset => |off| {
1820 // register, indirect use mr + 3
1821 // addressing mode: *r16/32/64*, r/m16/32/64
1822 const abi_size = dst_ty.abiSize(self.target.*);
1823 const adj_off = off + abi_size;
1824 if (off > math.maxInt(i32)) {
1825 return self.fail(src, "stack offset too large", .{});
1826 }
1827 const encoder = try X8664Encoder.init(self.code, 7);
1828 encoder.rex(.{
1829 .w = abi_size == 8,
1830 .r = dst_reg.isExtended(),
1831 });
1832 encoder.opcode_1byte(mr + 3);
1833 if (adj_off <= std.math.maxInt(i8)) {
1834 encoder.modRm_indirectDisp8(
1835 dst_reg.low_id(),
1836 Register.ebp.low_id(),
1837 );
1838 encoder.disp8(-@intCast(i8, adj_off));
1839 } else {
1840 encoder.modRm_indirectDisp32(
1841 dst_reg.low_id(),
1842 Register.ebp.low_id(),
1843 );
1844 encoder.disp32(-@intCast(i32, adj_off));
1845 }
1846 },
1605 .compare_flags_unsigned => {1847 .compare_flags_unsigned => {
1606 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});1848 return self.fail(src, "TODO implement x86 ADD/SUB/CMP source compare flag (unsigned)", .{});
1607 },1849 },
...@@ -1640,27 +1882,183 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -1640,27 +1882,183 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
1640 }1882 }
1641 }1883 }
16421884
1885 /// Performs integer multiplication between dst_mcv and src_mcv, storing the result in dst_mcv.
1886 fn genX8664Imul(
1887 self: *Self,
1888 src: LazySrcLoc,
1889 dst_ty: Type,
1890 dst_mcv: MCValue,
1891 src_mcv: MCValue,
1892 ) !void {
1893 switch (dst_mcv) {
1894 .none => unreachable,
1895 .undef => unreachable,
1896 .dead, .unreach, .immediate => unreachable,
1897 .compare_flags_unsigned => unreachable,
1898 .compare_flags_signed => unreachable,
1899 .ptr_stack_offset => unreachable,
1900 .ptr_embedded_in_code => unreachable,
1901 .register => |dst_reg| {
1902 switch (src_mcv) {
1903 .none => unreachable,
1904 .undef => try self.genSetReg(src, dst_ty, dst_reg, .undef),
1905 .dead, .unreach => unreachable,
1906 .ptr_stack_offset => unreachable,
1907 .ptr_embedded_in_code => unreachable,
1908 .register => |src_reg| {
1909 // register, register
1910 //
1911 // Use the following imul opcode
1912 // 0F AF /r: IMUL r32/64, r/m32/64
1913 const abi_size = dst_ty.abiSize(self.target.*);
1914 const encoder = try X8664Encoder.init(self.code, 4);
1915 encoder.rex(.{
1916 .w = abi_size == 8,
1917 .r = dst_reg.isExtended(),
1918 .b = src_reg.isExtended(),
1919 });
1920 encoder.opcode_2byte(0x0f, 0xaf);
1921 encoder.modRm_direct(
1922 dst_reg.low_id(),
1923 src_reg.low_id(),
1924 );
1925 },
1926 .immediate => |imm| {
1927 // register, immediate:
1928 // depends on size of immediate.
1929 //
1930 // immediate fits in i8:
1931 // 6B /r ib: IMUL r32/64, r/m32/64, imm8
1932 //
1933 // immediate fits in i32:
1934 // 69 /r id: IMUL r32/64, r/m32/64, imm32
1935 //
1936 // immediate is huge:
1937 // split into 2 instructions
1938 // 1) copy the 64 bit immediate into a tmp register
1939 // 2) perform register,register mul
1940 // 0F AF /r: IMUL r32/64, r/m32/64
1941 if (math.minInt(i8) <= imm and imm <= math.maxInt(i8)) {
1942 const abi_size = dst_ty.abiSize(self.target.*);
1943 const encoder = try X8664Encoder.init(self.code, 4);
1944 encoder.rex(.{
1945 .w = abi_size == 8,
1946 .r = dst_reg.isExtended(),
1947 .b = dst_reg.isExtended(),
1948 });
1949 encoder.opcode_1byte(0x6B);
1950 encoder.modRm_direct(
1951 dst_reg.low_id(),
1952 dst_reg.low_id(),
1953 );
1954 encoder.imm8(@intCast(i8, imm));
1955 } else if (math.minInt(i32) <= imm and imm <= math.maxInt(i32)) {
1956 const abi_size = dst_ty.abiSize(self.target.*);
1957 const encoder = try X8664Encoder.init(self.code, 7);
1958 encoder.rex(.{
1959 .w = abi_size == 8,
1960 .r = dst_reg.isExtended(),
1961 .b = dst_reg.isExtended(),
1962 });
1963 encoder.opcode_1byte(0x69);
1964 encoder.modRm_direct(
1965 dst_reg.low_id(),
1966 dst_reg.low_id(),
1967 );
1968 encoder.imm32(@intCast(i32, imm));
1969 } else {
1970 const src_reg = try self.copyToTmpRegister(src, dst_ty, src_mcv);
1971 return self.genX8664Imul(src, dst_ty, dst_mcv, MCValue{ .register = src_reg });
1972 }
1973 },
1974 .embedded_in_code, .memory, .stack_offset => {
1975 return self.fail(src, "TODO implement x86 multiply source memory", .{});
1976 },
1977 .compare_flags_unsigned => {
1978 return self.fail(src, "TODO implement x86 multiply source compare flag (unsigned)", .{});
1979 },
1980 .compare_flags_signed => {
1981 return self.fail(src, "TODO implement x86 multiply source compare flag (signed)", .{});
1982 },
1983 }
1984 },
1985 .stack_offset => |off| {
1986 switch (src_mcv) {
1987 .none => unreachable,
1988 .undef => return self.genSetStack(src, dst_ty, off, .undef),
1989 .dead, .unreach => unreachable,
1990 .ptr_stack_offset => unreachable,
1991 .ptr_embedded_in_code => unreachable,
1992 .register => |src_reg| {
1993 // copy dst to a register
1994 const dst_reg = try self.copyToTmpRegister(src, dst_ty, dst_mcv);
1995 // multiply into dst_reg
1996 // register, register
1997 // Use the following imul opcode
1998 // 0F AF /r: IMUL r32/64, r/m32/64
1999 const abi_size = dst_ty.abiSize(self.target.*);
2000 const encoder = try X8664Encoder.init(self.code, 4);
2001 encoder.rex(.{
2002 .w = abi_size == 8,
2003 .r = dst_reg.isExtended(),
2004 .b = src_reg.isExtended(),
2005 });
2006 encoder.opcode_2byte(0x0f, 0xaf);
2007 encoder.modRm_direct(
2008 dst_reg.low_id(),
2009 src_reg.low_id(),
2010 );
2011 // copy dst_reg back out
2012 return self.genSetStack(src, dst_ty, off, MCValue{ .register = dst_reg });
2013 },
2014 .immediate => |imm| {
2015 return self.fail(src, "TODO implement x86 multiply source immediate", .{});
2016 },
2017 .embedded_in_code, .memory, .stack_offset => {
2018 return self.fail(src, "TODO implement x86 multiply source memory", .{});
2019 },
2020 .compare_flags_unsigned => {
2021 return self.fail(src, "TODO implement x86 multiply source compare flag (unsigned)", .{});
2022 },
2023 .compare_flags_signed => {
2024 return self.fail(src, "TODO implement x86 multiply source compare flag (signed)", .{});
2025 },
2026 }
2027 },
2028 .embedded_in_code, .memory => {
2029 return self.fail(src, "TODO implement x86 multiply destination memory", .{});
2030 },
2031 }
2032 }
2033
1643 fn genX8664ModRMRegToStack(self: *Self, src: LazySrcLoc, ty: Type, off: u32, reg: Register, opcode: u8) !void {2034 fn genX8664ModRMRegToStack(self: *Self, src: LazySrcLoc, ty: Type, off: u32, reg: Register, opcode: u8) !void {
1644 const abi_size = ty.abiSize(self.target.*);2035 const abi_size = ty.abiSize(self.target.*);
1645 const adj_off = off + abi_size;2036 const adj_off = off + abi_size;
1646 try self.code.ensureCapacity(self.code.items.len + 7);2037 if (off > math.maxInt(i32)) {
1647 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended() });2038 return self.fail(src, "stack offset too large", .{});
1648 const reg_id: u8 = @truncate(u3, reg.id());2039 }
1649 if (adj_off <= 128) {2040
2041 const i_adj_off = -@intCast(i32, adj_off);
2042 const encoder = try X8664Encoder.init(self.code, 7);
2043 encoder.rex(.{
2044 .w = abi_size == 8,
2045 .r = reg.isExtended(),
2046 });
2047 encoder.opcode_1byte(opcode);
2048 if (i_adj_off < std.math.maxInt(i8)) {
1650 // example: 48 89 55 7f mov QWORD PTR [rbp+0x7f],rdx2049 // example: 48 89 55 7f mov QWORD PTR [rbp+0x7f],rdx
1651 const RM = @as(u8, 0b01_000_101) | (reg_id << 3);2050 encoder.modRm_indirectDisp8(
1652 const negative_offset = @intCast(i8, -@intCast(i32, adj_off));2051 reg.low_id(),
1653 const twos_comp = @bitCast(u8, negative_offset);2052 Register.ebp.low_id(),
1654 self.code.appendSliceAssumeCapacity(&[_]u8{ opcode, RM, twos_comp });2053 );
1655 } else if (adj_off <= 2147483648) {2054 encoder.disp8(@intCast(i8, i_adj_off));
1656 // example: 48 89 95 80 00 00 00 mov QWORD PTR [rbp+0x80],rdx
1657 const RM = @as(u8, 0b10_000_101) | (reg_id << 3);
1658 const negative_offset = @intCast(i32, -@intCast(i33, adj_off));
1659 const twos_comp = @bitCast(u32, negative_offset);
1660 self.code.appendSliceAssumeCapacity(&[_]u8{ opcode, RM });
1661 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), twos_comp);
1662 } else {2055 } else {
1663 return self.fail(src, "stack offset too large", .{});2056 // example: 48 89 95 80 00 00 00 mov QWORD PTR [rbp+0x80],rdx
2057 encoder.modRm_indirectDisp32(
2058 reg.low_id(),
2059 Register.ebp.low_id(),
2060 );
2061 encoder.disp32(i_adj_off);
1664 }2062 }
1665 }2063 }
16662064
...@@ -2106,12 +2504,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2106,12 +2504,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2106 log.debug("got_addr = 0x{x}", .{got_addr});2504 log.debug("got_addr = 0x{x}", .{got_addr});
2107 switch (arch) {2505 switch (arch) {
2108 .x86_64 => {2506 .x86_64 => {
2109 try self.genSetReg(inst.base.src, Type.initTag(.u32), .rax, .{ .memory = got_addr });2507 try self.genSetReg(inst.base.src, Type.initTag(.u64), .rax, .{ .memory = got_addr });
2110 // callq *%rax2508 // callq *%rax
2509 try self.code.ensureCapacity(self.code.items.len + 2);
2111 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });2510 self.code.appendSliceAssumeCapacity(&[2]u8{ 0xff, 0xd0 });
2112 },2511 },
2113 .aarch64 => {2512 .aarch64 => {
2114 try self.genSetReg(inst.base.src, Type.initTag(.u32), .x30, .{ .memory = got_addr });2513 try self.genSetReg(inst.base.src, Type.initTag(.u64), .x30, .{ .memory = got_addr });
2115 // blr x302514 // blr x30
2116 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());2515 writeInt(u32, try self.code.addManyAsArray(4), Instruction.blr(.x30).toU32());
2117 },2516 },
...@@ -2276,10 +2675,42 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2276,10 +2675,42 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2276 const lhs = try self.resolveInst(inst.lhs);2675 const lhs = try self.resolveInst(inst.lhs);
2277 const rhs = try self.resolveInst(inst.rhs);2676 const rhs = try self.resolveInst(inst.rhs);
22782677
2279 const src_mcv = rhs;2678 const lhs_is_register = lhs == .register;
2280 const dst_mcv = if (lhs != .register) try self.copyToNewRegister(inst.lhs, lhs) else lhs;2679 const rhs_is_register = rhs == .register;
2680 // lhs should always be a register
2681 const rhs_should_be_register = try self.armOperandShouldBeRegister(inst.rhs.src, rhs);
2682
2683 var lhs_mcv = lhs;
2684 var rhs_mcv = rhs;
2685
2686 // Allocate registers
2687 if (rhs_should_be_register) {
2688 if (!lhs_is_register and !rhs_is_register) {
2689 const regs = try self.register_manager.allocRegs(2, .{ inst.rhs, inst.lhs }, &.{});
2690 lhs_mcv = MCValue{ .register = regs[0] };
2691 rhs_mcv = MCValue{ .register = regs[1] };
2692 } else if (!rhs_is_register) {
2693 rhs_mcv = MCValue{ .register = try self.register_manager.allocReg(inst.rhs, &.{}) };
2694 }
2695 }
2696 if (!lhs_is_register) {
2697 lhs_mcv = MCValue{ .register = try self.register_manager.allocReg(inst.lhs, &.{}) };
2698 }
2699
2700 // Move the operands to the newly allocated registers
2701 const branch = &self.branch_stack.items[self.branch_stack.items.len - 1];
2702 if (lhs_mcv == .register and !lhs_is_register) {
2703 try self.genSetReg(inst.lhs.src, inst.lhs.ty, lhs_mcv.register, lhs);
2704 branch.inst_table.putAssumeCapacity(inst.lhs, lhs);
2705 }
2706 if (rhs_mcv == .register and !rhs_is_register) {
2707 try self.genSetReg(inst.rhs.src, inst.rhs.ty, rhs_mcv.register, rhs);
2708 branch.inst_table.putAssumeCapacity(inst.rhs, rhs);
2709 }
2710
2711 // The destination register is not present in the cmp instruction
2712 try self.genArmBinOpCode(inst.base.src, undefined, lhs_mcv, rhs_mcv, false, .cmp_eq);
22812713
2282 try self.genArmBinOpCode(inst.base.src, dst_mcv.register, dst_mcv, src_mcv, .cmp_eq);
2283 const info = inst.lhs.ty.intInfo(self.target.*);2714 const info = inst.lhs.ty.intInfo(self.target.*);
2284 return switch (info.signedness) {2715 return switch (info.signedness) {
2285 .signed => MCValue{ .compare_flags_signed = op },2716 .signed => MCValue{ .compare_flags_signed = op },
...@@ -2335,15 +2766,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2335,15 +2766,19 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2335 .register => |reg| blk: {2766 .register => |reg| blk: {
2336 // test reg, 12767 // test reg, 1
2337 // TODO detect al, ax, eax2768 // TODO detect al, ax, eax
2338 try self.code.ensureCapacity(self.code.items.len + 4);2769 const encoder = try X8664Encoder.init(self.code, 4);
2339 // TODO audit this codegen: we force w = true here to make2770 encoder.rex(.{
2340 // the value affect the big register2771 // TODO audit this codegen: we force w = true here to make
2341 self.rex(.{ .b = reg.isExtended(), .w = true });2772 // the value affect the big register
2342 self.code.appendSliceAssumeCapacity(&[_]u8{2773 .w = true,
2343 0xf6,2774 .b = reg.isExtended(),
2344 @as(u8, 0xC0) | (0 << 3) | @truncate(u3, reg.id()),
2345 0x01,
2346 });2775 });
2776 encoder.opcode_1byte(0xf6);
2777 encoder.modRm_direct(
2778 0,
2779 reg.low_id(),
2780 );
2781 encoder.disp8(1);
2347 break :blk 0x84;2782 break :blk 0x84;
2348 },2783 },
2349 else => return self.fail(inst.base.src, "TODO implement condbr {s} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),2784 else => return self.fail(inst.base.src, "TODO implement condbr {s} when condition is {s}", .{ self.target.cpu.arch, @tagName(cond) }),
...@@ -2653,9 +3088,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2653,9 +3088,9 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2653 switch (arch) {3088 switch (arch) {
2654 .x86_64 => switch (inst.base.tag) {3089 .x86_64 => switch (inst.base.tag) {
2655 // lhs AND rhs3090 // lhs AND rhs
2656 .bool_and => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 4, 0x20),3091 .bool_and => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
2657 // lhs OR rhs3092 // lhs OR rhs
2658 .bool_or => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs, 1, 0x08),3093 .bool_or => return try self.genX8664BinMath(&inst.base, inst.lhs, inst.rhs),
2659 else => unreachable, // Not a boolean operation3094 else => unreachable, // Not a boolean operation
2660 },3095 },
2661 .arm, .armeb => switch (inst.base.tag) {3096 .arm, .armeb => switch (inst.base.tag) {
...@@ -2862,39 +3297,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -2862,39 +3297,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
2862 }3297 }
2863 }3298 }
28643299
2865 /// Encodes a REX prefix as specified, and appends it to the instruction
2866 /// stream. This only modifies the instruction stream if at least one bit
2867 /// is set true, which has a few implications:
2868 ///
2869 /// * The length of the instruction buffer will be modified *if* the
2870 /// resulting REX is meaningful, but will remain the same if it is not.
2871 /// * Deliberately inserting a "meaningless REX" requires explicit usage of
2872 /// 0x40, and cannot be done via this function.
2873 /// W => 64 bit mode
2874 /// R => extension to the MODRM.reg field
2875 /// X => extension to the SIB.index field
2876 /// B => extension to the MODRM.rm field or the SIB.base field
2877 fn rex(self: *Self, arg: struct { b: bool = false, w: bool = false, x: bool = false, r: bool = false }) void {
2878 comptime assert(arch == .x86_64);
2879 // From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB.
2880 var value: u8 = 0x40;
2881 if (arg.b) {
2882 value |= 0x1;
2883 }
2884 if (arg.x) {
2885 value |= 0x2;
2886 }
2887 if (arg.r) {
2888 value |= 0x4;
2889 }
2890 if (arg.w) {
2891 value |= 0x8;
2892 }
2893 if (value != 0x40) {
2894 self.code.appendAssumeCapacity(value);
2895 }
2896 }
2897
2898 /// Sets the value without any modifications to register allocation metadata or stack allocation metadata.3300 /// Sets the value without any modifications to register allocation metadata or stack allocation metadata.
2899 fn setRegOrMem(self: *Self, src: LazySrcLoc, ty: Type, loc: MCValue, val: MCValue) !void {3301 fn setRegOrMem(self: *Self, src: LazySrcLoc, ty: Type, loc: MCValue, val: MCValue) !void {
2900 switch (loc) {3302 switch (loc) {
...@@ -3442,20 +3844,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3442,20 +3844,25 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3442 }3844 }
3443 },3845 },
3444 .compare_flags_unsigned => |op| {3846 .compare_flags_unsigned => |op| {
3445 try self.code.ensureCapacity(self.code.items.len + 3);3847 const encoder = try X8664Encoder.init(self.code, 7);
3446 // TODO audit this codegen: we force w = true here to make3848 // TODO audit this codegen: we force w = true here to make
3447 // the value affect the big register3849 // the value affect the big register
3448 self.rex(.{ .b = reg.isExtended(), .w = true });3850 encoder.rex(.{
3449 const opcode: u8 = switch (op) {3851 .w = true,
3852 .b = reg.isExtended(),
3853 });
3854 encoder.opcode_2byte(0x0f, switch (op) {
3450 .gte => 0x93,3855 .gte => 0x93,
3451 .gt => 0x97,3856 .gt => 0x97,
3452 .neq => 0x95,3857 .neq => 0x95,
3453 .lt => 0x92,3858 .lt => 0x92,
3454 .lte => 0x96,3859 .lte => 0x96,
3455 .eq => 0x94,3860 .eq => 0x94,
3456 };3861 });
3457 const id = @as(u8, reg.id() & 0b111);3862 encoder.modRm_direct(
3458 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x0f, opcode, 0xC0 | id });3863 0,
3864 reg.low_id(),
3865 );
3459 },3866 },
3460 .compare_flags_signed => |op| {3867 .compare_flags_signed => |op| {
3461 return self.fail(src, "TODO set register with compare flags value (signed)", .{});3868 return self.fail(src, "TODO set register with compare flags value (signed)", .{});
...@@ -3465,40 +3872,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3465,40 +3872,43 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3465 // register is the fastest way to zero a register.3872 // register is the fastest way to zero a register.
3466 if (x == 0) {3873 if (x == 0) {
3467 // The encoding for `xor r32, r32` is `0x31 /r`.3874 // The encoding for `xor r32, r32` is `0x31 /r`.
3468 // Section 3.1.1.1 of the Intel x64 Manual states that "/r indicates that the3875 const encoder = try X8664Encoder.init(self.code, 3);
3469 // ModR/M byte of the instruction contains a register operand and an r/m operand."3876
3470 //
3471 // R/M bytes are composed of two bits for the mode, then three bits for the register,
3472 // then three bits for the operand. Since we're zeroing a register, the two three-bit
3473 // values will be identical, and the mode is three (the raw register value).
3474 //
3475 // If we're accessing e.g. r8d, we need to use a REX prefix before the actual operation. Since3877 // If we're accessing e.g. r8d, we need to use a REX prefix before the actual operation. Since
3476 // this is a 32-bit operation, the W flag is set to zero. X is also zero, as we're not using a SIB.3878 // this is a 32-bit operation, the W flag is set to zero. X is also zero, as we're not using a SIB.
3477 // Both R and B are set, as we're extending, in effect, the register bits *and* the operand.3879 // Both R and B are set, as we're extending, in effect, the register bits *and* the operand.
3478 try self.code.ensureCapacity(self.code.items.len + 3);3880 encoder.rex(.{
3479 self.rex(.{ .r = reg.isExtended(), .b = reg.isExtended() });3881 .r = reg.isExtended(),
3480 const id = @as(u8, reg.id() & 0b111);3882 .b = reg.isExtended(),
3481 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x31, 0xC0 | id << 3 | id });3883 });
3884 encoder.opcode_1byte(0x31);
3885 // Section 3.1.1.1 of the Intel x64 Manual states that "/r indicates that the
3886 // ModR/M byte of the instruction contains a register operand and an r/m operand."
3887 encoder.modRm_direct(
3888 reg.low_id(),
3889 reg.low_id(),
3890 );
3891
3482 return;3892 return;
3483 }3893 }
3484 if (x <= math.maxInt(u32)) {3894 if (x <= math.maxInt(i32)) {
3485 // Next best case: if we set the lower four bytes, the upper four will be zeroed.3895 // Next best case: if we set the lower four bytes, the upper four will be zeroed.
3486 //3896 //
3487 // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.3897 // The encoding for `mov IMM32 -> REG` is (0xB8 + R) IMM.
3488 if (reg.isExtended()) {3898
3489 // Just as with XORing, we need a REX prefix. This time though, we only3899 const encoder = try X8664Encoder.init(self.code, 6);
3490 // need the B bit set, as we're extending the opcode's register field,3900 // Just as with XORing, we need a REX prefix. This time though, we only
3491 // and there is no Mod R/M byte.3901 // need the B bit set, as we're extending the opcode's register field,
3492 //3902 // and there is no Mod R/M byte.
3493 // Thus, we need b01000001, or 0x41.3903 encoder.rex(.{
3494 try self.code.resize(self.code.items.len + 6);3904 .b = reg.isExtended(),
3495 self.code.items[self.code.items.len - 6] = 0x41;3905 });
3496 } else {3906 encoder.opcode_withReg(0xB8, reg.low_id());
3497 try self.code.resize(self.code.items.len + 5);3907
3498 }3908 // no ModR/M byte
3499 self.code.items[self.code.items.len - 5] = 0xB8 | @as(u8, reg.id() & 0b111);3909
3500 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];3910 // IMM
3501 mem.writeIntLittle(u32, imm_ptr, @intCast(u32, x));3911 encoder.imm32(@intCast(i32, x));
3502 return;3912 return;
3503 }3913 }
3504 // Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls3914 // Worst case: we need to load the 64-bit register with the IMM. GNU's assemblers calls
...@@ -3508,79 +3918,98 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3508,79 +3918,98 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3508 // This encoding is, in fact, the *same* as the one used for 32-bit loads. The only3918 // This encoding is, in fact, the *same* as the one used for 32-bit loads. The only
3509 // difference is that we set REX.W before the instruction, which extends the load to3919 // difference is that we set REX.W before the instruction, which extends the load to
3510 // 64-bit and uses the full bit-width of the register.3920 // 64-bit and uses the full bit-width of the register.
3511 //3921 {
3512 // Since we always need a REX here, let's just check if we also need to set REX.B.3922 const encoder = try X8664Encoder.init(self.code, 10);
3513 //3923 encoder.rex(.{
3514 // In this case, the encoding of the REX byte is 0b0100100B3924 .w = true,
3515 try self.code.ensureCapacity(self.code.items.len + 10);3925 .b = reg.isExtended(),
3516 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended() });3926 });
3517 self.code.items.len += 9;3927 encoder.opcode_withReg(0xB8, reg.low_id());
3518 self.code.items[self.code.items.len - 9] = 0xB8 | @as(u8, reg.id() & 0b111);3928 encoder.imm64(x);
3519 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];3929 }
3520 mem.writeIntLittle(u64, imm_ptr, x);
3521 },3930 },
3522 .embedded_in_code => |code_offset| {3931 .embedded_in_code => |code_offset| {
3523 // We need the offset from RIP in a signed i32 twos complement.3932 // We need the offset from RIP in a signed i32 twos complement.
3524 // The instruction is 7 bytes long and RIP points to the next instruction.3933 // The instruction is 7 bytes long and RIP points to the next instruction.
3525 try self.code.ensureCapacity(self.code.items.len + 7);3934
3526 // 64-bit LEA is encoded as REX.W 8D /r. If the register is extended, the REX byte is modified,3935 // 64-bit LEA is encoded as REX.W 8D /r.
3527 // but the operation size is unchanged. Since we're using a disp32, we want mode 0 and lower three3936 const rip = self.code.items.len + 7;
3528 // bits as five.
3529 // REX 0x8D 0b00RRR101, where RRR is the lower three bits of the id.
3530 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended() });
3531 self.code.items.len += 6;
3532 const rip = self.code.items.len;
3533 const big_offset = @intCast(i64, code_offset) - @intCast(i64, rip);3937 const big_offset = @intCast(i64, code_offset) - @intCast(i64, rip);
3534 const offset = @intCast(i32, big_offset);3938 const offset = @intCast(i32, big_offset);
3535 self.code.items[self.code.items.len - 6] = 0x8D;3939 const encoder = try X8664Encoder.init(self.code, 7);
3536 self.code.items[self.code.items.len - 5] = 0b101 | (@as(u8, reg.id() & 0b111) << 3);3940
3537 const imm_ptr = self.code.items[self.code.items.len - 4 ..][0..4];3941 // byte 1, always exists because w = true
3538 mem.writeIntLittle(i32, imm_ptr, offset);3942 encoder.rex(.{
3943 .w = true,
3944 .r = reg.isExtended(),
3945 });
3946 // byte 2
3947 encoder.opcode_1byte(0x8D);
3948 // byte 3
3949 encoder.modRm_RIPDisp32(reg.low_id());
3950 // byte 4-7
3951 encoder.disp32(offset);
3952
3953 // Double check that we haven't done any math errors
3954 assert(rip == self.code.items.len);
3539 },3955 },
3540 .register => |src_reg| {3956 .register => |src_reg| {
3541 // If the registers are the same, nothing to do.3957 // If the registers are the same, nothing to do.
3542 if (src_reg.id() == reg.id())3958 if (src_reg.id() == reg.id())
3543 return;3959 return;
35443960
3545 // This is a variant of 8B /r. Since we're using 64-bit moves, we require a REX.3961 // This is a variant of 8B /r.
3546 // This is thus three bytes: REX 0x8B R/M.3962 const abi_size = ty.abiSize(self.target.*);
3547 // If the destination is extended, the R field must be 1.3963 const encoder = try X8664Encoder.init(self.code, 3);
3548 // If the *source* is extended, the B field must be 1.3964 encoder.rex(.{
3549 // Since the register is being accessed directly, the R/M mode is three. The reg field (the middle3965 .w = abi_size == 8,
3550 // three bits) contain the destination, and the R/M field (the lower three bits) contain the source.3966 .r = reg.isExtended(),
3551 try self.code.ensureCapacity(self.code.items.len + 3);3967 .b = src_reg.isExtended(),
3552 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended(), .b = src_reg.isExtended() });3968 });
3553 const R = 0xC0 | (@as(u8, reg.id() & 0b111) << 3) | @as(u8, src_reg.id() & 0b111);3969 encoder.opcode_1byte(0x8B);
3554 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, R });3970 encoder.modRm_direct(reg.low_id(), src_reg.low_id());
3555 },3971 },
3556 .memory => |x| {3972 .memory => |x| {
3557 if (self.bin_file.options.pie) {3973 if (self.bin_file.options.pie) {
3558 // RIP-relative displacement to the entry in the GOT table.3974 // RIP-relative displacement to the entry in the GOT table.
3975 const abi_size = ty.abiSize(self.target.*);
3976 const encoder = try X8664Encoder.init(self.code, 10);
3977
3978 // LEA reg, [<offset>]
3979
3980 // We encode the instruction FIRST because prefixes may or may not appear.
3981 // After we encode the instruction, we will know that the displacement bytes
3982 // for [<offset>] will be at self.code.items.len - 4.
3983 encoder.rex(.{
3984 .w = true, // force 64 bit because loading an address (to the GOT)
3985 .r = reg.isExtended(),
3986 });
3987 encoder.opcode_1byte(0x8D);
3988 encoder.modRm_RIPDisp32(reg.low_id());
3989 encoder.disp32(0);
3990
3559 // TODO we should come up with our own, backend independent relocation types3991 // TODO we should come up with our own, backend independent relocation types
3560 // which each backend (Elf, MachO, etc.) would then translate into an actual3992 // which each backend (Elf, MachO, etc.) would then translate into an actual
3561 // fixup when linking.3993 // fixup when linking.
3562 if (self.bin_file.cast(link.File.MachO)) |macho_file| {3994 if (self.bin_file.cast(link.File.MachO)) |macho_file| {
3563 try macho_file.pie_fixups.append(self.bin_file.allocator, .{3995 try macho_file.pie_fixups.append(self.bin_file.allocator, .{
3564 .target_addr = x,3996 .target_addr = x,
3565 .offset = self.code.items.len + 3,3997 .offset = self.code.items.len - 4,
3566 .size = 4,3998 .size = 4,
3567 });3999 });
3568 } else {4000 } else {
3569 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});4001 return self.fail(src, "TODO implement genSetReg for PIE GOT indirection on this platform", .{});
3570 }4002 }
3571 try self.code.ensureCapacity(self.code.items.len + 7);
3572 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended() });
3573 self.code.appendSliceAssumeCapacity(&[_]u8{
3574 0x8D,
3575 0x05 | (@as(u8, reg.id() & 0b111) << 3),
3576 });
3577 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), 0);
35784003
3579 try self.code.ensureCapacity(self.code.items.len + 3);4004 // MOV reg, [reg]
3580 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended(), .r = reg.isExtended() });4005 encoder.rex(.{
3581 const RM = (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id());4006 .w = abi_size == 8,
3582 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, RM });4007 .r = reg.isExtended(),
3583 } else if (x <= math.maxInt(u32)) {4008 .b = reg.isExtended(),
4009 });
4010 encoder.opcode_1byte(0x8B);
4011 encoder.modRm_indirectDisp0(reg.low_id(), reg.low_id());
4012 } else if (x <= math.maxInt(i32)) {
3584 // Moving from memory to a register is a variant of `8B /r`.4013 // Moving from memory to a register is a variant of `8B /r`.
3585 // Since we're using 64-bit moves, we require a REX.4014 // Since we're using 64-bit moves, we require a REX.
3586 // This variant also requires a SIB, as it would otherwise be RIP-relative.4015 // This variant also requires a SIB, as it would otherwise be RIP-relative.
...@@ -3588,14 +4017,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3588,14 +4017,18 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3588 // The SIB must be 0x25, to indicate a disp32 with no scaled index.4017 // The SIB must be 0x25, to indicate a disp32 with no scaled index.
3589 // 0b00RRR100, where RRR is the lower three bits of the register ID.4018 // 0b00RRR100, where RRR is the lower three bits of the register ID.
3590 // The instruction is thus eight bytes; REX 0x8B 0b00RRR100 0x25 followed by a four-byte disp32.4019 // The instruction is thus eight bytes; REX 0x8B 0b00RRR100 0x25 followed by a four-byte disp32.
3591 try self.code.ensureCapacity(self.code.items.len + 8);4020 const abi_size = ty.abiSize(self.target.*);
3592 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended() });4021 const encoder = try X8664Encoder.init(self.code, 8);
3593 self.code.appendSliceAssumeCapacity(&[_]u8{4022 encoder.rex(.{
3594 0x8B,4023 .w = abi_size == 8,
3595 0x04 | (@as(u8, reg.id() & 0b111) << 3), // R4024 .r = reg.isExtended(),
3596 0x25,
3597 });4025 });
3598 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), @intCast(u32, x));4026 encoder.opcode_1byte(0x8B);
4027 // effective address = [SIB]
4028 encoder.modRm_SIBDisp0(reg.low_id());
4029 // SIB = disp32
4030 encoder.sib_disp32();
4031 encoder.disp32(@intCast(i32, x));
3599 } else {4032 } else {
3600 // If this is RAX, we can use a direct load; otherwise, we need to load the address, then indirectly load4033 // If this is RAX, we can use a direct load; otherwise, we need to load the address, then indirectly load
3601 // the value.4034 // the value.
...@@ -3603,12 +4036,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3603,12 +4036,13 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3603 // REX.W 0xA1 moffs64*4036 // REX.W 0xA1 moffs64*
3604 // moffs64* is a 64-bit offset "relative to segment base", which really just means the4037 // moffs64* is a 64-bit offset "relative to segment base", which really just means the
3605 // absolute address for all practical purposes.4038 // absolute address for all practical purposes.
3606 try self.code.resize(self.code.items.len + 10);4039
3607 // REX.W == 0x484040 const encoder = try X8664Encoder.init(self.code, 10);
3608 self.code.items[self.code.items.len - 10] = 0x48;4041 encoder.rex(.{
3609 self.code.items[self.code.items.len - 9] = 0xA1;4042 .w = true,
3610 const imm_ptr = self.code.items[self.code.items.len - 8 ..][0..8];4043 });
3611 mem.writeIntLittle(u64, imm_ptr, x);4044 encoder.opcode_1byte(0xA1);
4045 encoder.writeIntLittle(u64, x);
3612 } else {4046 } else {
3613 // This requires two instructions; a move imm as used above, followed by an indirect load using the register4047 // This requires two instructions; a move imm as used above, followed by an indirect load using the register
3614 // as the address and the register as the destination.4048 // as the address and the register as the destination.
...@@ -3625,40 +4059,41 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {...@@ -3625,40 +4059,41 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type {
3625 // Now, the register contains the address of the value to load into it4059 // Now, the register contains the address of the value to load into it
3626 // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant.4060 // Currently, we're only allowing 64-bit registers, so we need the `REX.W 8B /r` variant.
3627 // TODO: determine whether to allow other sized registers, and if so, handle them properly.4061 // TODO: determine whether to allow other sized registers, and if so, handle them properly.
3628 // This operation requires three bytes: REX 0x8B R/M4062
3629 try self.code.ensureCapacity(self.code.items.len + 3);4063 // mov reg, [reg]
3630 // For this operation, we want R/M mode *zero* (use register indirectly), and the two register4064 const abi_size = ty.abiSize(self.target.*);
3631 // values must match. Thus, it's 00ABCABC where ABC is the lower three bits of the register ID.4065 const encoder = try X8664Encoder.init(self.code, 3);
3632 //4066 encoder.rex(.{
3633 // Furthermore, if this is an extended register, both B and R must be set in the REX byte, as *both*4067 .w = abi_size == 8,
3634 // register operands need to be marked as extended.4068 .r = reg.isExtended(),
3635 self.rex(.{ .w = reg.size() == 64, .b = reg.isExtended(), .r = reg.isExtended() });4069 .b = reg.isExtended(),
3636 const RM = (@as(u8, reg.id() & 0b111) << 3) | @truncate(u3, reg.id());4070 });
3637 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8B, RM });4071 encoder.opcode_1byte(0x8B);
4072 encoder.modRm_indirectDisp0(reg.low_id(), reg.low_id());
3638 }4073 }
3639 }4074 }
3640 },4075 },
3641 .stack_offset => |unadjusted_off| {4076 .stack_offset => |unadjusted_off| {
3642 try self.code.ensureCapacity(self.code.items.len + 7);4077 const abi_size = ty.abiSize(self.target.*);
3643 const size_bytes = @divExact(reg.size(), 8);4078 const off = unadjusted_off + abi_size;
3644 const off = unadjusted_off + size_bytes;4079 if (off < std.math.minInt(i32) or off > std.math.maxInt(i32)) {
3645 self.rex(.{ .w = reg.size() == 64, .r = reg.isExtended() });4080 return self.fail(src, "stack offset too large", .{});
3646 const reg_id: u8 = @truncate(u3, reg.id());4081 }
3647 if (off <= 128) {4082 const ioff = -@intCast(i32, off);
4083 const encoder = try X8664Encoder.init(self.code, 3);
4084 encoder.rex(.{
4085 .w = abi_size == 8,
4086 .r = reg.isExtended(),
4087 });
4088 encoder.opcode_1byte(0x8B);
4089 if (std.math.minInt(i8) <= ioff and ioff <= std.math.maxInt(i8)) {
3648 // Example: 48 8b 4d 7f mov rcx,QWORD PTR [rbp+0x7f]4090 // Example: 48 8b 4d 7f mov rcx,QWORD PTR [rbp+0x7f]
3649 const RM = @as(u8, 0b01_000_101) | (reg_id << 3);4091 encoder.modRm_indirectDisp8(reg.low_id(), Register.ebp.low_id());
3650 const negative_offset = @intCast(i8, -@intCast(i32, off));4092 encoder.disp8(@intCast(i8, ioff));
3651 const twos_comp = @bitCast(u8, negative_offset);
3652 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8b, RM, twos_comp });
3653 } else if (off <= 2147483648) {
3654 // Example: 48 8b 8d 80 00 00 00 mov rcx,QWORD PTR [rbp+0x80]
3655 const RM = @as(u8, 0b10_000_101) | (reg_id << 3);
3656 const negative_offset = @intCast(i32, -@intCast(i33, off));
3657 const twos_comp = @bitCast(u32, negative_offset);
3658 self.code.appendSliceAssumeCapacity(&[_]u8{ 0x8b, RM });
3659 mem.writeIntLittle(u32, self.code.addManyAsArrayAssumeCapacity(4), twos_comp);
3660 } else {4093 } else {
3661 return self.fail(src, "stack offset too large", .{});4094 // Example: 48 8b 8d 80 00 00 00 mov rcx,QWORD PTR [rbp+0x80]
4095 encoder.modRm_indirectDisp32(reg.low_id(), Register.ebp.low_id());
4096 encoder.disp32(ioff);
3662 }4097 }
3663 },4098 },
3664 },4099 },
src/codegen/x86_64.zig+497
...@@ -1,4 +1,9 @@...@@ -1,4 +1,9 @@
1const std = @import("std");1const std = @import("std");
2const testing = std.testing;
3const mem = std.mem;
4const assert = std.debug.assert;
5const ArrayList = std.ArrayList;
6const Allocator = std.mem.Allocator;
2const Type = @import("../Type.zig");7const Type = @import("../Type.zig");
3const DW = std.dwarf;8const DW = std.dwarf;
49
...@@ -68,6 +73,11 @@ pub const Register = enum(u8) {...@@ -68,6 +73,11 @@ pub const Register = enum(u8) {
68 return @truncate(u4, @enumToInt(self));73 return @truncate(u4, @enumToInt(self));
69 }74 }
7075
76 /// Like id, but only returns the lower 3 bits.
77 pub fn low_id(self: Register) u3 {
78 return @truncate(u3, @enumToInt(self));
79 }
80
71 /// Returns the index into `callee_preserved_regs`.81 /// Returns the index into `callee_preserved_regs`.
72 pub fn allocIndex(self: Register) ?u4 {82 pub fn allocIndex(self: Register) ?u4 {
73 return switch (self) {83 return switch (self) {
...@@ -136,6 +146,493 @@ pub const callee_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8...@@ -136,6 +146,493 @@ pub const callee_preserved_regs = [_]Register{ .rax, .rcx, .rdx, .rsi, .rdi, .r8
136pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };146pub const c_abi_int_param_regs = [_]Register{ .rdi, .rsi, .rdx, .rcx, .r8, .r9 };
137pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };147pub const c_abi_int_return_regs = [_]Register{ .rax, .rdx };
138148
149/// Encoding helper functions for x86_64 instructions
150///
151/// Many of these helpers do very little, but they can help make things
152/// slightly more readable with more descriptive field names / function names.
153///
154/// Some of them also have asserts to ensure that we aren't doing dumb things.
155/// For example, trying to use register 4 (esp) in an indirect modr/m byte is illegal,
156/// you need to encode it with an SIB byte.
157///
158/// Note that ALL of these helper functions will assume capacity,
159/// so ensure that the `code` has sufficient capacity before using them.
160/// The `init` method is the recommended way to ensure capacity.
161pub const Encoder = struct {
162 /// Non-owning reference to the code array
163 code: *ArrayList(u8),
164
165 const Self = @This();
166
167 /// Wrap `code` in Encoder to make it easier to call these helper functions
168 ///
169 /// maximum_inst_size should contain the maximum number of bytes
170 /// that the encoded instruction will take.
171 /// This is because the helper functions will assume capacity
172 /// in order to avoid bounds checking.
173 pub fn init(code: *ArrayList(u8), maximum_inst_size: u8) !Self {
174 try code.ensureCapacity(code.items.len + maximum_inst_size);
175 return Self{ .code = code };
176 }
177
178 /// Directly write a number to the code array with big endianness
179 pub fn writeIntBig(self: Self, comptime T: type, value: T) void {
180 mem.writeIntBig(
181 T,
182 self.code.addManyAsArrayAssumeCapacity(@divExact(@typeInfo(T).Int.bits, 8)),
183 value,
184 );
185 }
186
187 /// Directly write a number to the code array with little endianness
188 pub fn writeIntLittle(self: Self, comptime T: type, value: T) void {
189 mem.writeIntLittle(
190 T,
191 self.code.addManyAsArrayAssumeCapacity(@divExact(@typeInfo(T).Int.bits, 8)),
192 value,
193 );
194 }
195
196 // --------
197 // Prefixes
198 // --------
199
200 pub const LegacyPrefixes = packed struct {
201 /// LOCK
202 prefix_f0: bool = false,
203 /// REPNZ, REPNE, REP, Scalar Double-precision
204 prefix_f2: bool = false,
205 /// REPZ, REPE, REP, Scalar Single-precision
206 prefix_f3: bool = false,
207
208 /// CS segment override or Branch not taken
209 prefix_2e: bool = false,
210 /// DS segment override
211 prefix_36: bool = false,
212 /// ES segment override
213 prefix_26: bool = false,
214 /// FS segment override
215 prefix_64: bool = false,
216 /// GS segment override
217 prefix_65: bool = false,
218
219 /// Branch taken
220 prefix_3e: bool = false,
221
222 /// Operand size override (enables 16 bit operation)
223 prefix_66: bool = false,
224
225 /// Address size override (enables 16 bit address size)
226 prefix_67: bool = false,
227
228 padding: u5 = 0,
229 };
230
231 /// Encodes legacy prefixes
232 pub fn legacyPrefixes(self: Self, prefixes: LegacyPrefixes) void {
233 if (@bitCast(u16, prefixes) != 0) {
234 // Hopefully this path isn't taken very often, so we'll do it the slow way for now
235
236 // LOCK
237 if (prefixes.prefix_f0) self.code.appendAssumeCapacity(0xf0);
238 // REPNZ, REPNE, REP, Scalar Double-precision
239 if (prefixes.prefix_f2) self.code.appendAssumeCapacity(0xf2);
240 // REPZ, REPE, REP, Scalar Single-precision
241 if (prefixes.prefix_f3) self.code.appendAssumeCapacity(0xf3);
242
243 // CS segment override or Branch not taken
244 if (prefixes.prefix_2e) self.code.appendAssumeCapacity(0x2e);
245 // DS segment override
246 if (prefixes.prefix_36) self.code.appendAssumeCapacity(0x36);
247 // ES segment override
248 if (prefixes.prefix_26) self.code.appendAssumeCapacity(0x26);
249 // FS segment override
250 if (prefixes.prefix_64) self.code.appendAssumeCapacity(0x64);
251 // GS segment override
252 if (prefixes.prefix_65) self.code.appendAssumeCapacity(0x65);
253
254 // Branch taken
255 if (prefixes.prefix_3e) self.code.appendAssumeCapacity(0x3e);
256
257 // Operand size override
258 if (prefixes.prefix_66) self.code.appendAssumeCapacity(0x66);
259
260 // Address size override
261 if (prefixes.prefix_67) self.code.appendAssumeCapacity(0x67);
262 }
263 }
264
265 /// Use 16 bit operand size
266 ///
267 /// Note that this flag is overridden by REX.W, if both are present.
268 pub fn prefix16BitMode(self: Self) void {
269 self.code.appendAssumeCapacity(0x66);
270 }
271
272 /// From section 2.2.1.2 of the manual, REX is encoded as b0100WRXB
273 pub const Rex = struct {
274 /// Wide, enables 64-bit operation
275 w: bool = false,
276 /// Extends the reg field in the ModR/M byte
277 r: bool = false,
278 /// Extends the index field in the SIB byte
279 x: bool = false,
280 /// Extends the r/m field in the ModR/M byte,
281 /// or the base field in the SIB byte,
282 /// or the reg field in the Opcode byte
283 b: bool = false,
284 };
285
286 /// Encodes a REX prefix byte given all the fields
287 ///
288 /// Use this byte whenever you need 64 bit operation,
289 /// or one of reg, index, r/m, base, or opcode-reg might be extended.
290 ///
291 /// See struct `Rex` for a description of each field.
292 ///
293 /// Does not add a prefix byte if none of the fields are set!
294 pub fn rex(self: Self, byte: Rex) void {
295 var value: u8 = 0b0100_0000;
296
297 if (byte.w) value |= 0b1000;
298 if (byte.r) value |= 0b0100;
299 if (byte.x) value |= 0b0010;
300 if (byte.b) value |= 0b0001;
301
302 if (value != 0b0100_0000) {
303 self.code.appendAssumeCapacity(value);
304 }
305 }
306
307 // ------
308 // Opcode
309 // ------
310
311 /// Encodes a 1 byte opcode
312 pub fn opcode_1byte(self: Self, opcode: u8) void {
313 self.code.appendAssumeCapacity(opcode);
314 }
315
316 /// Encodes a 2 byte opcode
317 ///
318 /// e.g. IMUL has the opcode 0x0f 0xaf, so you use
319 ///
320 /// encoder.opcode_2byte(0x0f, 0xaf);
321 pub fn opcode_2byte(self: Self, prefix: u8, opcode: u8) void {
322 self.code.appendAssumeCapacity(prefix);
323 self.code.appendAssumeCapacity(opcode);
324 }
325
326 /// Encodes a 1 byte opcode with a reg field
327 ///
328 /// Remember to add a REX prefix byte if reg is extended!
329 pub fn opcode_withReg(self: Self, opcode: u8, reg: u3) void {
330 assert(opcode & 0b111 == 0);
331 self.code.appendAssumeCapacity(opcode | reg);
332 }
333
334 // ------
335 // ModR/M
336 // ------
337
338 /// Construct a ModR/M byte given all the fields
339 ///
340 /// Remember to add a REX prefix byte if reg or rm are extended!
341 pub fn modRm(self: Self, mod: u2, reg_or_opx: u3, rm: u3) void {
342 self.code.appendAssumeCapacity(
343 @as(u8, mod) << 6 | @as(u8, reg_or_opx) << 3 | rm,
344 );
345 }
346
347 /// Construct a ModR/M byte using direct r/m addressing
348 /// r/m effective address: r/m
349 ///
350 /// Note reg's effective address is always just reg for the ModR/M byte.
351 /// Remember to add a REX prefix byte if reg or rm are extended!
352 pub fn modRm_direct(self: Self, reg_or_opx: u3, rm: u3) void {
353 self.modRm(0b11, reg_or_opx, rm);
354 }
355
356 /// Construct a ModR/M byte using indirect r/m addressing
357 /// r/m effective address: [r/m]
358 ///
359 /// Note reg's effective address is always just reg for the ModR/M byte.
360 /// Remember to add a REX prefix byte if reg or rm are extended!
361 pub fn modRm_indirectDisp0(self: Self, reg_or_opx: u3, rm: u3) void {
362 assert(rm != 4 and rm != 5);
363 self.modRm(0b00, reg_or_opx, rm);
364 }
365
366 /// Construct a ModR/M byte using indirect SIB addressing
367 /// r/m effective address: [SIB]
368 ///
369 /// Note reg's effective address is always just reg for the ModR/M byte.
370 /// Remember to add a REX prefix byte if reg or rm are extended!
371 pub fn modRm_SIBDisp0(self: Self, reg_or_opx: u3) void {
372 self.modRm(0b00, reg_or_opx, 0b100);
373 }
374
375 /// Construct a ModR/M byte using RIP-relative addressing
376 /// r/m effective address: [RIP + disp32]
377 ///
378 /// Note reg's effective address is always just reg for the ModR/M byte.
379 /// Remember to add a REX prefix byte if reg or rm are extended!
380 pub fn modRm_RIPDisp32(self: Self, reg_or_opx: u3) void {
381 self.modRm(0b00, reg_or_opx, 0b101);
382 }
383
384 /// Construct a ModR/M byte using indirect r/m with a 8bit displacement
385 /// r/m effective address: [r/m + disp8]
386 ///
387 /// Note reg's effective address is always just reg for the ModR/M byte.
388 /// Remember to add a REX prefix byte if reg or rm are extended!
389 pub fn modRm_indirectDisp8(self: Self, reg_or_opx: u3, rm: u3) void {
390 assert(rm != 4);
391 self.modRm(0b01, reg_or_opx, rm);
392 }
393
394 /// Construct a ModR/M byte using indirect SIB with a 8bit displacement
395 /// r/m effective address: [SIB + disp8]
396 ///
397 /// Note reg's effective address is always just reg for the ModR/M byte.
398 /// Remember to add a REX prefix byte if reg or rm are extended!
399 pub fn modRm_SIBDisp8(self: Self, reg_or_opx: u3) void {
400 self.modRm(0b01, reg_or_opx, 0b100);
401 }
402
403 /// Construct a ModR/M byte using indirect r/m with a 32bit displacement
404 /// r/m effective address: [r/m + disp32]
405 ///
406 /// Note reg's effective address is always just reg for the ModR/M byte.
407 /// Remember to add a REX prefix byte if reg or rm are extended!
408 pub fn modRm_indirectDisp32(self: Self, reg_or_opx: u3, rm: u3) void {
409 assert(rm != 4);
410 self.modRm(0b10, reg_or_opx, rm);
411 }
412
413 /// Construct a ModR/M byte using indirect SIB with a 32bit displacement
414 /// r/m effective address: [SIB + disp32]
415 ///
416 /// Note reg's effective address is always just reg for the ModR/M byte.
417 /// Remember to add a REX prefix byte if reg or rm are extended!
418 pub fn modRm_SIBDisp32(self: Self, reg_or_opx: u3) void {
419 self.modRm(0b10, reg_or_opx, 0b100);
420 }
421
422 // ---
423 // SIB
424 // ---
425
426 /// Construct a SIB byte given all the fields
427 ///
428 /// Remember to add a REX prefix byte if index or base are extended!
429 pub fn sib(self: Self, scale: u2, index: u3, base: u3) void {
430 self.code.appendAssumeCapacity(
431 @as(u8, scale) << 6 | @as(u8, index) << 3 | base,
432 );
433 }
434
435 /// Construct a SIB byte with scale * index + base, no frills.
436 /// r/m effective address: [base + scale * index]
437 ///
438 /// Remember to add a REX prefix byte if index or base are extended!
439 pub fn sib_scaleIndexBase(self: Self, scale: u2, index: u3, base: u3) void {
440 assert(base != 5);
441
442 self.sib(scale, index, base);
443 }
444
445 /// Construct a SIB byte with scale * index + disp32
446 /// r/m effective address: [scale * index + disp32]
447 ///
448 /// Remember to add a REX prefix byte if index or base are extended!
449 pub fn sib_scaleIndexDisp32(self: Self, scale: u2, index: u3) void {
450 assert(index != 4);
451
452 // scale is actually ignored
453 // index = 4 means no index
454 // base = 5 means no base, if mod == 0.
455 self.sib(scale, index, 5);
456 }
457
458 /// Construct a SIB byte with just base
459 /// r/m effective address: [base]
460 ///
461 /// Remember to add a REX prefix byte if index or base are extended!
462 pub fn sib_base(self: Self, base: u3) void {
463 assert(base != 5);
464
465 // scale is actually ignored
466 // index = 4 means no index
467 self.sib(0, 4, base);
468 }
469
470 /// Construct a SIB byte with just disp32
471 /// r/m effective address: [disp32]
472 ///
473 /// Remember to add a REX prefix byte if index or base are extended!
474 pub fn sib_disp32(self: Self) void {
475 // scale is actually ignored
476 // index = 4 means no index
477 // base = 5 means no base, if mod == 0.
478 self.sib(0, 4, 5);
479 }
480
481 /// Construct a SIB byte with scale * index + base + disp8
482 /// r/m effective address: [base + scale * index + disp8]
483 ///
484 /// Remember to add a REX prefix byte if index or base are extended!
485 pub fn sib_scaleIndexBaseDisp8(self: Self, scale: u2, index: u3, base: u3) void {
486 self.sib(scale, index, base);
487 }
488
489 /// Construct a SIB byte with base + disp8, no index
490 /// r/m effective address: [base + disp8]
491 ///
492 /// Remember to add a REX prefix byte if index or base are extended!
493 pub fn sib_baseDisp8(self: Self, base: u3) void {
494 // scale is ignored
495 // index = 4 means no index
496 self.sib(0, 4, base);
497 }
498
499 /// Construct a SIB byte with scale * index + base + disp32
500 /// r/m effective address: [base + scale * index + disp32]
501 ///
502 /// Remember to add a REX prefix byte if index or base are extended!
503 pub fn sib_scaleIndexBaseDisp32(self: Self, scale: u2, index: u3, base: u3) void {
504 self.sib(scale, index, base);
505 }
506
507 /// Construct a SIB byte with base + disp32, no index
508 /// r/m effective address: [base + disp32]
509 ///
510 /// Remember to add a REX prefix byte if index or base are extended!
511 pub fn sib_baseDisp32(self: Self, base: u3) void {
512 // scale is ignored
513 // index = 4 means no index
514 self.sib(0, 4, base);
515 }
516
517 // -------------------------
518 // Trivial (no bit fiddling)
519 // -------------------------
520
521 /// Encode an 8 bit immediate
522 ///
523 /// It is sign-extended to 64 bits by the cpu.
524 pub fn imm8(self: Self, imm: i8) void {
525 self.code.appendAssumeCapacity(@bitCast(u8, imm));
526 }
527
528 /// Encode an 8 bit displacement
529 ///
530 /// It is sign-extended to 64 bits by the cpu.
531 pub fn disp8(self: Self, disp: i8) void {
532 self.code.appendAssumeCapacity(@bitCast(u8, disp));
533 }
534
535 /// Encode an 16 bit immediate
536 ///
537 /// It is sign-extended to 64 bits by the cpu.
538 pub fn imm16(self: Self, imm: i16) void {
539 self.writeIntLittle(i16, imm);
540 }
541
542 /// Encode an 32 bit immediate
543 ///
544 /// It is sign-extended to 64 bits by the cpu.
545 pub fn imm32(self: Self, imm: i32) void {
546 self.writeIntLittle(i32, imm);
547 }
548
549 /// Encode an 32 bit displacement
550 ///
551 /// It is sign-extended to 64 bits by the cpu.
552 pub fn disp32(self: Self, disp: i32) void {
553 self.writeIntLittle(i32, disp);
554 }
555
556 /// Encode an 64 bit immediate
557 ///
558 /// It is sign-extended to 64 bits by the cpu.
559 pub fn imm64(self: Self, imm: u64) void {
560 self.writeIntLittle(u64, imm);
561 }
562};
563
564test "x86_64 Encoder helpers" {
565 var code = ArrayList(u8).init(testing.allocator);
566 defer code.deinit();
567
568 // simple integer multiplication
569
570 // imul eax,edi
571 // 0faf c7
572 {
573 try code.resize(0);
574 const encoder = try Encoder.init(&code, 4);
575 encoder.rex(.{
576 .r = Register.eax.isExtended(),
577 .b = Register.edi.isExtended(),
578 });
579 encoder.opcode_2byte(0x0f, 0xaf);
580 encoder.modRm_direct(
581 Register.eax.low_id(),
582 Register.edi.low_id(),
583 );
584
585 try testing.expectEqualSlices(u8, &[_]u8{ 0x0f, 0xaf, 0xc7 }, code.items);
586 }
587
588 // simple mov
589
590 // mov eax,edi
591 // 89 f8
592 {
593 try code.resize(0);
594 const encoder = try Encoder.init(&code, 3);
595 encoder.rex(.{
596 .r = Register.edi.isExtended(),
597 .b = Register.eax.isExtended(),
598 });
599 encoder.opcode_1byte(0x89);
600 encoder.modRm_direct(
601 Register.edi.low_id(),
602 Register.eax.low_id(),
603 );
604
605 try testing.expectEqualSlices(u8, &[_]u8{ 0x89, 0xf8 }, code.items);
606 }
607
608 // signed integer addition of 32-bit sign extended immediate to 64 bit register
609
610 // add rcx, 2147483647
611 //
612 // Using the following opcode: REX.W + 81 /0 id, we expect the following encoding
613 //
614 // 48 : REX.W set for 64 bit operand (*r*cx)
615 // 81 : opcode for "<arithmetic> with immediate"
616 // c1 : id = rcx,
617 // : c1 = 11 <-- mod = 11 indicates r/m is register (rcx)
618 // : 000 <-- opcode_extension = 0 because opcode extension is /0. /0 specifies ADD
619 // : 001 <-- 001 is rcx
620 // ffffff7f : 2147483647
621 {
622 try code.resize(0);
623 const encoder = try Encoder.init(&code, 7);
624 encoder.rex(.{ .w = true }); // use 64 bit operation
625 encoder.opcode_1byte(0x81);
626 encoder.modRm_direct(
627 0,
628 Register.rcx.low_id(),
629 );
630 encoder.imm32(2147483647);
631
632 try testing.expectEqualSlices(u8, &[_]u8{ 0x48, 0x81, 0xc1, 0xff, 0xff, 0xff, 0x7f }, code.items);
633 }
634}
635
139// TODO add these registers to the enum and populate dwarfLocOp636// TODO add these registers to the enum and populate dwarfLocOp
140// // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register.637// // Return Address register. This is stored in `0(%rsp, "")` and is not a physical register.
141// RA = (16, "RA"),638// RA = (16, "RA"),
src/glibc.zig+7-5
...@@ -40,10 +40,11 @@ pub const ABI = struct {...@@ -40,10 +40,11 @@ pub const ABI = struct {
40 }40 }
41};41};
4242
43// The order of the elements in this array defines the linking order.
43pub const libs = [_]Lib{44pub const libs = [_]Lib{
44 .{ .name = "c", .sover = 6 },
45 .{ .name = "m", .sover = 6 },45 .{ .name = "m", .sover = 6 },
46 .{ .name = "pthread", .sover = 0 },46 .{ .name = "pthread", .sover = 0 },
47 .{ .name = "c", .sover = 6 },
47 .{ .name = "dl", .sover = 2 },48 .{ .name = "dl", .sover = 2 },
48 .{ .name = "rt", .sover = 1 },49 .{ .name = "rt", .sover = 1 },
49 .{ .name = "ld", .sover = 2 },50 .{ .name = "ld", .sover = 2 },
...@@ -763,16 +764,17 @@ pub fn buildSharedObjects(comp: *Compilation) !void {...@@ -763,16 +764,17 @@ pub fn buildSharedObjects(comp: *Compilation) !void {
763 .lt => continue,764 .lt => continue,
764 .gt => {765 .gt => {
765 // TODO Expose via compile error mechanism instead of log.766 // TODO Expose via compile error mechanism instead of log.
766 std.log.warn("invalid target glibc version: {}", .{target_version});767 std.log.err("invalid target glibc version: {}", .{target_version});
767 return error.InvalidTargetGLibCVersion;768 return error.InvalidTargetGLibCVersion;
768 },769 },
769 }770 }
770 } else blk: {771 } else {
771 const latest_index = metadata.all_versions.len - 1;772 const latest_index = metadata.all_versions.len - 1;
772 std.log.warn("zig cannot build new glibc version {}; providing instead {}", .{773 // TODO Expose via compile error mechanism instead of log.
774 std.log.err("zig does not yet provide glibc version {}, the max provided version is {}", .{
773 target_version, metadata.all_versions[latest_index],775 target_version, metadata.all_versions[latest_index],
774 });776 });
775 break :blk latest_index;777 return error.InvalidTargetGLibCVersion;
776 };778 };
777 {779 {
778 var map_contents = std.ArrayList(u8).init(arena);780 var map_contents = std.ArrayList(u8).init(arena);
src/link/Elf.zig+12-13
...@@ -1648,19 +1648,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {...@@ -1648,19 +1648,18 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
1648 // libc dep1648 // libc dep
1649 if (self.base.options.link_libc) {1649 if (self.base.options.link_libc) {
1650 if (self.base.options.libc_installation != null) {1650 if (self.base.options.libc_installation != null) {
1651 if (self.base.options.link_mode == .Static) {1651 const needs_grouping = self.base.options.link_mode == .Static;
1652 try argv.append("--start-group");1652 if (needs_grouping) try argv.append("--start-group");
1653 try argv.append("-lc");1653 // This matches the order of glibc.libs
1654 try argv.append("-lm");1654 try argv.appendSlice(&[_][]const u8{
1655 try argv.append("--end-group");1655 "-lm",
1656 } else {1656 "-lpthread",
1657 try argv.append("-lc");1657 "-lc",
1658 try argv.append("-lm");1658 "-ldl",
1659 }1659 "-lrt",
16601660 "-lutil",
1661 if (target.os.tag == .freebsd or target.os.tag == .netbsd or target.os.tag == .openbsd) {1661 });
1662 try argv.append("-lpthread");1662 if (needs_grouping) try argv.append("--end-group");
1663 }
1664 } else if (target.isGnuLibC()) {1663 } else if (target.isGnuLibC()) {
1665 try argv.append(comp.libunwind_static_lib.?.full_object_path);1664 try argv.append(comp.libunwind_static_lib.?.full_object_path);
1666 for (glibc.libs) |lib| {1665 for (glibc.libs) |lib| {
src/link/MachO.zig+4-1
...@@ -442,6 +442,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {...@@ -442,6 +442,7 @@ pub fn flushModule(self: *MachO, comp: *Compilation) !void {
442 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;442 const text_segment = self.load_commands.items[self.text_segment_cmd_index.?].Segment;
443 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;443 const main_cmd = &self.load_commands.items[self.main_cmd_index.?].Main;
444 main_cmd.entryoff = addr - text_segment.inner.vmaddr;444 main_cmd.entryoff = addr - text_segment.inner.vmaddr;
445 main_cmd.stacksize = self.base.options.stack_size_override orelse 0;
445 self.load_commands_dirty = true;446 self.load_commands_dirty = true;
446 }447 }
447 try self.writeRebaseInfoTable();448 try self.writeRebaseInfoTable();
...@@ -695,7 +696,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {...@@ -695,7 +696,9 @@ fn linkWithLLD(self: *MachO, comp: *Compilation) !void {
695 Compilation.dump_argv(argv.items);696 Compilation.dump_argv(argv.items);
696 }697 }
697698
698 try zld.link(input_files.items, full_out_path);699 try zld.link(input_files.items, full_out_path, .{
700 .stack_size = self.base.options.stack_size_override,
701 });
699702
700 break :outer;703 break :outer;
701 }704 }
src/link/MachO/Zld.zig+15-3
...@@ -29,6 +29,10 @@ page_size: ?u16 = null,...@@ -29,6 +29,10 @@ page_size: ?u16 = null,
29file: ?fs.File = null,29file: ?fs.File = null,
30out_path: ?[]const u8 = null,30out_path: ?[]const u8 = null,
3131
32// TODO these args will become obselete once Zld is coalesced with incremental
33// linker.
34stack_size: u64 = 0,
35
32objects: std.ArrayListUnmanaged(*Object) = .{},36objects: std.ArrayListUnmanaged(*Object) = .{},
33archives: std.ArrayListUnmanaged(*Archive) = .{},37archives: std.ArrayListUnmanaged(*Archive) = .{},
3438
...@@ -172,7 +176,11 @@ pub fn closeFiles(self: Zld) void {...@@ -172,7 +176,11 @@ pub fn closeFiles(self: Zld) void {
172 if (self.file) |f| f.close();176 if (self.file) |f| f.close();
173}177}
174178
175pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {179const LinkArgs = struct {
180 stack_size: ?u64 = null,
181};
182
183pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8, args: LinkArgs) !void {
176 if (files.len == 0) return error.NoInputFiles;184 if (files.len == 0) return error.NoInputFiles;
177 if (out_path.len == 0) return error.EmptyOutputPath;185 if (out_path.len == 0) return error.EmptyOutputPath;
178186
...@@ -206,6 +214,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {...@@ -206,6 +214,7 @@ pub fn link(self: *Zld, files: []const []const u8, out_path: []const u8) !void {
206 .read = true,214 .read = true,
207 .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777,215 .mode = if (std.Target.current.os.tag == .windows) 0 else 0o777,
208 });216 });
217 self.stack_size = args.stack_size orelse 0;
209218
210 try self.populateMetadata();219 try self.populateMetadata();
211 try self.parseInputFiles(files);220 try self.parseInputFiles(files);
...@@ -1533,7 +1542,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1533,7 +1542,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1533 }1542 }
1534 if (rel.target == .section) {1543 if (rel.target == .section) {
1535 const source_sect = object.sections.items[rel.target.section];1544 const source_sect = object.sections.items[rel.target.section];
1536 args.source_sect_addr = source_sect.inner.addr;1545 args.source_source_sect_addr = sect.inner.addr;
1546 args.source_target_sect_addr = source_sect.inner.addr;
1537 }1547 }
15381548
1539 rebases: {1549 rebases: {
...@@ -1588,7 +1598,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {...@@ -1588,7 +1598,8 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void {
1588 else => |tt| {1598 else => |tt| {
1589 if (tt == .signed and rel.target == .section) {1599 if (tt == .signed and rel.target == .section) {
1590 const source_sect = object.sections.items[rel.target.section];1600 const source_sect = object.sections.items[rel.target.section];
1591 args.source_sect_addr = source_sect.inner.addr;1601 args.source_source_sect_addr = sect.inner.addr;
1602 args.source_target_sect_addr = source_sect.inner.addr;
1592 }1603 }
1593 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);1604 args.target_addr = try self.relocTargetAddr(@intCast(u16, object_id), rel.target);
1594 },1605 },
...@@ -2202,6 +2213,7 @@ fn setEntryPoint(self: *Zld) !void {...@@ -2202,6 +2213,7 @@ fn setEntryPoint(self: *Zld) !void {
2202 const entry_sym = sym.cast(Symbol.Regular) orelse unreachable;2213 const entry_sym = sym.cast(Symbol.Regular) orelse unreachable;
2203 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;2214 const ec = &self.load_commands.items[self.main_cmd_index.?].Main;
2204 ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr);2215 ec.entryoff = @intCast(u32, entry_sym.address - seg.inner.vmaddr);
2216 ec.stacksize = self.stack_size;
2205}2217}
22062218
2207fn writeRebaseInfoTable(self: *Zld) !void {2219fn writeRebaseInfoTable(self: *Zld) !void {
src/link/MachO/reloc.zig+7-4
...@@ -29,7 +29,8 @@ pub const Relocation = struct {...@@ -29,7 +29,8 @@ pub const Relocation = struct {
29 source_addr: u64,29 source_addr: u64,
30 target_addr: u64,30 target_addr: u64,
31 subtractor: ?u64 = null,31 subtractor: ?u64 = null,
32 source_sect_addr: ?u64 = null,32 source_source_sect_addr: ?u64 = null,
33 source_target_sect_addr: ?u64 = null,
33 };34 };
3435
35 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {36 pub fn resolve(base: *Relocation, args: ResolveArgs) !void {
...@@ -39,8 +40,10 @@ pub const Relocation = struct {...@@ -39,8 +40,10 @@ pub const Relocation = struct {
39 log.debug(" | target address 0x{x}", .{args.target_addr});40 log.debug(" | target address 0x{x}", .{args.target_addr});
40 if (args.subtractor) |sub|41 if (args.subtractor) |sub|
41 log.debug(" | subtractor address 0x{x}", .{sub});42 log.debug(" | subtractor address 0x{x}", .{sub});
42 if (args.source_sect_addr) |addr|43 if (args.source_source_sect_addr) |addr|
43 log.debug(" | source section address 0x{x}", .{addr});44 log.debug(" | source source section address 0x{x}", .{addr});
45 if (args.source_target_sect_addr) |addr|
46 log.debug(" | source target section address 0x{x}", .{addr});
4447
45 return switch (base.@"type") {48 return switch (base.@"type") {
46 .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args),49 .unsigned => @fieldParentPtr(Unsigned, "base", base).resolve(args),
...@@ -104,7 +107,7 @@ pub const Unsigned = struct {...@@ -104,7 +107,7 @@ pub const Unsigned = struct {
104107
105 pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void {108 pub fn resolve(unsigned: Unsigned, args: Relocation.ResolveArgs) !void {
106 const addend = if (unsigned.base.target == .section)109 const addend = if (unsigned.base.target == .section)
107 unsigned.addend - @intCast(i64, args.source_sect_addr.?)110 unsigned.addend - @intCast(i64, args.source_target_sect_addr.?)
108 else111 else
109 unsigned.addend;112 unsigned.addend;
110113
src/link/MachO/reloc/x86_64.zig+15-18
...@@ -33,16 +33,19 @@ pub const Signed = struct {...@@ -33,16 +33,19 @@ pub const Signed = struct {
33 pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {33 pub fn resolve(signed: Signed, args: Relocation.ResolveArgs) !void {
34 const target_addr = target_addr: {34 const target_addr = target_addr: {
35 if (signed.base.target == .section) {35 if (signed.base.target == .section) {
36 const source_target = @intCast(i64, signed.base.offset) + signed.addend + 4 + signed.correction;36 const source_target = @intCast(i64, args.source_source_sect_addr.?) + @intCast(i64, signed.base.offset) + signed.addend + 4;
37 const source_disp = source_target - @intCast(i64, args.source_sect_addr.?);37 const source_disp = source_target - @intCast(i64, args.source_target_sect_addr.?);
38 break :target_addr @intCast(i64, args.target_addr) + source_disp;38 break :target_addr @intCast(i64, args.target_addr) + source_disp;
39 }39 }
40 break :target_addr @intCast(i64, args.target_addr) + signed.addend;40 break :target_addr @intCast(i64, args.target_addr) + signed.addend;
41 };41 };
42 const displacement = try math.cast(i32, target_addr - @intCast(i64, args.source_addr) - signed.correction - 4);42 const displacement = try math.cast(
43 i32,
44 target_addr - @intCast(i64, args.source_addr) - signed.correction - 4,
45 );
4346
44 log.debug(" | calculated addend 0x{x}", .{signed.addend});47 log.debug(" | addend 0x{x}", .{signed.addend});
45 log.debug(" | calculated correction 0x{x}", .{signed.correction});48 log.debug(" | correction 0x{x}", .{signed.correction});
46 log.debug(" | displacement 0x{x}", .{displacement});49 log.debug(" | displacement 0x{x}", .{displacement});
4750
48 mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));51 mem.writeIntLittle(u32, signed.base.code[0..4], @bitCast(u32, displacement));
...@@ -172,20 +175,14 @@ pub const Parser = struct {...@@ -172,20 +175,14 @@ pub const Parser = struct {
172175
173 const offset = @intCast(u32, rel.r_address);176 const offset = @intCast(u32, rel.r_address);
174 const inst = parser.code[offset..][0..4];177 const inst = parser.code[offset..][0..4];
175 const addend = mem.readIntLittle(i32, inst);178 const correction: i4 = switch (rel_type) {
176179 .X86_64_RELOC_SIGNED => 0,
177 const correction: i4 = correction: {180 .X86_64_RELOC_SIGNED_1 => 1,
178 if (is_extern) break :correction 0;181 .X86_64_RELOC_SIGNED_2 => 2,
179182 .X86_64_RELOC_SIGNED_4 => 4,
180 const corr: i4 = switch (rel_type) {183 else => unreachable,
181 .X86_64_RELOC_SIGNED => 0,
182 .X86_64_RELOC_SIGNED_1 => 1,
183 .X86_64_RELOC_SIGNED_2 => 2,
184 .X86_64_RELOC_SIGNED_4 => 4,
185 else => unreachable,
186 };
187 break :correction corr;
188 };184 };
185 const addend = mem.readIntLittle(i32, inst) + correction;
189186
190 var signed = try parser.allocator.create(Signed);187 var signed = try parser.allocator.create(Signed);
191 errdefer parser.allocator.destroy(signed);188 errdefer parser.allocator.destroy(signed);
src/main.zig+9-85
...@@ -2302,7 +2302,7 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi...@@ -2302,7 +2302,7 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi
2302 defer if (enable_cache) man.deinit();2302 defer if (enable_cache) man.deinit();
23032303
2304 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects2304 man.hash.add(@as(u16, 0xb945)); // Random number to distinguish translate-c from compiling C objects
2305 _ = man.addFile(c_source_file.src_path, null) catch |err| {2305 man.hashCSource(c_source_file) catch |err| {
2306 fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });2306 fatal("unable to process '{s}': {s}", .{ c_source_file.src_path, @errorName(err) });
2307 };2307 };
23082308
...@@ -2332,12 +2332,16 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi...@@ -2332,12 +2332,16 @@ fn cmdTranslateC(comp: *Compilation, arena: *Allocator, enable_cache: bool) !voi
2332 }2332 }
23332333
2334 // Convert to null terminated args.2334 // Convert to null terminated args.
2335 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, argv.items.len + 1);2335 const clang_args_len = argv.items.len + c_source_file.extra_flags.len;
2336 new_argv_with_sentinel[argv.items.len] = null;2336 const new_argv_with_sentinel = try arena.alloc(?[*:0]const u8, clang_args_len + 1);
2337 const new_argv = new_argv_with_sentinel[0..argv.items.len :null];2337 new_argv_with_sentinel[clang_args_len] = null;
2338 const new_argv = new_argv_with_sentinel[0..clang_args_len :null];
2338 for (argv.items) |arg, i| {2339 for (argv.items) |arg, i| {
2339 new_argv[i] = try arena.dupeZ(u8, arg);2340 new_argv[i] = try arena.dupeZ(u8, arg);
2340 }2341 }
2342 for (c_source_file.extra_flags) |arg, i| {
2343 new_argv[argv.items.len + i] = try arena.dupeZ(u8, arg);
2344 }
23412345
2342 const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});2346 const c_headers_dir_path = try comp.zig_lib_directory.join(arena, &[_][]const u8{"include"});
2343 const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);2347 const c_headers_dir_path_z = try arena.dupeZ(u8, c_headers_dir_path);
...@@ -3526,88 +3530,8 @@ test "fds" {...@@ -3526,88 +3530,8 @@ test "fds" {
3526 gimmeMoreOfThoseSweetSweetFileDescriptors();3530 gimmeMoreOfThoseSweetSweetFileDescriptors();
3527}3531}
35283532
3529fn detectNativeCpuWithLLVM(
3530 arch: std.Target.Cpu.Arch,
3531 llvm_cpu_name_z: ?[*:0]const u8,
3532 llvm_cpu_features_opt: ?[*:0]const u8,
3533) !std.Target.Cpu {
3534 var result = std.Target.Cpu.baseline(arch);
3535
3536 if (llvm_cpu_name_z) |cpu_name_z| {
3537 const llvm_cpu_name = mem.spanZ(cpu_name_z);
3538
3539 for (arch.allCpuModels()) |model| {
3540 const this_llvm_name = model.llvm_name orelse continue;
3541 if (mem.eql(u8, this_llvm_name, llvm_cpu_name)) {
3542 // Here we use the non-dependencies-populated set,
3543 // so that subtracting features later in this function
3544 // affect the prepopulated set.
3545 result = std.Target.Cpu{
3546 .arch = arch,
3547 .model = model,
3548 .features = model.features,
3549 };
3550 break;
3551 }
3552 }
3553 }
3554
3555 const all_features = arch.allFeaturesList();
3556
3557 if (llvm_cpu_features_opt) |llvm_cpu_features| {
3558 var it = mem.tokenize(mem.spanZ(llvm_cpu_features), ",");
3559 while (it.next()) |decorated_llvm_feat| {
3560 var op: enum {
3561 add,
3562 sub,
3563 } = undefined;
3564 var llvm_feat: []const u8 = undefined;
3565 if (mem.startsWith(u8, decorated_llvm_feat, "+")) {
3566 op = .add;
3567 llvm_feat = decorated_llvm_feat[1..];
3568 } else if (mem.startsWith(u8, decorated_llvm_feat, "-")) {
3569 op = .sub;
3570 llvm_feat = decorated_llvm_feat[1..];
3571 } else {
3572 return error.InvalidLlvmCpuFeaturesFormat;
3573 }
3574 for (all_features) |feature, index_usize| {
3575 const this_llvm_name = feature.llvm_name orelse continue;
3576 if (mem.eql(u8, llvm_feat, this_llvm_name)) {
3577 const index = @intCast(std.Target.Cpu.Feature.Set.Index, index_usize);
3578 switch (op) {
3579 .add => result.features.addFeature(index),
3580 .sub => result.features.removeFeature(index),
3581 }
3582 break;
3583 }
3584 }
3585 }
3586 }
3587
3588 result.features.populateDependencies(all_features);
3589 return result;
3590}
3591
3592fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !std.zig.system.NativeTargetInfo {3533fn detectNativeTargetInfo(gpa: *Allocator, cross_target: std.zig.CrossTarget) !std.zig.system.NativeTargetInfo {
3593 var info = try std.zig.system.NativeTargetInfo.detect(gpa, cross_target);3534 return std.zig.system.NativeTargetInfo.detect(gpa, cross_target);
3594 if (info.cpu_detection_unimplemented) {
3595 const arch = std.Target.current.cpu.arch;
3596
3597 // We want to just use detected_info.target but implementing
3598 // CPU model & feature detection is todo so here we rely on LLVM.
3599 // https://github.com/ziglang/zig/issues/4591
3600 if (!build_options.have_llvm)
3601 fatal("CPU features detection is not yet available for {s} without LLVM extensions", .{@tagName(arch)});
3602
3603 const llvm = @import("codegen/llvm/bindings.zig");
3604 const llvm_cpu_name = llvm.GetHostCPUName();
3605 const llvm_cpu_features = llvm.GetNativeFeatures();
3606 info.target.cpu = try detectNativeCpuWithLLVM(arch, llvm_cpu_name, llvm_cpu_features);
3607 cross_target.updateCpuFeatures(&info.target.cpu.features);
3608 info.target.cpu.arch = cross_target.getCpuArch();
3609 }
3610 return info;
3611}3535}
36123536
3613/// Indicate that we are now terminating with a successful exit code.3537/// Indicate that we are now terminating with a successful exit code.
src/register_manager.zig+56-27
...@@ -1,5 +1,6 @@...@@ -1,5 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const math = std.math;2const math = std.math;
3const mem = std.mem;
3const assert = std.debug.assert;4const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
5const ir = @import("ir.zig");6const ir = @import("ir.zig");
...@@ -66,8 +67,13 @@ pub fn RegisterManager(...@@ -66,8 +67,13 @@ pub fn RegisterManager(
66 }67 }
6768
68 /// Returns `null` if all registers are allocated.69 /// Returns `null` if all registers are allocated.
69 pub fn tryAllocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ?[count]Register {70 pub fn tryAllocRegs(
70 if (self.tryAllocRegsWithoutTracking(count)) |regs| {71 self: *Self,
72 comptime count: comptime_int,
73 insts: [count]*ir.Inst,
74 exceptions: []Register,
75 ) ?[count]Register {
76 if (self.tryAllocRegsWithoutTracking(count, exceptions)) |regs| {
71 for (regs) |reg, i| {77 for (regs) |reg, i| {
72 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null78 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
73 self.registers[index] = insts[i];79 self.registers[index] = insts[i];
...@@ -81,21 +87,30 @@ pub fn RegisterManager(...@@ -81,21 +87,30 @@ pub fn RegisterManager(
81 }87 }
8288
83 /// Returns `null` if all registers are allocated.89 /// Returns `null` if all registers are allocated.
84 pub fn tryAllocReg(self: *Self, inst: *ir.Inst) ?Register {90 pub fn tryAllocReg(self: *Self, inst: *ir.Inst, exceptions: []Register) ?Register {
85 return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null;91 return if (tryAllocRegs(self, 1, .{inst}, exceptions)) |regs| regs[0] else null;
86 }92 }
8793
88 pub fn allocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ![count]Register {94 pub fn allocRegs(
95 self: *Self,
96 comptime count: comptime_int,
97 insts: [count]*ir.Inst,
98 exceptions: []Register,
99 ) ![count]Register {
89 comptime assert(count > 0 and count <= callee_preserved_regs.len);100 comptime assert(count > 0 and count <= callee_preserved_regs.len);
101 assert(count + exceptions.len <= callee_preserved_regs.len);
90102
91 return self.tryAllocRegs(count, insts) orelse blk: {103 return self.tryAllocRegs(count, insts, exceptions) orelse blk: {
92 // We'll take over the first count registers. Spill104 // We'll take over the first count registers. Spill
93 // the instructions that were previously there to a105 // the instructions that were previously there to a
94 // stack allocations.106 // stack allocations.
95 var regs: [count]Register = undefined;107 var regs: [count]Register = undefined;
96 std.mem.copy(Register, &regs, callee_preserved_regs[0..count]);108 var i: usize = 0;
109 for (callee_preserved_regs) |reg| {
110 if (i >= count) break;
111 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
112 regs[i] = reg;
97113
98 for (regs) |reg, i| {
99 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null114 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
100 if (self.isRegFree(reg)) {115 if (self.isRegFree(reg)) {
101 self.markRegUsed(reg);116 self.markRegUsed(reg);
...@@ -104,21 +119,28 @@ pub fn RegisterManager(...@@ -104,21 +119,28 @@ pub fn RegisterManager(
104 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);119 try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst);
105 }120 }
106 self.registers[index] = insts[i];121 self.registers[index] = insts[i];
122
123 i += 1;
107 }124 }
108125
109 break :blk regs;126 break :blk regs;
110 };127 };
111 }128 }
112129
113 pub fn allocReg(self: *Self, inst: *ir.Inst) !Register {130 pub fn allocReg(self: *Self, inst: *ir.Inst, exceptions: []Register) !Register {
114 return (try self.allocRegs(1, .{inst}))[0];131 return (try self.allocRegs(1, .{inst}, exceptions))[0];
115 }132 }
116133
117 /// Does not track the registers.134 /// Does not track the registers.
118 /// Returns `null` if not enough registers are free.135 /// Returns `null` if not enough registers are free.
119 pub fn tryAllocRegsWithoutTracking(self: *Self, comptime count: comptime_int) ?[count]Register {136 pub fn tryAllocRegsWithoutTracking(
137 self: *Self,
138 comptime count: comptime_int,
139 exceptions: []Register,
140 ) ?[count]Register {
120 comptime if (callee_preserved_regs.len == 0) return null;141 comptime if (callee_preserved_regs.len == 0) return null;
121 comptime assert(count > 0 and count <= callee_preserved_regs.len);142 comptime assert(count > 0 and count <= callee_preserved_regs.len);
143 assert(count + exceptions.len <= callee_preserved_regs.len);
122144
123 const free_registers = @popCount(FreeRegInt, self.free_registers);145 const free_registers = @popCount(FreeRegInt, self.free_registers);
124 if (free_registers < count) return null;146 if (free_registers < count) return null;
...@@ -127,30 +149,35 @@ pub fn RegisterManager(...@@ -127,30 +149,35 @@ pub fn RegisterManager(
127 var i: usize = 0;149 var i: usize = 0;
128 for (callee_preserved_regs) |reg| {150 for (callee_preserved_regs) |reg| {
129 if (i >= count) break;151 if (i >= count) break;
152 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
130 if (self.isRegFree(reg)) {153 if (self.isRegFree(reg)) {
131 regs[i] = reg;154 regs[i] = reg;
132 i += 1;155 i += 1;
133 }156 }
134 }157 }
135 return regs;158
159 return if (i < count) null else regs;
136 }160 }
137161
138 /// Does not track the register.162 /// Does not track the register.
139 /// Returns `null` if all registers are allocated.163 /// Returns `null` if all registers are allocated.
140 pub fn tryAllocRegWithoutTracking(self: *Self) ?Register {164 pub fn tryAllocRegWithoutTracking(self: *Self, exceptions: []Register) ?Register {
141 return if (self.tryAllocRegsWithoutTracking(1)) |regs| regs[0] else null;165 return if (self.tryAllocRegsWithoutTracking(1, exceptions)) |regs| regs[0] else null;
142 }166 }
143167
144 /// Does not track the registers168 /// Does not track the registers
145 pub fn allocRegsWithoutTracking(self: *Self, comptime count: comptime_int) ![count]Register {169 pub fn allocRegsWithoutTracking(self: *Self, comptime count: comptime_int, exceptions: []Register) ![count]Register {
146 return self.tryAllocRegsWithoutTracking(count) orelse blk: {170 return self.tryAllocRegsWithoutTracking(count, exceptions) orelse blk: {
147 // We'll take over the first count registers. Spill171 // We'll take over the first count registers. Spill
148 // the instructions that were previously there to a172 // the instructions that were previously there to a
149 // stack allocations.173 // stack allocations.
150 var regs: [count]Register = undefined;174 var regs: [count]Register = undefined;
151 std.mem.copy(Register, &regs, callee_preserved_regs[0..count]);175 var i: usize = 0;
176 for (callee_preserved_regs) |reg| {
177 if (i >= count) break;
178 if (mem.indexOfScalar(Register, exceptions, reg) != null) continue;
179 regs[i] = reg;
152180
153 for (regs) |reg, i| {
154 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null181 const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null
155 if (!self.isRegFree(reg)) {182 if (!self.isRegFree(reg)) {
156 const spilled_inst = self.registers[index].?;183 const spilled_inst = self.registers[index].?;
...@@ -158,6 +185,8 @@ pub fn RegisterManager(...@@ -158,6 +185,8 @@ pub fn RegisterManager(
158 self.registers[index] = null;185 self.registers[index] = null;
159 self.markRegFree(reg);186 self.markRegFree(reg);
160 }187 }
188
189 i += 1;
161 }190 }
162191
163 break :blk regs;192 break :blk regs;
...@@ -165,8 +194,8 @@ pub fn RegisterManager(...@@ -165,8 +194,8 @@ pub fn RegisterManager(
165 }194 }
166195
167 /// Does not track the register.196 /// Does not track the register.
168 pub fn allocRegWithoutTracking(self: *Self) !Register {197 pub fn allocRegWithoutTracking(self: *Self, exceptions: []Register) !Register {
169 return (try self.allocRegsWithoutTracking(1))[0];198 return (try self.allocRegsWithoutTracking(1, exceptions))[0];
170 }199 }
171200
172 /// Allocates the specified register with the specified201 /// Allocates the specified register with the specified
...@@ -270,9 +299,9 @@ test "tryAllocReg: no spilling" {...@@ -270,9 +299,9 @@ test "tryAllocReg: no spilling" {
270 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));299 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
271 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));300 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
272301
273 try std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction));302 try std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
274 try std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction));303 try std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
275 try std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction));304 try std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction, &.{}));
276305
277 try std.testing.expect(function.register_manager.isRegAllocated(.r2));306 try std.testing.expect(function.register_manager.isRegAllocated(.r2));
278 try std.testing.expect(function.register_manager.isRegAllocated(.r3));307 try std.testing.expect(function.register_manager.isRegAllocated(.r3));
...@@ -301,16 +330,16 @@ test "allocReg: spilling" {...@@ -301,16 +330,16 @@ test "allocReg: spilling" {
301 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));330 try std.testing.expect(!function.register_manager.isRegAllocated(.r2));
302 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));331 try std.testing.expect(!function.register_manager.isRegAllocated(.r3));
303332
304 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction));333 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
305 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));334 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
306335
307 // Spill a register336 // Spill a register
308 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction));337 try std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction, &.{}));
309 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);338 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
310339
311 // No spilling necessary340 // No spilling necessary
312 function.register_manager.freeReg(.r3);341 function.register_manager.freeReg(.r3);
313 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction));342 try std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction, &.{}));
314 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);343 try std.testing.expectEqualSlices(MockRegister, &[_]MockRegister{.r2}, function.spilled.items);
315}344}
316345
src/stage1/all_types.hpp-1
...@@ -718,7 +718,6 @@ struct AstNodeFnProto {...@@ -718,7 +718,6 @@ struct AstNodeFnProto {
718 Buf *name;718 Buf *name;
719 ZigList<AstNode *> params;719 ZigList<AstNode *> params;
720 AstNode *return_type;720 AstNode *return_type;
721 Token *return_anytype_token;
722 AstNode *fn_def_node;721 AstNode *fn_def_node;
723 // populated if this is an extern declaration722 // populated if this is an extern declaration
724 Buf *lib_name;723 Buf *lib_name;
src/stage1/analyze.cpp-13
...@@ -2125,18 +2125,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc...@@ -2125,18 +2125,6 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
2125 return g->builtin_types.entry_invalid;2125 return g->builtin_types.entry_invalid;
2126 }2126 }
21272127
2128 if (fn_proto->return_anytype_token != nullptr) {
2129 if (!calling_convention_allows_zig_types(fn_type_id.cc)) {
2130 add_node_error(g, fn_proto->return_type,
2131 buf_sprintf("return type 'anytype' not allowed in function with calling convention '%s'",
2132 calling_convention_name(fn_type_id.cc)));
2133 return g->builtin_types.entry_invalid;
2134 }
2135 add_node_error(g, proto_node,
2136 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));
2137 return g->builtin_types.entry_invalid;
2138 }
2139
2140 ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);2128 ZigType *specified_return_type = analyze_type_expr(g, child_scope, fn_proto->return_type);
2141 if (type_is_invalid(specified_return_type)) {2129 if (type_is_invalid(specified_return_type)) {
2142 fn_type_id.return_type = g->builtin_types.entry_invalid;2130 fn_type_id.return_type = g->builtin_types.entry_invalid;
...@@ -10220,4 +10208,3 @@ const char *float_op_to_name(BuiltinFnId op) {...@@ -10220,4 +10208,3 @@ const char *float_op_to_name(BuiltinFnId op) {
10220 zig_unreachable();10208 zig_unreachable();
10221 }10209 }
10222}10210}
10223
src/stage1/ast_render.cpp+6-10
...@@ -490,17 +490,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -490,17 +490,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
490 fprintf(ar->f, ")");490 fprintf(ar->f, ")");
491 }491 }
492492
493 if (node->data.fn_proto.return_anytype_token != nullptr) {493 AstNode *return_type_node = node->data.fn_proto.return_type;
494 fprintf(ar->f, "anytype");494 assert(return_type_node != nullptr);
495 } else {495 fprintf(ar->f, " ");
496 AstNode *return_type_node = node->data.fn_proto.return_type;496 if (node->data.fn_proto.auto_err_set) {
497 assert(return_type_node != nullptr);497 fprintf(ar->f, "!");
498 fprintf(ar->f, " ");
499 if (node->data.fn_proto.auto_err_set) {
500 fprintf(ar->f, "!");
501 }
502 render_node_grouped(ar, return_type_node);
503 }498 }
499 render_node_grouped(ar, return_type_node);
504 break;500 break;
505 }501 }
506 case NodeTypeFnDef:502 case NodeTypeFnDef:
src/stage1/ir.cpp+37-46
...@@ -10104,19 +10104,12 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod...@@ -10104,19 +10104,12 @@ static IrInstSrc *ir_gen_fn_proto(IrBuilderSrc *irb, Scope *parent_scope, AstNod
10104 }10104 }
1010510105
10106 IrInstSrc *return_type;10106 IrInstSrc *return_type;
10107 if (node->data.fn_proto.return_anytype_token == nullptr) {10107 if (node->data.fn_proto.return_type == nullptr) {
10108 if (node->data.fn_proto.return_type == nullptr) {10108 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
10109 return_type = ir_build_const_type(irb, parent_scope, node, irb->codegen->builtin_types.entry_void);
10110 } else {
10111 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
10112 if (return_type == irb->codegen->invalid_inst_src)
10113 return irb->codegen->invalid_inst_src;
10114 }
10115 } else {10109 } else {
10116 add_node_error(irb->codegen, node,10110 return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
10117 buf_sprintf("TODO implement inferred return types https://github.com/ziglang/zig/issues/447"));10111 if (return_type == irb->codegen->invalid_inst_src)
10118 return irb->codegen->invalid_inst_src;10112 return irb->codegen->invalid_inst_src;
10119 //return_type = nullptr;
10120 }10113 }
1012110114
10122 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args);10115 return ir_build_fn_proto(irb, parent_scope, node, param_types, align_value, callconv_value, return_type, is_var_args);
...@@ -14978,7 +14971,7 @@ static IrInstGen *ir_analyze_struct_literal_to_array(IrAnalyze *ira, IrInst* sou...@@ -14978,7 +14971,7 @@ static IrInstGen *ir_analyze_struct_literal_to_array(IrAnalyze *ira, IrInst* sou
1497814971
14979 if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown)))14972 if ((err = type_resolve(ira->codegen, wanted_type, ResolveStatusSizeKnown)))
14980 return ira->codegen->invalid_inst_gen;14973 return ira->codegen->invalid_inst_gen;
14981 14974
14982 size_t array_len = wanted_type->data.array.len;14975 size_t array_len = wanted_type->data.array.len;
14983 size_t instr_field_count = actual_type->data.structure.src_field_count;14976 size_t instr_field_count = actual_type->data.structure.src_field_count;
14984 assert(array_len == instr_field_count);14977 assert(array_len == instr_field_count);
...@@ -20953,44 +20946,42 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,...@@ -20953,44 +20946,42 @@ static IrInstGen *ir_analyze_fn_call(IrAnalyze *ira, IrInst* source_instr,
20953 inst_fn_type_id.alignment = align_bytes;20946 inst_fn_type_id.alignment = align_bytes;
20954 }20947 }
2095520948
20956 if (fn_proto_node->data.fn_proto.return_anytype_token == nullptr) {20949 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;
20957 AstNode *return_type_node = fn_proto_node->data.fn_proto.return_type;20950 ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node);
20958 ZigType *specified_return_type = ir_analyze_type_expr(ira, impl_fn->child_scope, return_type_node);20951 if (type_is_invalid(specified_return_type))
20959 if (type_is_invalid(specified_return_type))20952 return ira->codegen->invalid_inst_gen;
20960 return ira->codegen->invalid_inst_gen;
20961
20962 if(!is_valid_return_type(specified_return_type)){
20963 ErrorMsg *msg = ir_add_error(ira, source_instr,
20964 buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name)));
20965 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here"));
2096620953
20967 Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name);20954 if(!is_valid_return_type(specified_return_type)){
20968 if (tld != nullptr) {20955 ErrorMsg *msg = ir_add_error(ira, source_instr,
20969 add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here"));20956 buf_sprintf("call to generic function with %s return type '%s' not allowed", type_id_name(specified_return_type->id), buf_ptr(&specified_return_type->name)));
20970 }20957 add_error_note(ira->codegen, msg, fn_proto_node, buf_sprintf("function declared here"));
20971 return ira->codegen->invalid_inst_gen;
20972 }
2097320958
20974 if (fn_proto_node->data.fn_proto.auto_err_set) {20959 Tld *tld = find_decl(ira->codegen, &fn_entry->fndef_scope->base, &specified_return_type->name);
20975 ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);20960 if (tld != nullptr) {
20976 if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown)))20961 add_error_note(ira->codegen, msg, tld->source_node, buf_sprintf("type declared here"));
20977 return ira->codegen->invalid_inst_gen;
20978 inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
20979 } else {
20980 inst_fn_type_id.return_type = specified_return_type;
20981 }20962 }
20963 return ira->codegen->invalid_inst_gen;
20964 }
2098220965
20983 switch (type_requires_comptime(ira->codegen, specified_return_type)) {20966 if (fn_proto_node->data.fn_proto.auto_err_set) {
20984 case ReqCompTimeYes:20967 ZigType *inferred_err_set_type = get_auto_err_set_type(ira->codegen, impl_fn);
20985 // Throw out our work and call the function as if it were comptime.20968 if ((err = type_resolve(ira->codegen, specified_return_type, ResolveStatusSizeKnown)))
20986 return ir_analyze_fn_call(ira, source_instr, fn_entry, fn_type, fn_ref, first_arg_ptr,
20987 first_arg_ptr_src, CallModifierCompileTime, new_stack, new_stack_src, is_async_call_builtin,
20988 args_ptr, args_len, ret_ptr, call_result_loc);
20989 case ReqCompTimeInvalid:
20990 return ira->codegen->invalid_inst_gen;20969 return ira->codegen->invalid_inst_gen;
20991 case ReqCompTimeNo:20970 inst_fn_type_id.return_type = get_error_union_type(ira->codegen, inferred_err_set_type, specified_return_type);
20992 break;20971 } else {
20993 }20972 inst_fn_type_id.return_type = specified_return_type;
20973 }
20974
20975 switch (type_requires_comptime(ira->codegen, specified_return_type)) {
20976 case ReqCompTimeYes:
20977 // Throw out our work and call the function as if it were comptime.
20978 return ir_analyze_fn_call(ira, source_instr, fn_entry, fn_type, fn_ref, first_arg_ptr,
20979 first_arg_ptr_src, CallModifierCompileTime, new_stack, new_stack_src, is_async_call_builtin,
20980 args_ptr, args_len, ret_ptr, call_result_loc);
20981 case ReqCompTimeInvalid:
20982 return ira->codegen->invalid_inst_gen;
20983 case ReqCompTimeNo:
20984 break;
20994 }20985 }
2099520986
20996 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);20987 auto existing_entry = ira->codegen->generic_table.put_unique(generic_id, impl_fn);
src/stage1/parser.cpp+11-14
...@@ -820,21 +820,19 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {...@@ -820,21 +820,19 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
820 AstNode *align_expr = ast_parse_byte_align(pc);820 AstNode *align_expr = ast_parse_byte_align(pc);
821 AstNode *section_expr = ast_parse_link_section(pc);821 AstNode *section_expr = ast_parse_link_section(pc);
822 AstNode *callconv_expr = ast_parse_callconv(pc);822 AstNode *callconv_expr = ast_parse_callconv(pc);
823 Token *anytype = eat_token_if(pc, TokenIdKeywordAnyType);
824 Token *exmark = nullptr;823 Token *exmark = nullptr;
825 AstNode *return_type = nullptr;824 AstNode *return_type = nullptr;
826 if (anytype == nullptr) {825
827 exmark = eat_token_if(pc, TokenIdBang);826 exmark = eat_token_if(pc, TokenIdBang);
828 return_type = ast_parse_type_expr(pc);827 return_type = ast_parse_type_expr(pc);
829 if (return_type == nullptr) {828 if (return_type == nullptr) {
830 Token *next = peek_token(pc);829 Token *next = peek_token(pc);
831 ast_error(830 ast_error(
832 pc,831 pc,
833 next,832 next,
834 "expected return type (use 'void' to return nothing), found: '%s'",833 "expected return type (use 'void' to return nothing), found: '%s'",
835 token_name(next->id)834 token_name(next->id)
836 );835 );
837 }
838 }836 }
839837
840 AstNode *res = ast_create_node(pc, NodeTypeFnProto, first);838 AstNode *res = ast_create_node(pc, NodeTypeFnProto, first);
...@@ -844,7 +842,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {...@@ -844,7 +842,6 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
844 res->data.fn_proto.align_expr = align_expr;842 res->data.fn_proto.align_expr = align_expr;
845 res->data.fn_proto.section_expr = section_expr;843 res->data.fn_proto.section_expr = section_expr;
846 res->data.fn_proto.callconv_expr = callconv_expr;844 res->data.fn_proto.callconv_expr = callconv_expr;
847 res->data.fn_proto.return_anytype_token = anytype;
848 res->data.fn_proto.auto_err_set = exmark != nullptr;845 res->data.fn_proto.auto_err_set = exmark != nullptr;
849 res->data.fn_proto.return_type = return_type;846 res->data.fn_proto.return_type = return_type;
850847
src/target.zig+5-1
...@@ -24,6 +24,10 @@ pub const available_libcs = [_]ArchOsAbi{...@@ -24,6 +24,10 @@ pub const available_libcs = [_]ArchOsAbi{
24 .{ .arch = .arm, .os = .linux, .abi = .gnueabihf },24 .{ .arch = .arm, .os = .linux, .abi = .gnueabihf },
25 .{ .arch = .arm, .os = .linux, .abi = .musleabi },25 .{ .arch = .arm, .os = .linux, .abi = .musleabi },
26 .{ .arch = .arm, .os = .linux, .abi = .musleabihf },26 .{ .arch = .arm, .os = .linux, .abi = .musleabihf },
27 .{ .arch = .thumb, .os = .linux, .abi = .gnueabi },
28 .{ .arch = .thumb, .os = .linux, .abi = .gnueabihf },
29 .{ .arch = .thumb, .os = .linux, .abi = .musleabi },
30 .{ .arch = .thumb, .os = .linux, .abi = .musleabihf },
27 .{ .arch = .arm, .os = .windows, .abi = .gnu },31 .{ .arch = .arm, .os = .windows, .abi = .gnu },
28 .{ .arch = .csky, .os = .linux, .abi = .gnueabi },32 .{ .arch = .csky, .os = .linux, .abi = .gnueabi },
29 .{ .arch = .csky, .os = .linux, .abi = .gnueabihf },33 .{ .arch = .csky, .os = .linux, .abi = .gnueabihf },
...@@ -97,7 +101,7 @@ pub fn libCGenericName(target: std.Target) [:0]const u8 {...@@ -97,7 +101,7 @@ pub fn libCGenericName(target: std.Target) [:0]const u8 {
97pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {101pub fn archMuslName(arch: std.Target.Cpu.Arch) [:0]const u8 {
98 switch (arch) {102 switch (arch) {
99 .aarch64, .aarch64_be => return "aarch64",103 .aarch64, .aarch64_be => return "aarch64",
100 .arm, .armeb => return "arm",104 .arm, .armeb, .thumb, .thumbeb => return "arm",
101 .mips, .mipsel => return "mips",105 .mips, .mipsel => return "mips",
102 .mips64el, .mips64 => return "mips64",106 .mips64el, .mips64 => return "mips64",
103 .powerpc => return "powerpc",107 .powerpc => return "powerpc",
src/translate_c.zig+7-1
...@@ -447,7 +447,13 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {...@@ -447,7 +447,13 @@ fn declVisitorNamesOnly(c: *Context, decl: *const clang.Decl) Error!void {
447 // TODO https://github.com/ziglang/zig/issues/3756447 // TODO https://github.com/ziglang/zig/issues/3756
448 // TODO https://github.com/ziglang/zig/issues/1802448 // TODO https://github.com/ziglang/zig/issues/1802
449 const name = if (isZigPrimitiveType(decl_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ decl_name, c.getMangle() }) else decl_name;449 const name = if (isZigPrimitiveType(decl_name)) try std.fmt.allocPrint(c.arena, "{s}_{d}", .{ decl_name, c.getMangle() }) else decl_name;
450 try c.unnamed_typedefs.putNoClobber(c.gpa, addr, name);450 const result = try c.unnamed_typedefs.getOrPut(c.gpa, addr);
451 if (result.found_existing) {
452 // One typedef can declare multiple names.
453 // Don't put this one in `decl_table` so it's processed later.
454 return;
455 }
456 result.entry.value = name;
451 // Put this typedef in the decl_table to avoid redefinitions.457 // Put this typedef in the decl_table to avoid redefinitions.
452 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);458 try c.decl_table.putNoClobber(c.gpa, @ptrToInt(typedef_decl.getCanonicalDecl()), name);
453 }459 }
test/run_translated_c.zig+14
...@@ -1476,4 +1476,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {...@@ -1476,4 +1476,18 @@ pub fn addCases(cases: *tests.RunTranslatedCContext) void {
1476 \\ return 0;1476 \\ return 0;
1477 \\}1477 \\}
1478 , "");1478 , "");
1479
1480 cases.add("typedef with multiple names",
1481 \\#include <stdlib.h>
1482 \\typedef struct {
1483 \\ char field;
1484 \\} a_t, b_t;
1485 \\
1486 \\int main(void) {
1487 \\ a_t a = { .field = 42 };
1488 \\ b_t b = a;
1489 \\ if (b.field != 42) abort();
1490 \\ return 0;
1491 \\}
1492 , "");
1479}1493}
test/stage2/arm.zig+53
...@@ -458,4 +458,57 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -458,4 +458,57 @@ pub fn addCases(ctx: *TestContext) !void {
458 "",458 "",
459 );459 );
460 }460 }
461
462 {
463 var case = ctx.exe("spilling registers", linux_arm);
464 case.addCompareOutput(
465 \\export fn _start() noreturn {
466 \\ assert(add(3, 4) == 791);
467 \\ exit();
468 \\}
469 \\
470 \\fn add(a: u32, b: u32) u32 {
471 \\ const x: u32 = blk: {
472 \\ const c = a + b; // 7
473 \\ const d = a + c; // 10
474 \\ const e = d + b; // 14
475 \\ const f = d + e; // 24
476 \\ const g = e + f; // 38
477 \\ const h = f + g; // 62
478 \\ const i = g + h; // 100
479 \\ const j = i + d; // 110
480 \\ const k = i + j; // 210
481 \\ const l = k + c; // 217
482 \\ const m = l + d; // 227
483 \\ const n = m + e; // 241
484 \\ const o = n + f; // 265
485 \\ const p = o + g; // 303
486 \\ const q = p + h; // 365
487 \\ const r = q + i; // 465
488 \\ const s = r + j; // 575
489 \\ const t = s + k; // 785
490 \\ break :blk t;
491 \\ };
492 \\ const y = x + a; // 788
493 \\ const z = y + a; // 791
494 \\ return z;
495 \\}
496 \\
497 \\fn assert(ok: bool) void {
498 \\ if (!ok) unreachable;
499 \\}
500 \\
501 \\fn exit() noreturn {
502 \\ asm volatile ("svc #0"
503 \\ :
504 \\ : [number] "{r7}" (1),
505 \\ [arg1] "{r0}" (0)
506 \\ : "memory"
507 \\ );
508 \\ unreachable;
509 \\}
510 ,
511 "",
512 );
513 }
461}514}
test/stage2/test.zig+117-13
...@@ -318,6 +318,81 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -318,6 +318,81 @@ pub fn addCases(ctx: *TestContext) !void {
318 , &[_][]const u8{":2:15: error: incompatible types: 'bool' and 'comptime_int'"});318 , &[_][]const u8{":2:15: error: incompatible types: 'bool' and 'comptime_int'"});
319 }319 }
320320
321 {
322 var case = ctx.exe("multiplying numbers at runtime and comptime", linux_x64);
323 case.addCompareOutput(
324 \\export fn _start() noreturn {
325 \\ mul(3, 4);
326 \\
327 \\ exit();
328 \\}
329 \\
330 \\fn mul(a: u32, b: u32) void {
331 \\ if (a * b != 12) unreachable;
332 \\}
333 \\
334 \\fn exit() noreturn {
335 \\ asm volatile ("syscall"
336 \\ :
337 \\ : [number] "{rax}" (231),
338 \\ [arg1] "{rdi}" (0)
339 \\ : "rcx", "r11", "memory"
340 \\ );
341 \\ unreachable;
342 \\}
343 ,
344 "",
345 );
346 // comptime function call
347 case.addCompareOutput(
348 \\export fn _start() noreturn {
349 \\ exit();
350 \\}
351 \\
352 \\fn mul(a: u32, b: u32) u32 {
353 \\ return a * b;
354 \\}
355 \\
356 \\const x = mul(3, 4);
357 \\
358 \\fn exit() noreturn {
359 \\ asm volatile ("syscall"
360 \\ :
361 \\ : [number] "{rax}" (231),
362 \\ [arg1] "{rdi}" (x - 12)
363 \\ : "rcx", "r11", "memory"
364 \\ );
365 \\ unreachable;
366 \\}
367 ,
368 "",
369 );
370 // Inline function call
371 case.addCompareOutput(
372 \\export fn _start() noreturn {
373 \\ var x: usize = 5;
374 \\ const y = mul(2, 3, x);
375 \\ exit(y - 30);
376 \\}
377 \\
378 \\fn mul(a: usize, b: usize, c: usize) callconv(.Inline) usize {
379 \\ return a * b * c;
380 \\}
381 \\
382 \\fn exit(code: usize) noreturn {
383 \\ asm volatile ("syscall"
384 \\ :
385 \\ : [number] "{rax}" (231),
386 \\ [arg1] "{rdi}" (code)
387 \\ : "rcx", "r11", "memory"
388 \\ );
389 \\ unreachable;
390 \\}
391 ,
392 "",
393 );
394 }
395
321 {396 {
322 var case = ctx.exe("assert function", linux_x64);397 var case = ctx.exe("assert function", linux_x64);
323 case.addCompareOutput(398 case.addCompareOutput(
...@@ -700,7 +775,8 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -700,7 +775,8 @@ pub fn addCases(ctx: *TestContext) !void {
700 // Spilling registers to the stack.775 // Spilling registers to the stack.
701 case.addCompareOutput(776 case.addCompareOutput(
702 \\pub export fn _start() noreturn {777 \\pub export fn _start() noreturn {
703 \\ assert(add(3, 4) == 791);778 \\ assert(add(3, 4) == 1221);
779 \\ assert(mul(3, 4) == 21609);
704 \\780 \\
705 \\ exit();781 \\ exit();
706 \\}782 \\}
...@@ -716,19 +792,47 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -716,19 +792,47 @@ pub fn addCases(ctx: *TestContext) !void {
716 \\ const i = g + h; // 100792 \\ const i = g + h; // 100
717 \\ const j = i + d; // 110793 \\ const j = i + d; // 110
718 \\ const k = i + j; // 210794 \\ const k = i + j; // 210
719 \\ const l = k + c; // 217795 \\ const l = j + k; // 320
720 \\ const m = l + d; // 227796 \\ const m = l + c; // 327
721 \\ const n = m + e; // 241797 \\ const n = m + d; // 337
722 \\ const o = n + f; // 265798 \\ const o = n + e; // 351
723 \\ const p = o + g; // 303799 \\ const p = o + f; // 375
724 \\ const q = p + h; // 365800 \\ const q = p + g; // 413
725 \\ const r = q + i; // 465801 \\ const r = q + h; // 475
726 \\ const s = r + j; // 575802 \\ const s = r + i; // 575
727 \\ const t = s + k; // 785803 \\ const t = s + j; // 685
728 \\ break :blk t;804 \\ const u = t + k; // 895
805 \\ const v = u + l; // 1215
806 \\ break :blk v;
807 \\ };
808 \\ const y = x + a; // 1218
809 \\ const z = y + a; // 1221
810 \\ return z;
811 \\}
812 \\
813 \\fn mul(a: u32, b: u32) u32 {
814 \\ const x: u32 = blk: {
815 \\ const c = a * a * a * a; // 81
816 \\ const d = a * a * a * b; // 108
817 \\ const e = a * a * b * a; // 108
818 \\ const f = a * a * b * b; // 144
819 \\ const g = a * b * a * a; // 108
820 \\ const h = a * b * a * b; // 144
821 \\ const i = a * b * b * a; // 144
822 \\ const j = a * b * b * b; // 192
823 \\ const k = b * a * a * a; // 108
824 \\ const l = b * a * a * b; // 144
825 \\ const m = b * a * b * a; // 144
826 \\ const n = b * a * b * b; // 192
827 \\ const o = b * b * a * a; // 144
828 \\ const p = b * b * a * b; // 192
829 \\ const q = b * b * b * a; // 192
830 \\ const r = b * b * b * b; // 256
831 \\ const s = c + d + e + f + g + h + i + j + k + l + m + n + o + p + q + r; // 2401
832 \\ break :blk s;
729 \\ };833 \\ };
730 \\ const y = x + a; // 788834 \\ const y = x * a; // 7203
731 \\ const z = y + a; // 791835 \\ const z = y * a; // 21609
732 \\ return z;836 \\ return z;
733 \\}837 \\}
734 \\838 \\
test/stage2/wasm.zig+4-1
...@@ -58,7 +58,10 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -58,7 +58,10 @@ pub fn addCases(ctx: *TestContext) !void {
58 ,58 ,
59 // This is what you get when you take the bits of the IEE-75459 // This is what you get when you take the bits of the IEE-754
60 // representation of 42.0 and reinterpret them as an unsigned60 // representation of 42.0 and reinterpret them as an unsigned
61 // integer. Guess that's a bug in wasmtime.61 // integer.
62 // Bug is fixed in wasmtime v0.26 but updating to v0.26 is blocked
63 // on this issue:
64 // https://github.com/ziglang/zig/issues/8742
62 "1109917696\n",65 "1109917696\n",
63 );66 );
6467
test/tests.zig+8-9
...@@ -98,15 +98,14 @@ const test_targets = blk: {...@@ -98,15 +98,14 @@ const test_targets = blk: {
98 },98 },
99 .link_libc = true,99 .link_libc = true,
100 },100 },
101 // https://github.com/ziglang/zig/issues/4926101 TestTarget{
102 //TestTarget{102 .target = .{
103 // .target = .{103 .cpu_arch = .i386,
104 // .cpu_arch = .i386,104 .os_tag = .linux,
105 // .os_tag = .linux,105 .abi = .gnu,
106 // .abi = .gnu,106 },
107 // },107 .link_libc = true,
108 // .link_libc = true,108 },
109 //},
110109
111 TestTarget{110 TestTarget{
112 .target = .{111 .target = .{