authorgravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2018-04-10 21:46:13-04:00
committergravatar for thejoshwolfe@gmail.comJosh Wolfe <thejoshwolfe@gmail.com> 2018-04-10 21:46:13-04:00
logb553b7ab83894447d53bcdc1b5a10c7cbcd2281f
treea2614c600dfbf57d7c92cfa8268767b60eb75b91
parent0ba85ea6ff910c7a49ae036625b945c475c0f58c
parentee3e2790aa85c624fc952bc8326b82d72843bb17

Merge branch 'master' into self-hosted-parser


54 files changed, 3104 insertions(+), 1106 deletions(-)

.travis.yml+3-1
...@@ -1,9 +1,11 @@...@@ -1,9 +1,11 @@
1sudo: required
2services:
3 - docker
1os:4os:
2 - linux5 - linux
3 - osx6 - osx
4dist: trusty7dist: trusty
5osx_image: xcode8.38osx_image: xcode8.3
6sudo: required
7language: cpp9language: cpp
8before_install:10before_install:
9 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi11 - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then ci/travis_linux_before_install; fi
CMakeLists.txt+12-7
...@@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE)...@@ -5,6 +5,11 @@ if(NOT CMAKE_BUILD_TYPE)
5 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)5 "Choose the type of build, options are: Debug Release RelWithDebInfo MinSizeRel." FORCE)
6endif()6endif()
77
8if(NOT CMAKE_INSTALL_PREFIX)
9 set(CMAKE_INSTALL_PREFIX "${CMAKE_BINARY_DIR}" CACHE STRING
10 "Directory to install zig to" FORCE)
11endif()
12
8project(zig C CXX)13project(zig C CXX)
9set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})14set(CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
1015
...@@ -30,11 +35,6 @@ if(GIT_EXE)...@@ -30,11 +35,6 @@ if(GIT_EXE)
30endif()35endif()
31message("Configuring zig version ${ZIG_VERSION}")36message("Configuring zig version ${ZIG_VERSION}")
3237
33set(ZIG_LIBC_LIB_DIR "" CACHE STRING "Default native target libc directory where crt1.o can be found")
34set(ZIG_LIBC_STATIC_LIB_DIR "" CACHE STRING "Default native target libc directory where crtbeginT.o can be found")
35set(ZIG_LIBC_INCLUDE_DIR "/usr/include" CACHE STRING "Default native target libc include directory")
36set(ZIG_DYNAMIC_LINKER "" CACHE STRING "Override dynamic linker for native target")
37set(ZIG_EACH_LIB_RPATH off CACHE BOOL "Add each dynamic library to rpath for native target")
38set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")38set(ZIG_STATIC off CACHE BOOL "Attempt to build a static zig executable (not compatible with glibc)")
3939
40string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")40string(REGEX REPLACE "\\\\" "\\\\\\\\" ZIG_LIBC_LIB_DIR_ESCAPED "${ZIG_LIBC_LIB_DIR}")
...@@ -430,18 +430,24 @@ set(ZIG_STD_FILES...@@ -430,18 +430,24 @@ set(ZIG_STD_FILES
430 "crypto/sha2.zig"430 "crypto/sha2.zig"
431 "crypto/sha3.zig"431 "crypto/sha3.zig"
432 "crypto/blake2.zig"432 "crypto/blake2.zig"
433 "crypto/hmac.zig"
433 "cstr.zig"434 "cstr.zig"
434 "debug/failing_allocator.zig"435 "debug/failing_allocator.zig"
435 "debug/index.zig"436 "debug/index.zig"
436 "dwarf.zig"437 "dwarf.zig"
437 "elf.zig"438 "elf.zig"
438 "empty.zig"439 "empty.zig"
439 "endian.zig"440 "event.zig"
440 "fmt/errol/enum3.zig"441 "fmt/errol/enum3.zig"
441 "fmt/errol/index.zig"442 "fmt/errol/index.zig"
442 "fmt/errol/lookup.zig"443 "fmt/errol/lookup.zig"
443 "fmt/index.zig"444 "fmt/index.zig"
444 "hash_map.zig"445 "hash_map.zig"
446 "hash/index.zig"
447 "hash/adler.zig"
448 "hash/crc.zig"
449 "hash/fnv.zig"
450 "hash/siphash.zig"
445 "heap.zig"451 "heap.zig"
446 "index.zig"452 "index.zig"
447 "io.zig"453 "io.zig"
...@@ -502,7 +508,6 @@ set(ZIG_STD_FILES...@@ -502,7 +508,6 @@ set(ZIG_STD_FILES
502 "os/get_user_id.zig"508 "os/get_user_id.zig"
503 "os/index.zig"509 "os/index.zig"
504 "os/linux/errno.zig"510 "os/linux/errno.zig"
505 "os/linux/i386.zig"
506 "os/linux/index.zig"511 "os/linux/index.zig"
507 "os/linux/x86_64.zig"512 "os/linux/x86_64.zig"
508 "os/path.zig"513 "os/path.zig"
README.md+4-10
...@@ -138,31 +138,25 @@ libc. Create demo games using Zig....@@ -138,31 +138,25 @@ libc. Create demo games using Zig.
138138
139##### POSIX139##### POSIX
140140
141If you have gcc or clang installed, you can find out what `ZIG_LIBC_LIB_DIR`,
142`ZIG_LIBC_STATIC_LIB_DIR`, and `ZIG_LIBC_INCLUDE_DIR` should be set to
143(example below).
144
145```141```
146mkdir build142mkdir build
147cd build143cd build
148cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $(cc -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | cc -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $(cc -print-file-name=crtbegin.o))144cmake ..
149make145make
150make install146make install
151./zig build --build-file ../build.zig test147bin/zig build --build-file ../build.zig test
152```148```
153149
154##### MacOS150##### MacOS
155151
156`ZIG_LIBC_LIB_DIR` and `ZIG_LIBC_STATIC_LIB_DIR` are unused.
157
158```152```
159brew install cmake llvm@6153brew install cmake llvm@6
160brew outdated llvm@6 || brew upgrade llvm@6154brew outdated llvm@6 || brew upgrade llvm@6
161mkdir build155mkdir build
162cd build156cd build
163cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@6/ -DCMAKE_INSTALL_PREFIX=$(pwd)157cmake .. -DCMAKE_PREFIX_PATH=/usr/local/opt/llvm@6/
164make install158make install
165./zig build --build-file ../build.zig test159bin/zig build --build-file ../build.zig test
166```160```
167161
168##### Windows162##### Windows
build.zig+5
...@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {...@@ -45,6 +45,11 @@ pub fn build(b: &Builder) !void {
4545
46 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");46 var exe = b.addExecutable("zig", "src-self-hosted/main.zig");
47 exe.setBuildMode(mode);47 exe.setBuildMode(mode);
48
49 // This is for finding /lib/libz.a on alpine linux.
50 // TODO turn this into -Dextra-lib-path=/lib option
51 exe.addLibPath("/lib");
52
48 exe.addIncludeDir("src");53 exe.addIncludeDir("src");
49 exe.addIncludeDir(cmake_binary_dir);54 exe.addIncludeDir(cmake_binary_dir);
50 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");55 addCppLib(b, exe, cmake_binary_dir, "zig_cpp");
ci/appveyor/build_script.bat+1-3
...@@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_...@@ -20,9 +20,7 @@ call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_
2020
21mkdir %ZIGBUILDDIR%21mkdir %ZIGBUILDDIR%
22cd %ZIGBUILDDIR%22cd %ZIGBUILDDIR%
23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release "-DZIG_LIBC_INCLUDE_DIR=C:\Program Files (x86)\Windows Kits\10\Include\10.0.10240.0\ucrt" "-DZIG_LIBC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\bin\x64\ucrt" "-DZIG_LIBC_STATIC_LIB_DIR=C:\Program Files (x86)\Windows Kits\10\Lib\10.0.10240.0\ucrt\x64" || exit /b23cmake.exe .. -Thost=x64 -G"Visual Studio 14 2015 Win64" "-DCMAKE_INSTALL_PREFIX=%ZIGBUILDDIR%" "-DCMAKE_PREFIX_PATH=%ZIGPREFIXPATH%" -DCMAKE_BUILD_TYPE=Release || exit /b
24msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b24msbuild /p:Configuration=Release INSTALL.vcxproj || exit /b
2525
26bin\zig.exe build --build-file ..\build.zig test || exit /b26bin\zig.exe build --build-file ..\build.zig test || exit /b
27
28@echo "MSVC build succeeded"
ci/travis_linux_install+1-1
...@@ -4,4 +4,4 @@ set -x...@@ -4,4 +4,4 @@ set -x
44
5sudo apt-get remove -y llvm-*5sudo apt-get remove -y llvm-*
6sudo rm -rf /usr/local/*6sudo rm -rf /usr/local/*
7sudo apt-get install -y clang-6.0 libclang-6.0 libclang-6.0-dev llvm-6.0 llvm-6.0-dev liblld-6.0 liblld-6.0-dev cmake wine1.6-amd647sudo apt-get install -y clang-6.0 libclang-6.0 libclang-6.0-dev llvm-6.0 llvm-6.0-dev liblld-6.0 liblld-6.0-dev cmake wine1.6-amd64 s3cmd
ci/travis_linux_script+11-20
...@@ -8,25 +8,16 @@ export CXX=clang++-6.0...@@ -8,25 +8,16 @@ export CXX=clang++-6.0
8echo $PATH8echo $PATH
9mkdir build9mkdir build
10cd build10cd build
11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd) -DZIG_LIBC_LIB_DIR=$(dirname $($CC -print-file-name=crt1.o)) -DZIG_LIBC_INCLUDE_DIR=$(echo -n | $CC -E -x c - -v 2>&1 | grep -B1 "End of search list." | head -n1 | cut -c 2- | sed "s/ .*//") -DZIG_LIBC_STATIC_LIB_DIR=$(dirname $($CC -print-file-name=crtbegin.o))11cmake .. -DCMAKE_INSTALL_PREFIX=$(pwd)
12make VERBOSE=112make -j2 install
13make install
14./zig build --build-file ../build.zig test13./zig build --build-file ../build.zig test
1514
16./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc15if [ "${TRAVIS_PULL_REQUEST}" = "false" ]; then
17wine zig-cache/test.exe16 mkdir $TRAVIS_BUILD_DIR/artifacts
1817 docker run -it --mount type=bind,source="$TRAVIS_BUILD_DIR/artifacts",target=/z ziglang/static-base:llvm6-1 -j2 $TRAVIS_COMMIT
19./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-fast18 echo "access_key = $AWS_ACCESS_KEY_ID" >> ~/.s3cfg
20wine zig-cache/test.exe19 echo "secret_key = $AWS_SECRET_ACCESS_KEY" >> ~/.s3cfg
2120 s3cmd put -P $TRAVIS_BUILD_DIR/artifacts/* s3://ziglang.org/builds/
22./zig test ../test/behavior.zig --target-os windows --target-arch i386 --target-environ msvc --release-safe21 touch empty
23wine zig-cache/test.exe22 s3cmd put -P empty s3://ziglang.org/builds/zig-linux-x86_64-$TRAVIS_BRANCH.tar.xz --add-header=x-amz-website-redirect-location:/builds/$(ls $TRAVIS_BUILD_DIR/artifacts)
2423fi
25./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc
26wine64 zig-cache/test.exe
27
28#./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-fast
29#wine64 test.exe
30#
31#./zig test ../test/behavior.zig --target-os windows --target-arch x86_64 --target-environ msvc --release-safe
32#wine64 test.exe
doc/docgen.zig+1-1
...@@ -55,7 +55,7 @@ pub fn main() !void {...@@ -55,7 +55,7 @@ pub fn main() !void {
55 // TODO issue #70955 // TODO issue #709
56 // disabled to pass CI tests, but obviously we want to implement this56 // disabled to pass CI tests, but obviously we want to implement this
57 // and then remove this workaround57 // and then remove this workaround
58 if (builtin.os == builtin.Os.linux) {58 if (builtin.os != builtin.Os.windows) {
59 os.deleteTree(allocator, tmp_dir_name) catch {};59 os.deleteTree(allocator, tmp_dir_name) catch {};
60 }60 }
61 }61 }
doc/langref.html.in+40-4
...@@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C };...@@ -1947,8 +1947,24 @@ const Foo = extern enum { A, B, C };
1947export fn entry(foo: Foo) void { }1947export fn entry(foo: Foo) void { }
1948 {#code_end#}1948 {#code_end#}
1949 {#header_close#}1949 {#header_close#}
1950 <p>TODO packed enum</p>1950 {#header_open|packed enum#}
1951 {#see_also|@memberName|@memberCount|@tagName#}1951 <p>By default, the size of enums is not guaranteed.</p>
1952 <p><code>packed enum</code> causes the size of the enum to be the same as the size of the integer tag type
1953 of the enum:</p>
1954 {#code_begin|test#}
1955const std = @import("std");
1956
1957test "packed enum" {
1958 const Number = packed enum(u8) {
1959 One,
1960 Two,
1961 Three,
1962 };
1963 std.debug.assert(@sizeOf(Number) == @sizeOf(u8));
1964}
1965 {#code_end#}
1966 {#header_close#}
1967 {#see_also|@memberName|@memberCount|@tagName|@sizeOf#}
1952 {#header_close#}1968 {#header_close#}
1953 {#header_open|union#}1969 {#header_open|union#}
1954 {#code_begin|test|union#}1970 {#code_begin|test|union#}
...@@ -2017,7 +2033,27 @@ test "union variant switch" {...@@ -2017,7 +2033,27 @@ test "union variant switch" {
2017 assert(mem.eql(u8, what_is_it, "this is a number"));2033 assert(mem.eql(u8, what_is_it, "this is a number"));
2018}2034}
20192035
2020// TODO union methods2036// Unions can have methods just like structs and enums:
2037
2038const Variant = union(enum) {
2039 Int: i32,
2040 Bool: bool,
2041
2042 fn truthy(self: &const Variant) bool {
2043 return switch (*self) {
2044 Variant.Int => |x_int| x_int != 0,
2045 Variant.Bool => |x_bool| x_bool,
2046 };
2047 }
2048};
2049
2050test "union method" {
2051 var v1 = Variant { .Int = 1 };
2052 var v2 = Variant { .Bool = false };
2053
2054 assert(v1.truthy());
2055 assert(!v2.truthy());
2056}
20212057
20222058
2023const Small = union {2059const Small = union {
...@@ -2873,7 +2909,7 @@ const err = (error {FileNotFound}).FileNotFound;...@@ -2873,7 +2909,7 @@ const err = (error {FileNotFound}).FileNotFound;
2873 {#header_close#}2909 {#header_close#}
2874 {#header_open|Error Union Type#}2910 {#header_open|Error Union Type#}
2875 <p>2911 <p>
2876 An error set type and normal type can be combined with the <code>!<code>2912 An error set type and normal type can be combined with the <code>!</code>
2877 binary operator to form an error union type. You are likely to use an2913 binary operator to form an error union type. You are likely to use an
2878 error union type more often than an error set type by itself.2914 error union type more often than an error set type by itself.
2879 </p>2915 </p>
example/guess_number/main.zig+7-6
...@@ -9,8 +9,6 @@ pub fn main() !void {...@@ -9,8 +9,6 @@ pub fn main() !void {
9 var stdout_file_stream = io.FileOutStream.init(&stdout_file);9 var stdout_file_stream = io.FileOutStream.init(&stdout_file);
10 const stdout = &stdout_file_stream.stream;10 const stdout = &stdout_file_stream.stream;
1111
12 var stdin_file = try io.getStdIn();
13
14 try stdout.print("Welcome to the Guess Number Game in Zig.\n");12 try stdout.print("Welcome to the Guess Number Game in Zig.\n");
1513
16 var seed_bytes: [@sizeOf(u64)]u8 = undefined;14 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
...@@ -27,12 +25,15 @@ pub fn main() !void {...@@ -27,12 +25,15 @@ pub fn main() !void {
27 try stdout.print("\nGuess a number between 1 and 100: ");25 try stdout.print("\nGuess a number between 1 and 100: ");
28 var line_buf : [20]u8 = undefined;26 var line_buf : [20]u8 = undefined;
2927
30 const line_len = stdin_file.read(line_buf[0..]) catch |err| {28 const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
31 try stdout.print("Unable to read from stdin: {}\n", @errorName(err));29 error.InputTooLong => {
32 return err;30 try stdout.print("Input too long.\n");
31 continue;
32 },
33 error.EndOfFile, error.StdInUnavailable => return err,
33 };34 };
3435
35 const guess = fmt.parseUnsigned(u8, line_buf[0..line_len - 1], 10) catch {36 const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch {
36 try stdout.print("Invalid number.\n");37 try stdout.print("Invalid number.\n");
37 continue;38 continue;
38 };39 };
src-self-hosted/main.zig+1
...@@ -741,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {...@@ -741,6 +741,7 @@ fn fmtMain(allocator: &mem.Allocator, file_paths: []const []const u8) !void {
741 defer baf.destroy();741 defer baf.destroy();
742742
743 try parser.renderSource(baf.stream(), tree.root_node);743 try parser.renderSource(baf.stream(), tree.root_node);
744 try baf.finish();
744 }745 }
745}746}
746747
src/all_types.hpp+32-12
...@@ -359,7 +359,6 @@ enum NodeType {...@@ -359,7 +359,6 @@ enum NodeType {
359 NodeTypeRoot,359 NodeTypeRoot,
360 NodeTypeFnProto,360 NodeTypeFnProto,
361 NodeTypeFnDef,361 NodeTypeFnDef,
362 NodeTypeFnDecl,
363 NodeTypeParamDecl,362 NodeTypeParamDecl,
364 NodeTypeBlock,363 NodeTypeBlock,
365 NodeTypeGroupedExpr,364 NodeTypeGroupedExpr,
...@@ -453,10 +452,6 @@ struct AstNodeFnDef {...@@ -453,10 +452,6 @@ struct AstNodeFnDef {
453 AstNode *body;452 AstNode *body;
454};453};
455454
456struct AstNodeFnDecl {
457 AstNode *fn_proto;
458};
459
460struct AstNodeParamDecl {455struct AstNodeParamDecl {
461 Buf *name;456 Buf *name;
462 AstNode *type;457 AstNode *type;
...@@ -713,10 +708,6 @@ struct AstNodeSwitchRange {...@@ -713,10 +708,6 @@ struct AstNodeSwitchRange {
713 AstNode *end;708 AstNode *end;
714};709};
715710
716struct AstNodeLabel {
717 Buf *name;
718};
719
720struct AstNodeCompTime {711struct AstNodeCompTime {
721 AstNode *expr;712 AstNode *expr;
722};713};
...@@ -892,7 +883,6 @@ struct AstNode {...@@ -892,7 +883,6 @@ struct AstNode {
892 union {883 union {
893 AstNodeRoot root;884 AstNodeRoot root;
894 AstNodeFnDef fn_def;885 AstNodeFnDef fn_def;
895 AstNodeFnDecl fn_decl;
896 AstNodeFnProto fn_proto;886 AstNodeFnProto fn_proto;
897 AstNodeParamDecl param_decl;887 AstNodeParamDecl param_decl;
898 AstNodeBlock block;888 AstNodeBlock block;
...@@ -917,7 +907,6 @@ struct AstNode {...@@ -917,7 +907,6 @@ struct AstNode {
917 AstNodeSwitchExpr switch_expr;907 AstNodeSwitchExpr switch_expr;
918 AstNodeSwitchProng switch_prong;908 AstNodeSwitchProng switch_prong;
919 AstNodeSwitchRange switch_range;909 AstNodeSwitchRange switch_range;
920 AstNodeLabel label;
921 AstNodeCompTime comptime_expr;910 AstNodeCompTime comptime_expr;
922 AstNodeAsmExpr asm_expr;911 AstNodeAsmExpr asm_expr;
923 AstNodeFieldAccessExpr field_access_expr;912 AstNodeFieldAccessExpr field_access_expr;
...@@ -1656,6 +1645,8 @@ struct CodeGen {...@@ -1656,6 +1645,8 @@ struct CodeGen {
1656 LLVMValueRef coro_save_fn_val;1645 LLVMValueRef coro_save_fn_val;
1657 LLVMValueRef coro_promise_fn_val;1646 LLVMValueRef coro_promise_fn_val;
1658 LLVMValueRef coro_alloc_helper_fn_val;1647 LLVMValueRef coro_alloc_helper_fn_val;
1648 LLVMValueRef merge_err_ret_traces_fn_val;
1649 LLVMValueRef add_error_return_trace_addr_fn_val;
1659 bool error_during_imports;1650 bool error_during_imports;
16601651
1661 const char **clang_argv;1652 const char **clang_argv;
...@@ -2054,6 +2045,8 @@ enum IrInstructionId {...@@ -2054,6 +2045,8 @@ enum IrInstructionId {
2054 IrInstructionIdAwaitBookkeeping,2045 IrInstructionIdAwaitBookkeeping,
2055 IrInstructionIdSaveErrRetAddr,2046 IrInstructionIdSaveErrRetAddr,
2056 IrInstructionIdAddImplicitReturnType,2047 IrInstructionIdAddImplicitReturnType,
2048 IrInstructionIdMergeErrRetTraces,
2049 IrInstructionIdMarkErrRetTracePtr,
2057};2050};
20582051
2059struct IrInstruction {2052struct IrInstruction {
...@@ -2892,6 +2885,11 @@ struct IrInstructionExport {...@@ -2892,6 +2885,11 @@ struct IrInstructionExport {
28922885
2893struct IrInstructionErrorReturnTrace {2886struct IrInstructionErrorReturnTrace {
2894 IrInstruction base;2887 IrInstruction base;
2888
2889 enum Nullable {
2890 Null,
2891 NonNull,
2892 } nullable;
2895};2893};
28962894
2897struct IrInstructionErrorUnion {2895struct IrInstructionErrorUnion {
...@@ -3024,6 +3022,20 @@ struct IrInstructionAddImplicitReturnType {...@@ -3024,6 +3022,20 @@ struct IrInstructionAddImplicitReturnType {
3024 IrInstruction *value;3022 IrInstruction *value;
3025};3023};
30263024
3025struct IrInstructionMergeErrRetTraces {
3026 IrInstruction base;
3027
3028 IrInstruction *coro_promise_ptr;
3029 IrInstruction *src_err_ret_trace_ptr;
3030 IrInstruction *dest_err_ret_trace_ptr;
3031};
3032
3033struct IrInstructionMarkErrRetTracePtr {
3034 IrInstruction base;
3035
3036 IrInstruction *err_ret_trace_ptr;
3037};
3038
3027static const size_t slice_ptr_index = 0;3039static const size_t slice_ptr_index = 0;
3028static const size_t slice_len_index = 1;3040static const size_t slice_len_index = 1;
30293041
...@@ -3033,10 +3045,18 @@ static const size_t maybe_null_index = 1;...@@ -3033,10 +3045,18 @@ static const size_t maybe_null_index = 1;
3033static const size_t err_union_err_index = 0;3045static const size_t err_union_err_index = 0;
3034static const size_t err_union_payload_index = 1;3046static const size_t err_union_payload_index = 1;
30353047
3048// TODO call graph analysis to find out what this number needs to be for every function
3049static const size_t stack_trace_ptr_count = 30;
3050
3051// these belong to the async function
3052#define RETURN_ADDRESSES_FIELD_NAME "return_addresses"
3053#define ERR_RET_TRACE_FIELD_NAME "err_ret_trace"
3054#define RESULT_FIELD_NAME "result"
3036#define ASYNC_ALLOC_FIELD_NAME "allocFn"3055#define ASYNC_ALLOC_FIELD_NAME "allocFn"
3037#define ASYNC_FREE_FIELD_NAME "freeFn"3056#define ASYNC_FREE_FIELD_NAME "freeFn"
3038#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"3057#define AWAITER_HANDLE_FIELD_NAME "awaiter_handle"
3039#define RESULT_FIELD_NAME "result"3058// these point to data belonging to the awaiter
3059#define ERR_RET_TRACE_PTR_FIELD_NAME "err_ret_trace_ptr"
3040#define RESULT_PTR_FIELD_NAME "result_ptr"3060#define RESULT_PTR_FIELD_NAME "result_ptr"
30413061
30423062
src/analyze.cpp+132-12
...@@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)...@@ -468,10 +468,30 @@ TypeTableEntry *get_promise_frame_type(CodeGen *g, TypeTableEntry *return_type)
468468
469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);469 TypeTableEntry *awaiter_handle_type = get_maybe_type(g, g->builtin_types.entry_promise);
470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);470 TypeTableEntry *result_ptr_type = get_pointer_to_type(g, return_type, false);
471 const char *field_names[] = {AWAITER_HANDLE_FIELD_NAME, RESULT_FIELD_NAME, RESULT_PTR_FIELD_NAME};471
472 TypeTableEntry *field_types[] = {awaiter_handle_type, return_type, result_ptr_type};472 ZigList<const char *> field_names = {};
473 field_names.append(AWAITER_HANDLE_FIELD_NAME);
474 field_names.append(RESULT_FIELD_NAME);
475 field_names.append(RESULT_PTR_FIELD_NAME);
476 if (g->have_err_ret_tracing) {
477 field_names.append(ERR_RET_TRACE_PTR_FIELD_NAME);
478 field_names.append(ERR_RET_TRACE_FIELD_NAME);
479 field_names.append(RETURN_ADDRESSES_FIELD_NAME);
480 }
481
482 ZigList<TypeTableEntry *> field_types = {};
483 field_types.append(awaiter_handle_type);
484 field_types.append(return_type);
485 field_types.append(result_ptr_type);
486 if (g->have_err_ret_tracing) {
487 field_types.append(get_ptr_to_stack_trace_type(g));
488 field_types.append(g->stack_trace_type);
489 field_types.append(get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count));
490 }
491
492 assert(field_names.length == field_types.length);
473 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));493 Buf *name = buf_sprintf("AsyncFramePromise(%s)", buf_ptr(&return_type->name));
474 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names, field_types, 3);494 TypeTableEntry *entry = get_struct_type(g, buf_ptr(name), field_names.items, field_types.items, field_names.length);
475495
476 return_type->promise_frame_parent = entry;496 return_type->promise_frame_parent = entry;
477 return entry;497 return entry;
...@@ -3216,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {...@@ -3216,7 +3236,6 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
3216 break;3236 break;
3217 case NodeTypeContainerDecl:3237 case NodeTypeContainerDecl:
3218 case NodeTypeParamDecl:3238 case NodeTypeParamDecl:
3219 case NodeTypeFnDecl:
3220 case NodeTypeReturnExpr:3239 case NodeTypeReturnExpr:
3221 case NodeTypeDefer:3240 case NodeTypeDefer:
3222 case NodeTypeBlock:3241 case NodeTypeBlock:
...@@ -4285,24 +4304,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {...@@ -4285,24 +4304,118 @@ static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
4285 return g->win_sdk;4304 return g->win_sdk;
4286}4305}
42874306
4307
4308Buf *get_linux_libc_lib_path(const char *o_file) {
4309 const char *cc_exe = getenv("CC");
4310 cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
4311 ZigList<const char *> args = {};
4312 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", o_file)));
4313 Termination term;
4314 Buf *out_stderr = buf_alloc();
4315 Buf *out_stdout = buf_alloc();
4316 int err;
4317 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
4318 zig_panic("unable to determine libc lib path: executing C compiler: %s", err_str(err));
4319 }
4320 if (term.how != TerminationIdClean || term.code != 0) {
4321 zig_panic("unable to determine libc lib path: executing C compiler command failed");
4322 }
4323 if (buf_ends_with_str(out_stdout, "\n")) {
4324 buf_resize(out_stdout, buf_len(out_stdout) - 1);
4325 }
4326 if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, o_file)) {
4327 zig_panic("unable to determine libc lib path: C compiler could not find %s", o_file);
4328 }
4329 Buf *result = buf_alloc();
4330 os_path_dirname(out_stdout, result);
4331 return result;
4332}
4333
4334Buf *get_linux_libc_include_path(void) {
4335 const char *cc_exe = getenv("CC");
4336 cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
4337 ZigList<const char *> args = {};
4338 args.append("-E");
4339 args.append("-Wp,-v");
4340 args.append("-xc");
4341 args.append("/dev/null");
4342 Termination term;
4343 Buf *out_stderr = buf_alloc();
4344 Buf *out_stdout = buf_alloc();
4345 int err;
4346 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
4347 zig_panic("unable to determine libc include path: executing C compiler: %s", err_str(err));
4348 }
4349 if (term.how != TerminationIdClean || term.code != 0) {
4350 zig_panic("unable to determine libc include path: executing C compiler command failed");
4351 }
4352 char *prev_newline = buf_ptr(out_stderr);
4353 ZigList<const char *> search_paths = {};
4354 bool found_search_paths = false;
4355 for (;;) {
4356 char *newline = strchr(prev_newline, '\n');
4357 if (newline == nullptr) {
4358 zig_panic("unable to determine libc include path: bad output from C compiler command");
4359 }
4360 *newline = 0;
4361 if (found_search_paths) {
4362 if (strcmp(prev_newline, "End of search list.") == 0) {
4363 break;
4364 }
4365 search_paths.append(prev_newline);
4366 } else {
4367 if (strcmp(prev_newline, "#include <...> search starts here:") == 0) {
4368 found_search_paths = true;
4369 }
4370 }
4371 prev_newline = newline + 1;
4372 }
4373 if (search_paths.length == 0) {
4374 zig_panic("unable to determine libc include path: even C compiler does not know where libc headers are");
4375 }
4376 for (size_t i = 0; i < search_paths.length; i += 1) {
4377 // search in reverse order
4378 const char *search_path = search_paths.items[search_paths.length - i - 1];
4379 // cut off spaces
4380 while (*search_path == ' ') {
4381 search_path += 1;
4382 }
4383 Buf *stdlib_path = buf_sprintf("%s/stdlib.h", search_path);
4384 bool exists;
4385 if ((err = os_file_exists(stdlib_path, &exists))) {
4386 exists = false;
4387 }
4388 if (exists) {
4389 return buf_create_from_str(search_path);
4390 }
4391 }
4392 zig_panic("unable to determine libc include path: stdlib.h not found in C compiler search paths");
4393}
4394
4288void find_libc_include_path(CodeGen *g) {4395void find_libc_include_path(CodeGen *g) {
4289 if (!g->libc_include_dir || buf_len(g->libc_include_dir) == 0) {4396 if (g->libc_include_dir == nullptr) {
42904397
4291 if (g->zig_target.os == OsWindows) {4398 if (g->zig_target.os == OsWindows) {
4292 ZigWindowsSDK *sdk = get_windows_sdk(g);4399 ZigWindowsSDK *sdk = get_windows_sdk(g);
4400 g->libc_include_dir = buf_alloc();
4293 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {4401 if (os_get_win32_ucrt_include_path(sdk, g->libc_include_dir)) {
4294 zig_panic("Unable to determine libc include path.");4402 zig_panic("Unable to determine libc include path.");
4295 }4403 }
4404 } else if (g->zig_target.os == OsLinux) {
4405 g->libc_include_dir = get_linux_libc_include_path();
4406 } else if (g->zig_target.os == OsMacOSX) {
4407 g->libc_include_dir = buf_create_from_str("/usr/include");
4408 } else {
4409 // TODO find libc at runtime for other operating systems
4410 zig_panic("Unable to determine libc include path.");
4296 }4411 }
4297
4298 // TODO find libc at runtime for other operating systems
4299 zig_panic("Unable to determine libc include path.");
4300 }4412 }
4413 assert(buf_len(g->libc_include_dir) != 0);
4301}4414}
43024415
4303void find_libc_lib_path(CodeGen *g) {4416void find_libc_lib_path(CodeGen *g) {
4304 // later we can handle this better by reporting an error via the normal mechanism4417 // later we can handle this better by reporting an error via the normal mechanism
4305 if (!g->libc_lib_dir || buf_len(g->libc_lib_dir) == 0 ||4418 if (g->libc_lib_dir == nullptr ||
4306 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))4419 (g->zig_target.os == OsWindows && (g->msvc_lib_dir == nullptr || g->kernel32_lib_dir == nullptr)))
4307 {4420 {
4308 if (g->zig_target.os == OsWindows) {4421 if (g->zig_target.os == OsWindows) {
...@@ -4326,18 +4439,25 @@ void find_libc_lib_path(CodeGen *g) {...@@ -4326,18 +4439,25 @@ void find_libc_lib_path(CodeGen *g) {
4326 g->msvc_lib_dir = vc_lib_dir;4439 g->msvc_lib_dir = vc_lib_dir;
4327 g->libc_lib_dir = ucrt_lib_path;4440 g->libc_lib_dir = ucrt_lib_path;
4328 g->kernel32_lib_dir = kern_lib_path;4441 g->kernel32_lib_dir = kern_lib_path;
4442 } else if (g->zig_target.os == OsLinux) {
4443 g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
4329 } else {4444 } else {
4330 zig_panic("Unable to determine libc lib path.");4445 zig_panic("Unable to determine libc lib path.");
4331 }4446 }
4447 } else {
4448 assert(buf_len(g->libc_lib_dir) != 0);
4332 }4449 }
43334450
4334 if (!g->libc_static_lib_dir || buf_len(g->libc_static_lib_dir) == 0) {4451 if (g->libc_static_lib_dir == nullptr) {
4335 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {4452 if ((g->zig_target.os == OsWindows) && (g->msvc_lib_dir != NULL)) {
4336 return;4453 return;
4337 }4454 } else if (g->zig_target.os == OsLinux) {
4338 else {4455 g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
4456 } else {
4339 zig_panic("Unable to determine libc static lib path.");4457 zig_panic("Unable to determine libc static lib path.");
4340 }4458 }
4459 } else {
4460 assert(buf_len(g->libc_static_lib_dir) != 0);
4341 }4461 }
4342}4462}
43434463
src/ast_render.cpp-3
...@@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {...@@ -148,8 +148,6 @@ static const char *node_type_str(NodeType node_type) {
148 return "Root";148 return "Root";
149 case NodeTypeFnDef:149 case NodeTypeFnDef:
150 return "FnDef";150 return "FnDef";
151 case NodeTypeFnDecl:
152 return "FnDecl";
153 case NodeTypeFnProto:151 case NodeTypeFnProto:
154 return "FnProto";152 return "FnProto";
155 case NodeTypeParamDecl:153 case NodeTypeParamDecl:
...@@ -1098,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {...@@ -1098,7 +1096,6 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
1098 }1096 }
1099 break;1097 break;
1100 }1098 }
1101 case NodeTypeFnDecl:
1102 case NodeTypeParamDecl:1099 case NodeTypeParamDecl:
1103 case NodeTypeTestDecl:1100 case NodeTypeTestDecl:
1104 case NodeTypeStructField:1101 case NodeTypeStructField:
src/codegen.cpp+265-61
...@@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -112,10 +112,10 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
112 // that's for native compilation112 // that's for native compilation
113 g->zig_target = *target;113 g->zig_target = *target;
114 resolve_target_object_format(&g->zig_target);114 resolve_target_object_format(&g->zig_target);
115 g->dynamic_linker = buf_create_from_str("");115 g->dynamic_linker = nullptr;
116 g->libc_lib_dir = buf_create_from_str("");116 g->libc_lib_dir = nullptr;
117 g->libc_static_lib_dir = buf_create_from_str("");117 g->libc_static_lib_dir = nullptr;
118 g->libc_include_dir = buf_create_from_str("");118 g->libc_include_dir = nullptr;
119 g->msvc_lib_dir = nullptr;119 g->msvc_lib_dir = nullptr;
120 g->kernel32_lib_dir = nullptr;120 g->kernel32_lib_dir = nullptr;
121 g->each_lib_rpath = false;121 g->each_lib_rpath = false;
...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out...@@ -123,16 +123,13 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
123 // native compilation, we can rely on the configuration stuff123 // native compilation, we can rely on the configuration stuff
124 g->is_native_target = true;124 g->is_native_target = true;
125 get_native_target(&g->zig_target);125 get_native_target(&g->zig_target);
126 g->dynamic_linker = buf_create_from_str(ZIG_DYNAMIC_LINKER);126 g->dynamic_linker = nullptr; // find it at runtime
127 g->libc_lib_dir = buf_create_from_str(ZIG_LIBC_LIB_DIR);127 g->libc_lib_dir = nullptr; // find it at runtime
128 g->libc_static_lib_dir = buf_create_from_str(ZIG_LIBC_STATIC_LIB_DIR);128 g->libc_static_lib_dir = nullptr; // find it at runtime
129 g->libc_include_dir = buf_create_from_str(ZIG_LIBC_INCLUDE_DIR);129 g->libc_include_dir = nullptr; // find it at runtime
130 g->msvc_lib_dir = nullptr; // find it at runtime130 g->msvc_lib_dir = nullptr; // find it at runtime
131 g->kernel32_lib_dir = nullptr; // find it at runtime131 g->kernel32_lib_dir = nullptr; // find it at runtime
132
133#ifdef ZIG_EACH_LIB_RPATH
134 g->each_lib_rpath = true;132 g->each_lib_rpath = true;
135#endif
136133
137 if (g->zig_target.os == OsMacOSX ||134 if (g->zig_target.os == OsMacOSX ||
138 g->zig_target.os == OsIOS)135 g->zig_target.os == OsIOS)
...@@ -411,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e...@@ -411,6 +408,9 @@ static uint32_t get_err_ret_trace_arg_index(CodeGen *g, FnTableEntry *fn_table_e
411 if (!g->have_err_ret_tracing) {408 if (!g->have_err_ret_tracing) {
412 return UINT32_MAX;409 return UINT32_MAX;
413 }410 }
411 if (fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync) {
412 return 0;
413 }
414 TypeTableEntry *fn_type = fn_table_entry->type_entry;414 TypeTableEntry *fn_type = fn_table_entry->type_entry;
415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {415 if (!fn_type_can_fail(&fn_type->data.fn.fn_type_id)) {
416 return UINT32_MAX;416 return UINT32_MAX;
...@@ -1117,22 +1117,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {...@@ -1117,22 +1117,19 @@ static LLVMValueRef get_return_address_fn_val(CodeGen *g) {
1117 return g->return_address_fn_val;1117 return g->return_address_fn_val;
1118}1118}
11191119
1120static LLVMValueRef get_return_err_fn(CodeGen *g) {1120static LLVMValueRef get_add_error_return_trace_addr_fn(CodeGen *g) {
1121 if (g->return_err_fn != nullptr)1121 if (g->add_error_return_trace_addr_fn_val != nullptr)
1122 return g->return_err_fn;1122 return g->add_error_return_trace_addr_fn_val;
1123
1124 assert(g->err_tag_type != nullptr);
11251123
1126 LLVMTypeRef arg_types[] = {1124 LLVMTypeRef arg_types[] = {
1127 // error return trace pointer
1128 get_ptr_to_stack_trace_type(g)->type_ref,1125 get_ptr_to_stack_trace_type(g)->type_ref,
1126 g->builtin_types.entry_usize->type_ref,
1129 };1127 };
1130 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);1128 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 2, false);
11311129
1132 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);1130 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_add_err_ret_trace_addr"), false);
1133 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);1131 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1134 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address1132 addLLVMFnAttr(fn_val, "alwaysinline");
1135 addLLVMFnAttr(fn_val, "cold");
1136 LLVMSetLinkage(fn_val, LLVMInternalLinkage);1133 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1137 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));1134 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1138 addLLVMFnAttr(fn_val, "nounwind");1135 addLLVMFnAttr(fn_val, "nounwind");
...@@ -1154,6 +1151,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1154,6 +1151,8 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1154 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;1151 // stack_trace.instruction_addresses[stack_trace.index % stack_trace.instruction_addresses.len] = return_address;
11551152
1156 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);1153 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1154 LLVMValueRef address_value = LLVMGetParam(fn_val, 1);
1155
1157 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;1156 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1158 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");1157 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, err_ret_trace_ptr, (unsigned)index_field_index, "");
1159 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;1158 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
...@@ -1175,15 +1174,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1175,15 +1174,10 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1175 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");1174 LLVMValueRef ptr_value = gen_load_untyped(g, ptr_field_ptr, 0, false, "");
1176 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");1175 LLVMValueRef address_slot = LLVMBuildInBoundsGEP(g->builder, ptr_value, address_indices, 1, "");
11771176
1178 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1179 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1180 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1181
1182 LLVMValueRef address_value = LLVMBuildPtrToInt(g->builder, return_address, usize_type_ref, "");
1183 gen_store_untyped(g, address_value, address_slot, 0, false);1177 gen_store_untyped(g, address_value, address_slot, 0, false);
11841178
1185 // stack_trace.index += 1;1179 // stack_trace.index += 1;
1186 LLVMValueRef index_plus_one_val = LLVMBuildAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");1180 LLVMValueRef index_plus_one_val = LLVMBuildNUWAdd(g->builder, index_val, LLVMConstInt(usize_type_ref, 1, false), "");
1187 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);1181 gen_store_untyped(g, index_plus_one_val, index_field_ptr, 0, false);
11881182
1189 // return;1183 // return;
...@@ -1192,6 +1186,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {...@@ -1192,6 +1186,187 @@ static LLVMValueRef get_return_err_fn(CodeGen *g) {
1192 LLVMPositionBuilderAtEnd(g->builder, prev_block);1186 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1193 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);1187 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
11941188
1189 g->add_error_return_trace_addr_fn_val = fn_val;
1190 return fn_val;
1191}
1192
1193static LLVMValueRef get_merge_err_ret_traces_fn_val(CodeGen *g) {
1194 if (g->merge_err_ret_traces_fn_val)
1195 return g->merge_err_ret_traces_fn_val;
1196
1197 assert(g->stack_trace_type != nullptr);
1198
1199 LLVMTypeRef param_types[] = {
1200 get_ptr_to_stack_trace_type(g)->type_ref,
1201 get_ptr_to_stack_trace_type(g)->type_ref,
1202 };
1203 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), param_types, 2, false);
1204
1205 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_merge_error_return_traces"), false);
1206 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1207 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1208 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1209 addLLVMFnAttr(fn_val, "nounwind");
1210 add_uwtable_attr(g, fn_val);
1211 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1212 addLLVMArgAttr(fn_val, (unsigned)0, "noalias");
1213 addLLVMArgAttr(fn_val, (unsigned)0, "writeonly");
1214 addLLVMArgAttr(fn_val, (unsigned)1, "nonnull");
1215 addLLVMArgAttr(fn_val, (unsigned)1, "noalias");
1216 addLLVMArgAttr(fn_val, (unsigned)1, "readonly");
1217 if (g->build_mode == BuildModeDebug) {
1218 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1219 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1220 }
1221
1222 // this is above the ZigLLVMClearCurrentDebugLocation
1223 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1224
1225 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1226 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1227 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1228 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1229 ZigLLVMClearCurrentDebugLocation(g->builder);
1230
1231 // var frame_index: usize = undefined;
1232 // var frames_left: usize = undefined;
1233 // if (src_stack_trace.index < src_stack_trace.instruction_addresses.len) {
1234 // frame_index = 0;
1235 // frames_left = src_stack_trace.index;
1236 // if (frames_left == 0) return;
1237 // } else {
1238 // frame_index = (src_stack_trace.index + 1) % src_stack_trace.instruction_addresses.len;
1239 // frames_left = src_stack_trace.instruction_addresses.len;
1240 // }
1241 // while (true) {
1242 // __zig_add_err_ret_trace_addr(dest_stack_trace, src_stack_trace.instruction_addresses[frame_index]);
1243 // frames_left -= 1;
1244 // if (frames_left == 0) return;
1245 // frame_index = (frame_index + 1) % src_stack_trace.instruction_addresses.len;
1246 // }
1247 LLVMBasicBlockRef return_block = LLVMAppendBasicBlock(fn_val, "Return");
1248
1249 LLVMValueRef frame_index_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frame_index");
1250 LLVMValueRef frames_left_ptr = LLVMBuildAlloca(g->builder, g->builtin_types.entry_usize->type_ref, "frames_left");
1251
1252 LLVMValueRef dest_stack_trace_ptr = LLVMGetParam(fn_val, 0);
1253 LLVMValueRef src_stack_trace_ptr = LLVMGetParam(fn_val, 1);
1254
1255 size_t src_index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
1256 size_t src_addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
1257 LLVMValueRef src_index_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1258 (unsigned)src_index_field_index, "");
1259 LLVMValueRef src_addresses_field_ptr = LLVMBuildStructGEP(g->builder, src_stack_trace_ptr,
1260 (unsigned)src_addresses_field_index, "");
1261 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
1262 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
1263 LLVMValueRef src_ptr_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)ptr_field_index, "");
1264 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
1265 LLVMValueRef src_len_field_ptr = LLVMBuildStructGEP(g->builder, src_addresses_field_ptr, (unsigned)len_field_index, "");
1266 LLVMValueRef src_index_val = LLVMBuildLoad(g->builder, src_index_field_ptr, "");
1267 LLVMValueRef src_ptr_val = LLVMBuildLoad(g->builder, src_ptr_field_ptr, "");
1268 LLVMValueRef src_len_val = LLVMBuildLoad(g->builder, src_len_field_ptr, "");
1269 LLVMValueRef no_wrap_bit = LLVMBuildICmp(g->builder, LLVMIntULT, src_index_val, src_len_val, "");
1270 LLVMBasicBlockRef no_wrap_block = LLVMAppendBasicBlock(fn_val, "NoWrap");
1271 LLVMBasicBlockRef yes_wrap_block = LLVMAppendBasicBlock(fn_val, "YesWrap");
1272 LLVMBasicBlockRef loop_block = LLVMAppendBasicBlock(fn_val, "Loop");
1273 LLVMBuildCondBr(g->builder, no_wrap_bit, no_wrap_block, yes_wrap_block);
1274
1275 LLVMPositionBuilderAtEnd(g->builder, no_wrap_block);
1276 LLVMValueRef usize_zero = LLVMConstNull(g->builtin_types.entry_usize->type_ref);
1277 LLVMBuildStore(g->builder, usize_zero, frame_index_ptr);
1278 LLVMBuildStore(g->builder, src_index_val, frames_left_ptr);
1279 LLVMValueRef frames_left_eq_zero_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, src_index_val, usize_zero, "");
1280 LLVMBuildCondBr(g->builder, frames_left_eq_zero_bit, return_block, loop_block);
1281
1282 LLVMPositionBuilderAtEnd(g->builder, yes_wrap_block);
1283 LLVMValueRef usize_one = LLVMConstInt(g->builtin_types.entry_usize->type_ref, 1, false);
1284 LLVMValueRef plus_one = LLVMBuildNUWAdd(g->builder, src_index_val, usize_one, "");
1285 LLVMValueRef mod_len = LLVMBuildURem(g->builder, plus_one, src_len_val, "");
1286 LLVMBuildStore(g->builder, mod_len, frame_index_ptr);
1287 LLVMBuildStore(g->builder, src_len_val, frames_left_ptr);
1288 LLVMBuildBr(g->builder, loop_block);
1289
1290 LLVMPositionBuilderAtEnd(g->builder, loop_block);
1291 LLVMValueRef ptr_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1292 LLVMValueRef addr_ptr = LLVMBuildInBoundsGEP(g->builder, src_ptr_val, &ptr_index, 1, "");
1293 LLVMValueRef this_addr_val = LLVMBuildLoad(g->builder, addr_ptr, "");
1294 LLVMValueRef args[] = {dest_stack_trace_ptr, this_addr_val};
1295 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1296 LLVMValueRef prev_frames_left = LLVMBuildLoad(g->builder, frames_left_ptr, "");
1297 LLVMValueRef new_frames_left = LLVMBuildNUWSub(g->builder, prev_frames_left, usize_one, "");
1298 LLVMValueRef done_bit = LLVMBuildICmp(g->builder, LLVMIntEQ, new_frames_left, usize_zero, "");
1299 LLVMBasicBlockRef continue_block = LLVMAppendBasicBlock(fn_val, "Continue");
1300 LLVMBuildCondBr(g->builder, done_bit, return_block, continue_block);
1301
1302 LLVMPositionBuilderAtEnd(g->builder, return_block);
1303 LLVMBuildRetVoid(g->builder);
1304
1305 LLVMPositionBuilderAtEnd(g->builder, continue_block);
1306 LLVMBuildStore(g->builder, new_frames_left, frames_left_ptr);
1307 LLVMValueRef prev_index = LLVMBuildLoad(g->builder, frame_index_ptr, "");
1308 LLVMValueRef index_plus_one = LLVMBuildNUWAdd(g->builder, prev_index, usize_one, "");
1309 LLVMValueRef index_mod_len = LLVMBuildURem(g->builder, index_plus_one, src_len_val, "");
1310 LLVMBuildStore(g->builder, index_mod_len, frame_index_ptr);
1311 LLVMBuildBr(g->builder, loop_block);
1312
1313 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1314 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1315
1316 g->merge_err_ret_traces_fn_val = fn_val;
1317 return fn_val;
1318
1319}
1320
1321static LLVMValueRef get_return_err_fn(CodeGen *g) {
1322 if (g->return_err_fn != nullptr)
1323 return g->return_err_fn;
1324
1325 assert(g->err_tag_type != nullptr);
1326
1327 LLVMTypeRef arg_types[] = {
1328 // error return trace pointer
1329 get_ptr_to_stack_trace_type(g)->type_ref,
1330 };
1331 LLVMTypeRef fn_type_ref = LLVMFunctionType(LLVMVoidType(), arg_types, 1, false);
1332
1333 Buf *fn_name = get_mangled_name(g, buf_create_from_str("__zig_return_error"), false);
1334 LLVMValueRef fn_val = LLVMAddFunction(g->module, buf_ptr(fn_name), fn_type_ref);
1335 addLLVMFnAttr(fn_val, "noinline"); // so that we can look at return address
1336 addLLVMFnAttr(fn_val, "cold");
1337 LLVMSetLinkage(fn_val, LLVMInternalLinkage);
1338 LLVMSetFunctionCallConv(fn_val, get_llvm_cc(g, CallingConventionUnspecified));
1339 addLLVMFnAttr(fn_val, "nounwind");
1340 add_uwtable_attr(g, fn_val);
1341 addLLVMArgAttr(fn_val, (unsigned)0, "nonnull");
1342 if (g->build_mode == BuildModeDebug) {
1343 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim", "true");
1344 ZigLLVMAddFunctionAttr(fn_val, "no-frame-pointer-elim-non-leaf", nullptr);
1345 }
1346
1347 // this is above the ZigLLVMClearCurrentDebugLocation
1348 LLVMValueRef add_error_return_trace_addr_fn_val = get_add_error_return_trace_addr_fn(g);
1349
1350 LLVMBasicBlockRef entry_block = LLVMAppendBasicBlock(fn_val, "Entry");
1351 LLVMBasicBlockRef prev_block = LLVMGetInsertBlock(g->builder);
1352 LLVMValueRef prev_debug_location = LLVMGetCurrentDebugLocation(g->builder);
1353 LLVMPositionBuilderAtEnd(g->builder, entry_block);
1354 ZigLLVMClearCurrentDebugLocation(g->builder);
1355
1356 LLVMValueRef err_ret_trace_ptr = LLVMGetParam(fn_val, 0);
1357
1358 LLVMTypeRef usize_type_ref = g->builtin_types.entry_usize->type_ref;
1359 LLVMValueRef zero = LLVMConstNull(g->builtin_types.entry_i32->type_ref);
1360 LLVMValueRef return_address_ptr = LLVMBuildCall(g->builder, get_return_address_fn_val(g), &zero, 1, "");
1361 LLVMValueRef return_address = LLVMBuildPtrToInt(g->builder, return_address_ptr, usize_type_ref, "");
1362
1363 LLVMValueRef args[] = { err_ret_trace_ptr, return_address };
1364 ZigLLVMBuildCall(g->builder, add_error_return_trace_addr_fn_val, args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAlways, "");
1365 LLVMBuildRetVoid(g->builder);
1366
1367 LLVMPositionBuilderAtEnd(g->builder, prev_block);
1368 LLVMSetCurrentDebugLocation(g->builder, prev_debug_location);
1369
1195 g->return_err_fn = fn_val;1370 g->return_err_fn = fn_val;
1196 return fn_val;1371 return fn_val;
1197}1372}
...@@ -1644,7 +1819,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut...@@ -1644,7 +1819,6 @@ static LLVMValueRef ir_render_save_err_ret_addr(CodeGen *g, IrExecutable *execut
1644 };1819 };
1645 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,1820 LLVMValueRef call_instruction = ZigLLVMBuildCall(g->builder, return_err_fn, args, 1,
1646 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");1821 get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
1647 LLVMSetTailCall(call_instruction, true);
1648 return call_instruction;1822 return call_instruction;
1649}1823}
16501824
...@@ -4207,6 +4381,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,...@@ -4207,6 +4381,27 @@ static LLVMValueRef ir_render_atomic_rmw(CodeGen *g, IrExecutable *executable,
4207 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");4381 return LLVMBuildIntToPtr(g->builder, uncasted_result, operand_type->type_ref, "");
4208}4382}
42094383
4384static LLVMValueRef ir_render_merge_err_ret_traces(CodeGen *g, IrExecutable *executable,
4385 IrInstructionMergeErrRetTraces *instruction)
4386{
4387 assert(g->have_err_ret_tracing);
4388
4389 LLVMValueRef src_trace_ptr = ir_llvm_value(g, instruction->src_err_ret_trace_ptr);
4390 LLVMValueRef dest_trace_ptr = ir_llvm_value(g, instruction->dest_err_ret_trace_ptr);
4391
4392 LLVMValueRef args[] = { dest_trace_ptr, src_trace_ptr };
4393 ZigLLVMBuildCall(g->builder, get_merge_err_ret_traces_fn_val(g), args, 2, get_llvm_cc(g, CallingConventionUnspecified), ZigLLVM_FnInlineAuto, "");
4394 return nullptr;
4395}
4396
4397static LLVMValueRef ir_render_mark_err_ret_trace_ptr(CodeGen *g, IrExecutable *executable,
4398 IrInstructionMarkErrRetTracePtr *instruction)
4399{
4400 assert(g->have_err_ret_tracing);
4401 g->cur_err_ret_trace_val_stack = ir_llvm_value(g, instruction->err_ret_trace_ptr);
4402 return nullptr;
4403}
4404
4210static void set_debug_location(CodeGen *g, IrInstruction *instruction) {4405static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
4211 AstNode *source_node = instruction->source_node;4406 AstNode *source_node = instruction->source_node;
4212 Scope *scope = instruction->scope;4407 Scope *scope = instruction->scope;
...@@ -4424,6 +4619,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -4424,6 +4619,10 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
4424 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);4619 return ir_render_atomic_rmw(g, executable, (IrInstructionAtomicRmw *)instruction);
4425 case IrInstructionIdSaveErrRetAddr:4620 case IrInstructionIdSaveErrRetAddr:
4426 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);4621 return ir_render_save_err_ret_addr(g, executable, (IrInstructionSaveErrRetAddr *)instruction);
4622 case IrInstructionIdMergeErrRetTraces:
4623 return ir_render_merge_err_ret_traces(g, executable, (IrInstructionMergeErrRetTraces *)instruction);
4624 case IrInstructionIdMarkErrRetTracePtr:
4625 return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
4427 }4626 }
4428 zig_unreachable();4627 zig_unreachable();
4429}4628}
...@@ -5313,38 +5512,14 @@ static void do_code_gen(CodeGen *g) {...@@ -5313,38 +5512,14 @@ static void do_code_gen(CodeGen *g) {
5313 g->cur_err_ret_trace_val_arg = nullptr;5512 g->cur_err_ret_trace_val_arg = nullptr;
5314 }5513 }
53155514
5515 // error return tracing setup
5316 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;5516 bool is_async = fn_table_entry->type_entry->data.fn.fn_type_id.cc == CallingConventionAsync;
5317 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn &&5517 bool have_err_ret_trace_stack = g->have_err_ret_tracing && fn_table_entry->calls_or_awaits_errorable_fn && !is_async && !have_err_ret_trace_arg;
5318 (is_async || !have_err_ret_trace_arg);5518 LLVMValueRef err_ret_array_val = nullptr;
5319 if (have_err_ret_trace_stack) {5519 if (have_err_ret_trace_stack) {
5320 // TODO call graph analysis to find out what this number needs to be for every function5520 TypeTableEntry *array_type = get_array_type(g, g->builtin_types.entry_usize, stack_trace_ptr_count);
5321 static const size_t stack_trace_ptr_count = 30;5521 err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses", get_abi_alignment(g, array_type));
5322
5323 TypeTableEntry *usize = g->builtin_types.entry_usize;
5324 TypeTableEntry *array_type = get_array_type(g, usize, stack_trace_ptr_count);
5325 LLVMValueRef err_ret_array_val = build_alloca(g, array_type, "error_return_trace_addresses",
5326 get_abi_alignment(g, array_type));
5327 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));5522 g->cur_err_ret_trace_val_stack = build_alloca(g, g->stack_trace_type, "error_return_trace", get_abi_alignment(g, g->stack_trace_type));
5328 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5329 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5330 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5331
5332 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5333 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5334
5335 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5336 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5337 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5338 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5339 LLVMValueRef indices[] = {zero, zero};
5340 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5341 indices, 2, "");
5342 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr,
5343 get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false));
5344
5345 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5346 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5347 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5348 } else {5523 } else {
5349 g->cur_err_ret_trace_val_stack = nullptr;5524 g->cur_err_ret_trace_val_stack = nullptr;
5350 }5525 }
...@@ -5439,6 +5614,31 @@ static void do_code_gen(CodeGen *g) {...@@ -5439,6 +5614,31 @@ static void do_code_gen(CodeGen *g) {
5439 }5614 }
5440 }5615 }
54415616
5617 // finishing error return trace setup. we have to do this after all the allocas.
5618 if (have_err_ret_trace_stack) {
5619 TypeTableEntry *usize = g->builtin_types.entry_usize;
5620 size_t index_field_index = g->stack_trace_type->data.structure.fields[0].gen_index;
5621 LLVMValueRef index_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)index_field_index, "");
5622 gen_store_untyped(g, LLVMConstNull(usize->type_ref), index_field_ptr, 0, false);
5623
5624 size_t addresses_field_index = g->stack_trace_type->data.structure.fields[1].gen_index;
5625 LLVMValueRef addresses_field_ptr = LLVMBuildStructGEP(g->builder, g->cur_err_ret_trace_val_stack, (unsigned)addresses_field_index, "");
5626
5627 TypeTableEntry *slice_type = g->stack_trace_type->data.structure.fields[1].type_entry;
5628 size_t ptr_field_index = slice_type->data.structure.fields[slice_ptr_index].gen_index;
5629 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)ptr_field_index, "");
5630 LLVMValueRef zero = LLVMConstNull(usize->type_ref);
5631 LLVMValueRef indices[] = {zero, zero};
5632 LLVMValueRef err_ret_array_val_elem0_ptr = LLVMBuildInBoundsGEP(g->builder, err_ret_array_val,
5633 indices, 2, "");
5634 TypeTableEntry *ptr_ptr_usize_type = get_pointer_to_type(g, get_pointer_to_type(g, usize, false), false);
5635 gen_store(g, err_ret_array_val_elem0_ptr, ptr_field_ptr, ptr_ptr_usize_type);
5636
5637 size_t len_field_index = slice_type->data.structure.fields[slice_len_index].gen_index;
5638 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, addresses_field_ptr, (unsigned)len_field_index, "");
5639 gen_store(g, LLVMConstInt(usize->type_ref, stack_trace_ptr_count, false), len_field_ptr, get_pointer_to_type(g, usize, false));
5640 }
5641
5442 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;5642 FnTypeId *fn_type_id = &fn_table_entry->type_entry->data.fn.fn_type_id;
54435643
5444 // create debug variable declarations for parameters5644 // create debug variable declarations for parameters
...@@ -5946,6 +6146,8 @@ static void define_builtin_compile_vars(CodeGen *g) {...@@ -5946,6 +6146,8 @@ static void define_builtin_compile_vars(CodeGen *g) {
5946 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);6146 os_path_join(g->cache_dir, buf_create_from_str(builtin_zig_basename), builtin_zig_path);
5947 Buf *contents = buf_alloc();6147 Buf *contents = buf_alloc();
59486148
6149 // Modifications to this struct must be coordinated with code that does anything with
6150 // g->stack_trace_type. There are hard-coded references to the field indexes.
5949 buf_append_str(contents,6151 buf_append_str(contents,
5950 "pub const StackTrace = struct {\n"6152 "pub const StackTrace = struct {\n"
5951 " index: usize,\n"6153 " index: usize,\n"
...@@ -6210,7 +6412,9 @@ static void init(CodeGen *g) {...@@ -6210,7 +6412,9 @@ static void init(CodeGen *g) {
6210 g->builder = LLVMCreateBuilder();6412 g->builder = LLVMCreateBuilder();
6211 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);6413 g->dbuilder = ZigLLVMCreateDIBuilder(g->module, true);
62126414
6213 Buf *producer = buf_sprintf("zig %s", ZIG_VERSION_STRING);6415 // Don't use ZIG_VERSION_STRING here, llvm misparses it when it includes
6416 // the git revision.
6417 Buf *producer = buf_sprintf("zig %d.%d.%d", ZIG_VERSION_MAJOR, ZIG_VERSION_MINOR, ZIG_VERSION_PATCH);
6214 const char *flags = "";6418 const char *flags = "";
6215 unsigned runtime_version = 0;6419 unsigned runtime_version = 0;
6216 ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),6420 ZigLLVMDIFile *compile_unit_file = ZigLLVMCreateFile(g->dbuilder, buf_ptr(g->root_out_name),
...@@ -6289,7 +6493,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package...@@ -6289,7 +6493,7 @@ static ImportTableEntry *add_special_code(CodeGen *g, PackageTableEntry *package
6289 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6493 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6290 }6494 }
6291 Buf *import_code = buf_alloc();6495 Buf *import_code = buf_alloc();
6292 if ((err = os_fetch_file_path(abs_full_path, import_code))) {6496 if ((err = os_fetch_file_path(abs_full_path, import_code, false))) {
6293 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));6497 zig_panic("unable to open '%s': %s", buf_ptr(&path_to_code_src), err_str(err));
6294 }6498 }
62956499
...@@ -6377,7 +6581,7 @@ static void gen_root_source(CodeGen *g) {...@@ -6377,7 +6581,7 @@ static void gen_root_source(CodeGen *g) {
6377 }6581 }
63786582
6379 Buf *source_code = buf_alloc();6583 Buf *source_code = buf_alloc();
6380 if ((err = os_fetch_file_path(rel_full_path, source_code))) {6584 if ((err = os_fetch_file_path(rel_full_path, source_code, true))) {
6381 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));6585 zig_panic("unable to open '%s': %s", buf_ptr(rel_full_path), err_str(err));
6382 }6586 }
63836587
...@@ -6442,7 +6646,7 @@ static void gen_global_asm(CodeGen *g) {...@@ -6442,7 +6646,7 @@ static void gen_global_asm(CodeGen *g) {
6442 int err;6646 int err;
6443 for (size_t i = 0; i < g->assembly_files.length; i += 1) {6647 for (size_t i = 0; i < g->assembly_files.length; i += 1) {
6444 Buf *asm_file = g->assembly_files.at(i);6648 Buf *asm_file = g->assembly_files.at(i);
6445 if ((err = os_fetch_file_path(asm_file, &contents))) {6649 if ((err = os_fetch_file_path(asm_file, &contents, false))) {
6446 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));6650 zig_panic("Unable to read %s: %s", buf_ptr(asm_file), err_str(err));
6447 }6651 }
6448 buf_append_buf(&g->global_asm, &contents);6652 buf_append_buf(&g->global_asm, &contents);
src/config.h.in-8
...@@ -13,14 +13,6 @@...@@ -13,14 +13,6 @@
13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@13#define ZIG_VERSION_PATCH @ZIG_VERSION_PATCH@
14#define ZIG_VERSION_STRING "@ZIG_VERSION@"14#define ZIG_VERSION_STRING "@ZIG_VERSION@"
1515
16#define ZIG_INSTALL_PREFIX "@CMAKE_INSTALL_PREFIX@"
17#define ZIG_LIBC_INCLUDE_DIR "@ZIG_LIBC_INCLUDE_DIR_ESCAPED@"
18#define ZIG_LIBC_LIB_DIR "@ZIG_LIBC_LIB_DIR_ESCAPED@"
19#define ZIG_LIBC_STATIC_LIB_DIR "@ZIG_LIBC_STATIC_LIB_DIR_ESCAPED@"
20#define ZIG_DYNAMIC_LINKER "@ZIG_DYNAMIC_LINKER@"
21
22#cmakedefine ZIG_EACH_LIB_RPATH
23
24// Only used for running tests before installing.16// Only used for running tests before installing.
25#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"17#define ZIG_TEST_DIR "@CMAKE_SOURCE_DIR@/test"
2618
src/ir.cpp+190-84
...@@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur...@@ -725,6 +725,14 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionAddImplicitRetur
725 return IrInstructionIdAddImplicitReturnType;725 return IrInstructionIdAddImplicitReturnType;
726}726}
727727
728static constexpr IrInstructionId ir_instruction_id(IrInstructionMergeErrRetTraces *) {
729 return IrInstructionIdMergeErrRetTraces;
730}
731
732static constexpr IrInstructionId ir_instruction_id(IrInstructionMarkErrRetTracePtr *) {
733 return IrInstructionIdMarkErrRetTracePtr;
734}
735
728template<typename T>736template<typename T>
729static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {737static T *ir_create_instruction(IrBuilder *irb, Scope *scope, AstNode *source_node) {
730 T *special_instruction = allocate<T>(1);738 T *special_instruction = allocate<T>(1);
...@@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast...@@ -956,25 +964,6 @@ static IrInstruction *ir_build_const_c_str_lit(IrBuilder *irb, Scope *scope, Ast
956 return &const_instruction->base;964 return &const_instruction->base;
957}965}
958966
959static IrInstruction *ir_build_const_promise_init(IrBuilder *irb, Scope *scope, AstNode *source_node,
960 TypeTableEntry *return_type)
961{
962 TypeTableEntry *struct_type = get_promise_frame_type(irb->codegen, return_type);
963
964 IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, source_node);
965 const_instruction->base.value.type = struct_type;
966 const_instruction->base.value.special = ConstValSpecialStatic;
967 const_instruction->base.value.data.x_struct.fields = allocate<ConstExprValue>(struct_type->data.structure.src_field_count);
968 const_instruction->base.value.data.x_struct.fields[0].type = struct_type->data.structure.fields[0].type_entry;
969 const_instruction->base.value.data.x_struct.fields[0].special = ConstValSpecialStatic;
970 const_instruction->base.value.data.x_struct.fields[0].data.x_maybe = nullptr;
971 const_instruction->base.value.data.x_struct.fields[1].type = return_type;
972 const_instruction->base.value.data.x_struct.fields[1].special = ConstValSpecialUndef;
973 const_instruction->base.value.data.x_struct.fields[2].type = struct_type->data.structure.fields[2].type_entry;
974 const_instruction->base.value.data.x_struct.fields[2].special = ConstValSpecialUndef;
975 return &const_instruction->base;
976}
977
978static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,967static IrInstruction *ir_build_bin_op(IrBuilder *irb, Scope *scope, AstNode *source_node, IrBinOp op_id,
979 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)968 IrInstruction *op1, IrInstruction *op2, bool safety_check_on)
980{969{
...@@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s...@@ -2495,8 +2484,9 @@ static IrInstruction *ir_build_arg_type(IrBuilder *irb, Scope *scope, AstNode *s
2495 return &instruction->base;2484 return &instruction->base;
2496}2485}
24972486
2498static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node) {2487static IrInstruction *ir_build_error_return_trace(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstructionErrorReturnTrace::Nullable nullable) {
2499 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);2488 IrInstructionErrorReturnTrace *instruction = ir_build_instruction<IrInstructionErrorReturnTrace>(irb, scope, source_node);
2489 instruction->nullable = nullable;
25002490
2501 return &instruction->base;2491 return &instruction->base;
2502}2492}
...@@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s...@@ -2717,6 +2707,30 @@ static IrInstruction *ir_build_add_implicit_return_type(IrBuilder *irb, Scope *s
2717 return &instruction->base;2707 return &instruction->base;
2718}2708}
27192709
2710static IrInstruction *ir_build_merge_err_ret_traces(IrBuilder *irb, Scope *scope, AstNode *source_node,
2711 IrInstruction *coro_promise_ptr, IrInstruction *src_err_ret_trace_ptr, IrInstruction *dest_err_ret_trace_ptr)
2712{
2713 IrInstructionMergeErrRetTraces *instruction = ir_build_instruction<IrInstructionMergeErrRetTraces>(irb, scope, source_node);
2714 instruction->coro_promise_ptr = coro_promise_ptr;
2715 instruction->src_err_ret_trace_ptr = src_err_ret_trace_ptr;
2716 instruction->dest_err_ret_trace_ptr = dest_err_ret_trace_ptr;
2717
2718 ir_ref_instruction(coro_promise_ptr, irb->current_basic_block);
2719 ir_ref_instruction(src_err_ret_trace_ptr, irb->current_basic_block);
2720 ir_ref_instruction(dest_err_ret_trace_ptr, irb->current_basic_block);
2721
2722 return &instruction->base;
2723}
2724
2725static IrInstruction *ir_build_mark_err_ret_trace_ptr(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *err_ret_trace_ptr) {
2726 IrInstructionMarkErrRetTracePtr *instruction = ir_build_instruction<IrInstructionMarkErrRetTracePtr>(irb, scope, source_node);
2727 instruction->err_ret_trace_ptr = err_ret_trace_ptr;
2728
2729 ir_ref_instruction(err_ret_trace_ptr, irb->current_basic_block);
2730
2731 return &instruction->base;
2732}
2733
2720static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {2734static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
2721 results[ReturnKindUnconditional] = 0;2735 results[ReturnKindUnconditional] = 0;
2722 results[ReturnKindError] = 0;2736 results[ReturnKindError] = 0;
...@@ -2741,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {...@@ -2741,9 +2755,10 @@ static IrInstruction *ir_mark_gen(IrInstruction *instruction) {
27412755
2742static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {2756static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, bool gen_error_defers) {
2743 Scope *scope = inner_scope;2757 Scope *scope = inner_scope;
2758 bool is_noreturn = false;
2744 while (scope != outer_scope) {2759 while (scope != outer_scope) {
2745 if (!scope)2760 if (!scope)
2746 return false;2761 return is_noreturn;
27472762
2748 if (scope->id == ScopeIdDefer) {2763 if (scope->id == ScopeIdDefer) {
2749 AstNode *defer_node = scope->source_node;2764 AstNode *defer_node = scope->source_node;
...@@ -2756,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o...@@ -2756,14 +2771,18 @@ static bool ir_gen_defers_for_block(IrBuilder *irb, Scope *inner_scope, Scope *o
2756 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;2771 Scope *defer_expr_scope = defer_node->data.defer.expr_scope;
2757 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);2772 IrInstruction *defer_expr_value = ir_gen_node(irb, defer_expr_node, defer_expr_scope);
2758 if (defer_expr_value != irb->codegen->invalid_instruction) {2773 if (defer_expr_value != irb->codegen->invalid_instruction) {
2759 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));2774 if (defer_expr_value->value.type != nullptr && defer_expr_value->value.type->id == TypeTableEntryIdUnreachable) {
2775 is_noreturn = true;
2776 } else {
2777 ir_mark_gen(ir_build_check_statement_is_void(irb, defer_expr_scope, defer_expr_node, defer_expr_value));
2778 }
2760 }2779 }
2761 }2780 }
27622781
2763 }2782 }
2764 scope = scope->parent;2783 scope = scope->parent;
2765 }2784 }
2766 return true;2785 return is_noreturn;
2767}2786}
27682787
2769static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {2788static void ir_set_cursor_at_end(IrBuilder *irb, IrBasicBlock *basic_block) {
...@@ -2822,34 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode...@@ -2822,34 +2841,6 @@ static IrInstruction *ir_gen_async_return(IrBuilder *irb, Scope *scope, AstNode
2822 // the above blocks are rendered by ir_gen after the rest of codegen2841 // the above blocks are rendered by ir_gen after the rest of codegen
2823}2842}
28242843
2825static bool exec_have_err_ret_trace(CodeGen *g, IrExecutable *exec) {
2826 if (!g->have_err_ret_tracing)
2827 return false;
2828 FnTableEntry *fn_entry = exec_fn_entry(exec);
2829 if (fn_entry == nullptr)
2830 return false;
2831 if (exec->is_inline)
2832 return false;
2833 return type_can_fail(fn_entry->type_entry->data.fn.fn_type_id.return_type);
2834}
2835
2836static void ir_gen_save_err_ret_addr(IrBuilder *irb, Scope *scope, AstNode *node) {
2837 if (!exec_have_err_ret_trace(irb->codegen, irb->exec))
2838 return;
2839
2840 bool is_async = exec_is_async(irb->exec);
2841
2842 if (is_async) {
2843 //IrInstruction *err_ret_addr_ptr = ir_build_load_ptr(irb, scope, node, irb->exec->coro_err_ret_addr_ptr);
2844 //IrInstruction *return_address_ptr = ir_build_instr_addr(irb, scope, node);
2845 //IrInstruction *return_address_usize = ir_build_ptr_to_int(irb, scope, node, return_address_ptr);
2846 //ir_build_store_ptr(irb, scope, node, err_ret_addr_ptr, return_address_usize);
2847 return;
2848 }
2849
2850 ir_build_save_err_ret_addr(irb, scope, node);
2851}
2852
2853static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {2844static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node, LVal lval) {
2854 assert(node->type == NodeTypeReturnExpr);2845 assert(node->type == NodeTypeReturnExpr);
28552846
...@@ -2895,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2895,8 +2886,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
28952886
2896 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);2887 IrInstruction *is_err = ir_build_test_err(irb, scope, node, return_value);
28972888
2889 bool should_inline = ir_should_inline(irb->exec, scope);
2898 IrInstruction *is_comptime;2890 IrInstruction *is_comptime;
2899 if (ir_should_inline(irb->exec, scope)) {2891 if (should_inline) {
2900 is_comptime = ir_build_const_bool(irb, scope, node, true);2892 is_comptime = ir_build_const_bool(irb, scope, node, true);
2901 } else {2893 } else {
2902 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);2894 is_comptime = ir_build_test_comptime(irb, scope, node, is_err);
...@@ -2909,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2909,7 +2901,9 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2909 if (have_err_defers) {2901 if (have_err_defers) {
2910 ir_gen_defers_for_block(irb, scope, outer_scope, true);2902 ir_gen_defers_for_block(irb, scope, outer_scope, true);
2911 }2903 }
2912 ir_gen_save_err_ret_addr(irb, scope, node);2904 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2905 ir_build_save_err_ret_addr(irb, scope, node);
2906 }
2913 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);2907 ir_build_br(irb, scope, node, ret_stmt_block, is_comptime);
29142908
2915 ir_set_cursor_at_end_and_append_block(irb, ok_block);2909 ir_set_cursor_at_end_and_append_block(irb, ok_block);
...@@ -2938,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2938,7 +2932,8 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2938 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");2932 IrBasicBlock *return_block = ir_create_basic_block(irb, scope, "ErrRetReturn");
2939 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");2933 IrBasicBlock *continue_block = ir_create_basic_block(irb, scope, "ErrRetContinue");
2940 IrInstruction *is_comptime;2934 IrInstruction *is_comptime;
2941 if (ir_should_inline(irb->exec, scope)) {2935 bool should_inline = ir_should_inline(irb->exec, scope);
2936 if (should_inline) {
2942 is_comptime = ir_build_const_bool(irb, scope, node, true);2937 is_comptime = ir_build_const_bool(irb, scope, node, true);
2943 } else {2938 } else {
2944 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);2939 is_comptime = ir_build_test_comptime(irb, scope, node, is_err_val);
...@@ -2946,10 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,...@@ -2946,10 +2941,13 @@ static IrInstruction *ir_gen_return(IrBuilder *irb, Scope *scope, AstNode *node,
2946 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));2941 ir_mark_gen(ir_build_cond_br(irb, scope, node, is_err_val, return_block, continue_block, is_comptime));
29472942
2948 ir_set_cursor_at_end_and_append_block(irb, return_block);2943 ir_set_cursor_at_end_and_append_block(irb, return_block);
2949 ir_gen_defers_for_block(irb, scope, outer_scope, true);2944 if (!ir_gen_defers_for_block(irb, scope, outer_scope, true)) {
2950 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);2945 IrInstruction *err_val = ir_build_unwrap_err_code(irb, scope, node, err_union_ptr);
2951 ir_gen_save_err_ret_addr(irb, scope, node);2946 if (irb->codegen->have_err_ret_tracing && !should_inline) {
2952 ir_gen_async_return(irb, scope, node, err_val, false);2947 ir_build_save_err_ret_addr(irb, scope, node);
2948 }
2949 ir_gen_async_return(irb, scope, node, err_val, false);
2950 }
29532951
2954 ir_set_cursor_at_end_and_append_block(irb, continue_block);2952 ir_set_cursor_at_end_and_append_block(irb, continue_block);
2955 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);2953 IrInstruction *unwrapped_ptr = ir_build_unwrap_err_payload(irb, scope, node, err_union_ptr, false);
...@@ -4242,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4242,7 +4240,7 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
4242 }4240 }
4243 case BuiltinFnIdErrorReturnTrace:4241 case BuiltinFnIdErrorReturnTrace:
4244 {4242 {
4245 return ir_build_error_return_trace(irb, scope, node);4243 return ir_build_error_return_trace(irb, scope, node, IrInstructionErrorReturnTrace::Null);
4246 }4244 }
4247 case BuiltinFnIdAtomicRmw:4245 case BuiltinFnIdAtomicRmw:
4248 {4246 {
...@@ -5703,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast...@@ -5703,7 +5701,7 @@ static IrInstruction *ir_gen_continue(IrBuilder *irb, Scope *continue_scope, Ast
57035701
5704 IrBasicBlock *dest_block = loop_scope->continue_block;5702 IrBasicBlock *dest_block = loop_scope->continue_block;
5705 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);5703 ir_gen_defers_for_block(irb, continue_scope, dest_block->scope, false);
5706 return ir_build_br(irb, continue_scope, node, dest_block, is_comptime);5704 return ir_mark_gen(ir_build_br(irb, continue_scope, node, dest_block, is_comptime));
5707}5705}
57085706
5709static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {5707static IrInstruction *ir_gen_error_type(IrBuilder *irb, Scope *scope, AstNode *node) {
...@@ -6125,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6125,6 +6123,13 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6125 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6123 Buf *result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6126 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);6124 IrInstruction *result_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_ptr_field_name);
61276125
6126 if (irb->codegen->have_err_ret_tracing) {
6127 IrInstruction *err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6128 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6129 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6130 ir_build_store_ptr(irb, parent_scope, node, err_ret_trace_ptr_field_ptr, err_ret_trace_ptr);
6131 }
6132
6128 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6133 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6129 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,6134 IrInstruction *awaiter_field_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr,
6130 awaiter_handle_field_name);6135 awaiter_handle_field_name);
...@@ -6148,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6148,10 +6153,16 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
6148 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);6153 IrInstruction *is_non_null = ir_build_test_nonnull(irb, parent_scope, node, maybe_await_handle);
6149 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");6154 IrBasicBlock *yes_suspend_block = ir_create_basic_block(irb, parent_scope, "YesSuspend");
6150 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");6155 IrBasicBlock *no_suspend_block = ir_create_basic_block(irb, parent_scope, "NoSuspend");
6151 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "Merge");6156 IrBasicBlock *merge_block = ir_create_basic_block(irb, parent_scope, "MergeSuspend");
6152 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);6157 ir_build_cond_br(irb, parent_scope, node, is_non_null, no_suspend_block, yes_suspend_block, const_bool_false);
61536158
6154 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);6159 ir_set_cursor_at_end_and_append_block(irb, no_suspend_block);
6160 if (irb->codegen->have_err_ret_tracing) {
6161 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6162 IrInstruction *src_err_ret_trace_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, err_ret_trace_field_name);
6163 IrInstruction *dest_err_ret_trace_ptr = ir_build_error_return_trace(irb, parent_scope, node, IrInstructionErrorReturnTrace::NonNull);
6164 ir_build_merge_err_ret_traces(irb, parent_scope, node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
6165 }
6155 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6166 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6156 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);6167 IrInstruction *promise_result_ptr = ir_build_field_ptr(irb, parent_scope, node, coro_promise_ptr, result_field_name);
6157 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);6168 IrInstruction *no_suspend_result = ir_build_load_ptr(irb, parent_scope, node, promise_result_ptr);
...@@ -6173,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast...@@ -6173,7 +6184,7 @@ static IrInstruction *ir_gen_await_expr(IrBuilder *irb, Scope *parent_scope, Ast
61736184
6174 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6185 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6175 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6186 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6176 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6187 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
61776188
6178 ir_set_cursor_at_end_and_append_block(irb, resume_block);6189 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6179 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);6190 IrInstruction *yes_suspend_result = ir_build_load_ptr(irb, parent_scope, node, my_result_var_ptr);
...@@ -6249,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod...@@ -6249,7 +6260,7 @@ static IrInstruction *ir_gen_suspend(IrBuilder *irb, Scope *parent_scope, AstNod
62496260
6250 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);6261 ir_set_cursor_at_end_and_append_block(irb, cleanup_block);
6251 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);6262 ir_gen_defers_for_block(irb, parent_scope, outer_scope, true);
6252 ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false);6263 ir_mark_gen(ir_build_br(irb, parent_scope, node, irb->exec->coro_final_cleanup_block, const_bool_false));
62536264
6254 ir_set_cursor_at_end_and_append_block(irb, resume_block);6265 ir_set_cursor_at_end_and_append_block(irb, resume_block);
6255 return ir_build_const_void(irb, parent_scope, node);6266 return ir_build_const_void(irb, parent_scope, node);
...@@ -6268,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -6268,7 +6279,6 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
6268 case NodeTypeSwitchRange:6279 case NodeTypeSwitchRange:
6269 case NodeTypeStructField:6280 case NodeTypeStructField:
6270 case NodeTypeFnDef:6281 case NodeTypeFnDef:
6271 case NodeTypeFnDecl:
6272 case NodeTypeTestDecl:6282 case NodeTypeTestDecl:
6273 zig_unreachable();6283 zig_unreachable();
6274 case NodeTypeBlock:6284 case NodeTypeBlock:
...@@ -6407,6 +6417,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6407,6 +6417,8 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6407 IrInstruction *coro_id;6417 IrInstruction *coro_id;
6408 IrInstruction *u8_ptr_type;6418 IrInstruction *u8_ptr_type;
6409 IrInstruction *const_bool_false;6419 IrInstruction *const_bool_false;
6420 IrInstruction *coro_promise_ptr;
6421 IrInstruction *err_ret_trace_ptr;
6410 TypeTableEntry *return_type;6422 TypeTableEntry *return_type;
6411 Buf *result_ptr_field_name;6423 Buf *result_ptr_field_name;
6412 VariableTableEntry *coro_size_var;6424 VariableTableEntry *coro_size_var;
...@@ -6417,9 +6429,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6417,9 +6429,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6417 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6429 VariableTableEntry *promise_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
64186430
6419 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;6431 return_type = fn_entry->type_entry->data.fn.fn_type_id.return_type;
6420 IrInstruction *promise_init = ir_build_const_promise_init(irb, coro_scope, node, return_type);6432 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6421 ir_build_var_decl(irb, coro_scope, node, promise_var, nullptr, nullptr, promise_init);6433 TypeTableEntry *coro_frame_type = get_promise_frame_type(irb->codegen, return_type);
6422 IrInstruction *coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);6434 IrInstruction *coro_frame_type_value = ir_build_const_type(irb, coro_scope, node, coro_frame_type);
6435 // TODO mark this var decl as "no safety" e.g. disable initializing the undef value to 0xaa
6436 ir_build_var_decl(irb, coro_scope, node, promise_var, coro_frame_type_value, nullptr, undef);
6437 coro_promise_ptr = ir_build_var_ptr(irb, coro_scope, node, promise_var, false, false);
64236438
6424 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);6439 VariableTableEntry *await_handle_var = ir_create_var(irb, node, coro_scope, nullptr, false, false, true, const_bool_false);
6425 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);6440 IrInstruction *null_value = ir_build_const_null(irb, coro_scope, node);
...@@ -6452,7 +6467,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6452,7 +6467,6 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6452 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);6467 ir_set_cursor_at_end_and_append_block(irb, alloc_err_block);
6453 // we can return undefined here, because the caller passes a pointer to the error struct field6468 // we can return undefined here, because the caller passes a pointer to the error struct field
6454 // in the error union result, and we populate it in case of allocation failure.6469 // in the error union result, and we populate it in case of allocation failure.
6455 IrInstruction *undef = ir_build_const_undefined(irb, coro_scope, node);
6456 ir_build_return(irb, coro_scope, node, undef);6470 ir_build_return(irb, coro_scope, node, undef);
64576471
6458 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);6472 ir_set_cursor_at_end_and_append_block(irb, alloc_ok_block);
...@@ -6460,13 +6474,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6460,13 +6474,35 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6460 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);6474 irb->exec->coro_handle = ir_build_coro_begin(irb, coro_scope, node, coro_id, coro_mem_ptr);
64616475
6462 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);6476 Buf *awaiter_handle_field_name = buf_create_from_str(AWAITER_HANDLE_FIELD_NAME);
6463 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr,6477 irb->exec->coro_awaiter_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr,
6464 awaiter_handle_field_name);6478 awaiter_handle_field_name);
6479 ir_build_store_ptr(irb, scope, node, irb->exec->coro_awaiter_field_ptr, null_value);
6465 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);6480 Buf *result_field_name = buf_create_from_str(RESULT_FIELD_NAME);
6466 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_field_name);6481 irb->exec->coro_result_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_field_name);
6467 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);6482 result_ptr_field_name = buf_create_from_str(RESULT_PTR_FIELD_NAME);
6468 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, coro_scope, node, coro_promise_ptr, result_ptr_field_name);6483 irb->exec->coro_result_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, result_ptr_field_name);
6469 ir_build_store_ptr(irb, coro_scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);6484 ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_ptr_field_ptr, irb->exec->coro_result_field_ptr);
6485 if (irb->codegen->have_err_ret_tracing) {
6486 // initialize the error return trace
6487 Buf *return_addresses_field_name = buf_create_from_str(RETURN_ADDRESSES_FIELD_NAME);
6488 IrInstruction *return_addresses_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, return_addresses_field_name);
6489
6490 Buf *err_ret_trace_field_name = buf_create_from_str(ERR_RET_TRACE_FIELD_NAME);
6491 err_ret_trace_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_field_name);
6492 ir_build_mark_err_ret_trace_ptr(irb, scope, node, err_ret_trace_ptr);
6493
6494 // coordinate with builtin.zig
6495 Buf *index_name = buf_create_from_str("index");
6496 IrInstruction *index_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, index_name);
6497 IrInstruction *zero = ir_build_const_usize(irb, scope, node, 0);
6498 ir_build_store_ptr(irb, scope, node, index_ptr, zero);
6499
6500 Buf *instruction_addresses_name = buf_create_from_str("instruction_addresses");
6501 IrInstruction *addrs_slice_ptr = ir_build_field_ptr(irb, scope, node, err_ret_trace_ptr, instruction_addresses_name);
6502
6503 IrInstruction *slice_value = ir_build_slice(irb, scope, node, return_addresses_ptr, zero, nullptr, false);
6504 ir_build_store_ptr(irb, scope, node, addrs_slice_ptr, slice_value);
6505 }
64706506
64716507
6472 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");6508 irb->exec->coro_early_final = ir_create_basic_block(irb, scope, "CoroEarlyFinal");
...@@ -6517,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec...@@ -6517,6 +6553,12 @@ bool ir_gen(CodeGen *codegen, AstNode *node, Scope *scope, IrExecutable *ir_exec
6517 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);6553 IrInstruction *size_of_ret_val = ir_build_size_of(irb, scope, node, return_type_inst);
6518 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);6554 ir_build_memcpy(irb, scope, node, result_ptr_as_u8_ptr, return_value_ptr_as_u8_ptr, size_of_ret_val);
6519 }6555 }
6556 if (irb->codegen->have_err_ret_tracing) {
6557 Buf *err_ret_trace_ptr_field_name = buf_create_from_str(ERR_RET_TRACE_PTR_FIELD_NAME);
6558 IrInstruction *err_ret_trace_ptr_field_ptr = ir_build_field_ptr(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr_field_name);
6559 IrInstruction *dest_err_ret_trace_ptr = ir_build_load_ptr(irb, scope, node, err_ret_trace_ptr_field_ptr);
6560 ir_build_merge_err_ret_traces(irb, scope, node, coro_promise_ptr, err_ret_trace_ptr, dest_err_ret_trace_ptr);
6561 }
6520 ir_build_br(irb, scope, node, check_free_block, const_bool_false);6562 ir_build_br(irb, scope, node, check_free_block, const_bool_false);
65216563
6522 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);6564 ir_set_cursor_at_end_and_append_block(irb, irb->exec->coro_final_cleanup_block);
...@@ -11579,18 +11621,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {...@@ -11579,18 +11621,25 @@ static bool exec_has_err_ret_trace(CodeGen *g, IrExecutable *exec) {
11579static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,11621static TypeTableEntry *ir_analyze_instruction_error_return_trace(IrAnalyze *ira,
11580 IrInstructionErrorReturnTrace *instruction)11622 IrInstructionErrorReturnTrace *instruction)
11581{11623{
11582 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);11624 if (instruction->nullable == IrInstructionErrorReturnTrace::Null) {
11583 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);11625 TypeTableEntry *ptr_to_stack_trace_type = get_ptr_to_stack_trace_type(ira->codegen);
11584 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {11626 TypeTableEntry *nullable_type = get_maybe_type(ira->codegen, ptr_to_stack_trace_type);
11585 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);11627 if (!exec_has_err_ret_trace(ira->codegen, ira->new_irb.exec)) {
11586 out_val->data.x_maybe = nullptr;11628 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
11629 out_val->data.x_maybe = nullptr;
11630 return nullable_type;
11631 }
11632 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11633 instruction->base.source_node, instruction->nullable);
11634 ir_link_new_instruction(new_instruction, &instruction->base);
11587 return nullable_type;11635 return nullable_type;
11636 } else {
11637 assert(ira->codegen->have_err_ret_tracing);
11638 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11639 instruction->base.source_node, instruction->nullable);
11640 ir_link_new_instruction(new_instruction, &instruction->base);
11641 return get_ptr_to_stack_trace_type(ira->codegen);
11588 }11642 }
11589
11590 IrInstruction *new_instruction = ir_build_error_return_trace(&ira->new_irb, instruction->base.scope,
11591 instruction->base.source_node);
11592 ir_link_new_instruction(new_instruction, &instruction->base);
11593 return nullable_type;
11594}11643}
1159511644
11596static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,11645static TypeTableEntry *ir_analyze_instruction_error_union(IrAnalyze *ira,
...@@ -13072,6 +13121,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,...@@ -13072,6 +13121,7 @@ static IrInstruction *ir_analyze_container_member_access_inner(IrAnalyze *ira,
13072{13121{
13073 if (!is_slice(bare_struct_type)) {13122 if (!is_slice(bare_struct_type)) {
13074 ScopeDecls *container_scope = get_container_scope(bare_struct_type);13123 ScopeDecls *container_scope = get_container_scope(bare_struct_type);
13124 assert(container_scope != nullptr);
13075 auto entry = container_scope->decl_table.maybe_get(field_name);13125 auto entry = container_scope->decl_table.maybe_get(field_name);
13076 Tld *tld = entry ? entry->value : nullptr;13126 Tld *tld = entry ? entry->value : nullptr;
13077 if (tld && tld->id == TldIdFn) {13127 if (tld && tld->id == TldIdFn) {
...@@ -14709,7 +14759,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi...@@ -14709,7 +14759,7 @@ static TypeTableEntry *ir_analyze_instruction_import(IrAnalyze *ira, IrInstructi
14709 return ira->codegen->builtin_types.entry_namespace;14759 return ira->codegen->builtin_types.entry_namespace;
14710 }14760 }
1471114761
14712 if ((err = os_fetch_file_path(abs_full_path, import_code))) {14762 if ((err = os_fetch_file_path(abs_full_path, import_code, true))) {
14713 if (err == ErrorFileNotFound) {14763 if (err == ErrorFileNotFound) {
14714 ir_add_error_node(ira, source_node,14764 ir_add_error_node(ira, source_node,
14715 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));14765 buf_sprintf("unable to find '%s'", buf_ptr(import_target_path)));
...@@ -15570,7 +15620,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr...@@ -15570,7 +15620,7 @@ static TypeTableEntry *ir_analyze_instruction_embed_file(IrAnalyze *ira, IrInstr
15570 // load from file system into const expr15620 // load from file system into const expr
15571 Buf *file_contents = buf_alloc();15621 Buf *file_contents = buf_alloc();
15572 int err;15622 int err;
15573 if ((err = os_fetch_file_path(&file_path, file_contents))) {15623 if ((err = os_fetch_file_path(&file_path, file_contents, false))) {
15574 if (err == ErrorFileNotFound) {15624 if (err == ErrorFileNotFound) {
15575 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));15625 ir_add_error(ira, instruction->name, buf_sprintf("unable to find '%s'", buf_ptr(&file_path)));
15576 return ira->codegen->builtin_types.entry_invalid;15626 return ira->codegen->builtin_types.entry_invalid;
...@@ -16702,6 +16752,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc...@@ -16702,6 +16752,11 @@ static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstruc
16702 return ira->codegen->builtin_types.entry_invalid;16752 return ira->codegen->builtin_types.entry_invalid;
1670316753
16704 if (fn_type_id.cc == CallingConventionAsync) {16754 if (fn_type_id.cc == CallingConventionAsync) {
16755 if (instruction->async_allocator_type_value == nullptr) {
16756 ir_add_error(ira, &instruction->base,
16757 buf_sprintf("async fn proto missing allocator type"));
16758 return ira->codegen->builtin_types.entry_invalid;
16759 }
16705 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;16760 IrInstruction *async_allocator_type_value = instruction->async_allocator_type_value->other;
16706 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);16761 fn_type_id.async_allocator_type = ir_resolve_type(ira, async_allocator_type_value);
16707 if (type_is_invalid(fn_type_id.async_allocator_type))16762 if (type_is_invalid(fn_type_id.async_allocator_type))
...@@ -17904,6 +17959,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,...@@ -17904,6 +17959,39 @@ static TypeTableEntry *ir_analyze_instruction_await_bookkeeping(IrAnalyze *ira,
17904 return out_val->type;17959 return out_val->type;
17905}17960}
1790617961
17962static TypeTableEntry *ir_analyze_instruction_merge_err_ret_traces(IrAnalyze *ira,
17963 IrInstructionMergeErrRetTraces *instruction)
17964{
17965 IrInstruction *coro_promise_ptr = instruction->coro_promise_ptr->other;
17966 if (type_is_invalid(coro_promise_ptr->value.type))
17967 return ira->codegen->builtin_types.entry_invalid;
17968
17969 assert(coro_promise_ptr->value.type->id == TypeTableEntryIdPointer);
17970 TypeTableEntry *promise_frame_type = coro_promise_ptr->value.type->data.pointer.child_type;
17971 assert(promise_frame_type->id == TypeTableEntryIdStruct);
17972 TypeTableEntry *promise_result_type = promise_frame_type->data.structure.fields[1].type_entry;
17973
17974 if (!type_can_fail(promise_result_type)) {
17975 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
17976 out_val->type = ira->codegen->builtin_types.entry_void;
17977 return out_val->type;
17978 }
17979
17980 IrInstruction *src_err_ret_trace_ptr = instruction->src_err_ret_trace_ptr->other;
17981 if (type_is_invalid(src_err_ret_trace_ptr->value.type))
17982 return ira->codegen->builtin_types.entry_invalid;
17983
17984 IrInstruction *dest_err_ret_trace_ptr = instruction->dest_err_ret_trace_ptr->other;
17985 if (type_is_invalid(dest_err_ret_trace_ptr->value.type))
17986 return ira->codegen->builtin_types.entry_invalid;
17987
17988 IrInstruction *result = ir_build_merge_err_ret_traces(&ira->new_irb, instruction->base.scope,
17989 instruction->base.source_node, coro_promise_ptr, src_err_ret_trace_ptr, dest_err_ret_trace_ptr);
17990 ir_link_new_instruction(result, &instruction->base);
17991 result->value.type = ira->codegen->builtin_types.entry_void;
17992 return result->value.type;
17993}
17994
17907static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {17995static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira, IrInstructionSaveErrRetAddr *instruction) {
17908 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,17996 IrInstruction *result = ir_build_save_err_ret_addr(&ira->new_irb, instruction->base.scope,
17909 instruction->base.source_node);17997 instruction->base.source_node);
...@@ -17912,6 +18000,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira,...@@ -17912,6 +18000,18 @@ static TypeTableEntry *ir_analyze_instruction_save_err_ret_addr(IrAnalyze *ira,
17912 return result->value.type;18000 return result->value.type;
17913}18001}
1791418002
18003static TypeTableEntry *ir_analyze_instruction_mark_err_ret_trace_ptr(IrAnalyze *ira, IrInstructionMarkErrRetTracePtr *instruction) {
18004 IrInstruction *err_ret_trace_ptr = instruction->err_ret_trace_ptr->other;
18005 if (type_is_invalid(err_ret_trace_ptr->value.type))
18006 return ira->codegen->builtin_types.entry_invalid;
18007
18008 IrInstruction *result = ir_build_mark_err_ret_trace_ptr(&ira->new_irb, instruction->base.scope,
18009 instruction->base.source_node, err_ret_trace_ptr);
18010 ir_link_new_instruction(result, &instruction->base);
18011 result->value.type = ira->codegen->builtin_types.entry_void;
18012 return result->value.type;
18013}
18014
17915static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {18015static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
17916 switch (instruction->id) {18016 switch (instruction->id) {
17917 case IrInstructionIdInvalid:18017 case IrInstructionIdInvalid:
...@@ -18155,6 +18255,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -18155,6 +18255,10 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
18155 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);18255 return ir_analyze_instruction_save_err_ret_addr(ira, (IrInstructionSaveErrRetAddr *)instruction);
18156 case IrInstructionIdAddImplicitReturnType:18256 case IrInstructionIdAddImplicitReturnType:
18157 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);18257 return ir_analyze_instruction_add_implicit_return_type(ira, (IrInstructionAddImplicitReturnType *)instruction);
18258 case IrInstructionIdMergeErrRetTraces:
18259 return ir_analyze_instruction_merge_err_ret_traces(ira, (IrInstructionMergeErrRetTraces *)instruction);
18260 case IrInstructionIdMarkErrRetTracePtr:
18261 return ir_analyze_instruction_mark_err_ret_trace_ptr(ira, (IrInstructionMarkErrRetTracePtr *)instruction);
18158 }18262 }
18159 zig_unreachable();18263 zig_unreachable();
18160}18264}
...@@ -18282,6 +18386,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -18282,6 +18386,8 @@ bool ir_has_side_effects(IrInstruction *instruction) {
18282 case IrInstructionIdAwaitBookkeeping:18386 case IrInstructionIdAwaitBookkeeping:
18283 case IrInstructionIdSaveErrRetAddr:18387 case IrInstructionIdSaveErrRetAddr:
18284 case IrInstructionIdAddImplicitReturnType:18388 case IrInstructionIdAddImplicitReturnType:
18389 case IrInstructionIdMergeErrRetTraces:
18390 case IrInstructionIdMarkErrRetTracePtr:
18285 return true;18391 return true;
1828618392
18287 case IrInstructionIdPhi:18393 case IrInstructionIdPhi:
src/ir_print.cpp+32-1
...@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {...@@ -1024,7 +1024,16 @@ static void ir_print_export(IrPrint *irp, IrInstructionExport *instruction) {
1024}1024}
10251025
1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {1026static void ir_print_error_return_trace(IrPrint *irp, IrInstructionErrorReturnTrace *instruction) {
1027 fprintf(irp->f, "@errorReturnTrace()");1027 fprintf(irp->f, "@errorReturnTrace(");
1028 switch (instruction->nullable) {
1029 case IrInstructionErrorReturnTrace::Null:
1030 fprintf(irp->f, "Null");
1031 break;
1032 case IrInstructionErrorReturnTrace::NonNull:
1033 fprintf(irp->f, "NonNull");
1034 break;
1035 }
1036 fprintf(irp->f, ")");
1028}1037}
10291038
1030static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {1039static void ir_print_error_union(IrPrint *irp, IrInstructionErrorUnion *instruction) {
...@@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl...@@ -1179,6 +1188,22 @@ static void ir_print_add_implicit_return_type(IrPrint *irp, IrInstructionAddImpl
1179 fprintf(irp->f, ")");1188 fprintf(irp->f, ")");
1180}1189}
11811190
1191static void ir_print_merge_err_ret_traces(IrPrint *irp, IrInstructionMergeErrRetTraces *instruction) {
1192 fprintf(irp->f, "@mergeErrRetTraces(");
1193 ir_print_other_instruction(irp, instruction->coro_promise_ptr);
1194 fprintf(irp->f, ",");
1195 ir_print_other_instruction(irp, instruction->src_err_ret_trace_ptr);
1196 fprintf(irp->f, ",");
1197 ir_print_other_instruction(irp, instruction->dest_err_ret_trace_ptr);
1198 fprintf(irp->f, ")");
1199}
1200
1201static void ir_print_mark_err_ret_trace_ptr(IrPrint *irp, IrInstructionMarkErrRetTracePtr *instruction) {
1202 fprintf(irp->f, "@markErrRetTracePtr(");
1203 ir_print_other_instruction(irp, instruction->err_ret_trace_ptr);
1204 fprintf(irp->f, ")");
1205}
1206
1182static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {1207static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1183 ir_print_prefix(irp, instruction);1208 ir_print_prefix(irp, instruction);
1184 switch (instruction->id) {1209 switch (instruction->id) {
...@@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1559,6 +1584,12 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1559 case IrInstructionIdAddImplicitReturnType:1584 case IrInstructionIdAddImplicitReturnType:
1560 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);1585 ir_print_add_implicit_return_type(irp, (IrInstructionAddImplicitReturnType *)instruction);
1561 break;1586 break;
1587 case IrInstructionIdMergeErrRetTraces:
1588 ir_print_merge_err_ret_traces(irp, (IrInstructionMergeErrRetTraces *)instruction);
1589 break;
1590 case IrInstructionIdMarkErrRetTracePtr:
1591 ir_print_mark_err_ret_trace_ptr(irp, (IrInstructionMarkErrRetTracePtr *)instruction);
1592 break;
1562 }1593 }
1563 fprintf(irp->f, "\n");1594 fprintf(irp->f, "\n");
1564}1595}
src/link.cpp+54-7
...@@ -164,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {...@@ -164,6 +164,47 @@ static void add_rpath(LinkJob *lj, Buf *rpath) {
164 lj->rpath_table.put(rpath, true);164 lj->rpath_table.put(rpath, true);
165}165}
166166
167static Buf *try_dynamic_linker_path(const char *ld_name) {
168 const char *cc_exe = getenv("CC");
169 cc_exe = (cc_exe == nullptr) ? "cc" : cc_exe;
170 ZigList<const char *> args = {};
171 args.append(buf_ptr(buf_sprintf("-print-file-name=%s", ld_name)));
172 Termination term;
173 Buf *out_stderr = buf_alloc();
174 Buf *out_stdout = buf_alloc();
175 int err;
176 if ((err = os_exec_process(cc_exe, args, &term, out_stderr, out_stdout))) {
177 return nullptr;
178 }
179 if (term.how != TerminationIdClean || term.code != 0) {
180 return nullptr;
181 }
182 if (buf_ends_with_str(out_stdout, "\n")) {
183 buf_resize(out_stdout, buf_len(out_stdout) - 1);
184 }
185 if (buf_len(out_stdout) == 0 || buf_eql_str(out_stdout, ld_name)) {
186 return nullptr;
187 }
188 return out_stdout;
189}
190
191static Buf *get_dynamic_linker_path(CodeGen *g) {
192 if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) {
193 static const char *ld_names[] = {
194 "ld-linux-x86-64.so.2",
195 "ld-musl-x86_64.so.1",
196 };
197 for (size_t i = 0; i < array_length(ld_names); i += 1) {
198 const char *ld_name = ld_names[i];
199 Buf *result = try_dynamic_linker_path(ld_name);
200 if (result != nullptr) {
201 return result;
202 }
203 }
204 }
205 return target_dynamic_linker(&g->zig_target);
206}
207
167static void construct_linker_job_elf(LinkJob *lj) {208static void construct_linker_job_elf(LinkJob *lj) {
168 CodeGen *g = lj->codegen;209 CodeGen *g = lj->codegen;
169210
...@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -259,12 +300,16 @@ static void construct_linker_job_elf(LinkJob *lj) {
259 lj->args.append(buf_ptr(g->libc_static_lib_dir));300 lj->args.append(buf_ptr(g->libc_static_lib_dir));
260 }301 }
261302
262 if (g->dynamic_linker && buf_len(g->dynamic_linker) > 0) {303 if (!g->is_static) {
263 lj->args.append("-dynamic-linker");304 if (g->dynamic_linker != nullptr) {
264 lj->args.append(buf_ptr(g->dynamic_linker));305 assert(buf_len(g->dynamic_linker) != 0);
265 } else {306 lj->args.append("-dynamic-linker");
266 lj->args.append("-dynamic-linker");307 lj->args.append(buf_ptr(g->dynamic_linker));
267 lj->args.append(buf_ptr(target_dynamic_linker(&g->zig_target)));308 } else {
309 Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);
310 lj->args.append("-dynamic-linker");
311 lj->args.append(buf_ptr(resolved_dynamic_linker));
312 }
268 }313 }
269314
270 if (shared) {315 if (shared) {
...@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {...@@ -423,7 +468,9 @@ static void construct_linker_job_coff(LinkJob *lj) {
423 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));468 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->kernel32_lib_dir))));
424469
425 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));470 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_lib_dir))));
426 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));471 if (g->libc_static_lib_dir != nullptr) {
472 lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", buf_ptr(g->libc_static_lib_dir))));
473 }
427 }474 }
428475
429 if (lj->link_in_crt) {476 if (lj->link_in_crt) {
src/main.cpp+50-15
...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {...@@ -23,6 +23,7 @@ static int usage(const char *arg0) {
23 " build-exe [source] create executable from source or object files\n"23 " build-exe [source] create executable from source or object files\n"
24 " build-lib [source] create library from source or object files\n"24 " build-lib [source] create library from source or object files\n"
25 " build-obj [source] create object from source or assembly\n"25 " build-obj [source] create object from source or assembly\n"
26 " run [source] create executable and run immediately\n"
26 " translate-c [source] convert c code to zig code\n"27 " translate-c [source] convert c code to zig code\n"
27 " targets list available compilation targets\n"28 " targets list available compilation targets\n"
28 " test [source] create and run a test build\n"29 " test [source] create and run a test build\n"
...@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {...@@ -195,13 +196,6 @@ static int find_zig_lib_dir(Buf *out_path) {
195 }196 }
196 }197 }
197198
198 if (ZIG_INSTALL_PREFIX != nullptr) {
199 if (test_zig_install_prefix(buf_create_from_str(ZIG_INSTALL_PREFIX), out_path)) {
200 return 0;
201 }
202 }
203
204
205 return ErrorFileNotFound;199 return ErrorFileNotFound;
206}200}
207201
...@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {...@@ -227,6 +221,7 @@ static Buf *resolve_zig_lib_dir(const char *zig_install_prefix_arg) {
227enum Cmd {221enum Cmd {
228 CmdInvalid,222 CmdInvalid,
229 CmdBuild,223 CmdBuild,
224 CmdRun,
230 CmdTest,225 CmdTest,
231 CmdVersion,226 CmdVersion,
232 CmdZen,227 CmdZen,
...@@ -336,6 +331,8 @@ int main(int argc, char **argv) {...@@ -336,6 +331,8 @@ int main(int argc, char **argv) {
336 CliPkg *cur_pkg = allocate<CliPkg>(1);331 CliPkg *cur_pkg = allocate<CliPkg>(1);
337 BuildMode build_mode = BuildModeDebug;332 BuildMode build_mode = BuildModeDebug;
338 ZigList<const char *> test_exec_args = {0};333 ZigList<const char *> test_exec_args = {0};
334 int comptime_args_end = 0;
335 int runtime_args_start = argc;
339336
340 if (argc >= 2 && strcmp(argv[1], "build") == 0) {337 if (argc >= 2 && strcmp(argv[1], "build") == 0) {
341 const char *zig_exe_path = arg0;338 const char *zig_exe_path = arg0;
...@@ -488,11 +485,15 @@ int main(int argc, char **argv) {...@@ -488,11 +485,15 @@ int main(int argc, char **argv) {
488 return (term.how == TerminationIdClean) ? term.code : -1;485 return (term.how == TerminationIdClean) ? term.code : -1;
489 }486 }
490487
491 for (int i = 1; i < argc; i += 1) {488 for (int i = 1; i < argc; i += 1, comptime_args_end += 1) {
492 char *arg = argv[i];489 char *arg = argv[i];
493490
494 if (arg[0] == '-') {491 if (arg[0] == '-') {
495 if (strcmp(arg, "--release-fast") == 0) {492 if (strcmp(arg, "--") == 0) {
493 // ignore -- from both compile and runtime arg sets
494 runtime_args_start = i + 1;
495 break;
496 } else if (strcmp(arg, "--release-fast") == 0) {
496 build_mode = BuildModeFastRelease;497 build_mode = BuildModeFastRelease;
497 } else if (strcmp(arg, "--release-safe") == 0) {498 } else if (strcmp(arg, "--release-safe") == 0) {
498 build_mode = BuildModeSafeRelease;499 build_mode = BuildModeSafeRelease;
...@@ -659,6 +660,9 @@ int main(int argc, char **argv) {...@@ -659,6 +660,9 @@ int main(int argc, char **argv) {
659 } else if (strcmp(arg, "build-lib") == 0) {660 } else if (strcmp(arg, "build-lib") == 0) {
660 cmd = CmdBuild;661 cmd = CmdBuild;
661 out_type = OutTypeLib;662 out_type = OutTypeLib;
663 } else if (strcmp(arg, "run") == 0) {
664 cmd = CmdRun;
665 out_type = OutTypeExe;
662 } else if (strcmp(arg, "version") == 0) {666 } else if (strcmp(arg, "version") == 0) {
663 cmd = CmdVersion;667 cmd = CmdVersion;
664 } else if (strcmp(arg, "zen") == 0) {668 } else if (strcmp(arg, "zen") == 0) {
...@@ -677,6 +681,7 @@ int main(int argc, char **argv) {...@@ -677,6 +681,7 @@ int main(int argc, char **argv) {
677 } else {681 } else {
678 switch (cmd) {682 switch (cmd) {
679 case CmdBuild:683 case CmdBuild:
684 case CmdRun:
680 case CmdTranslateC:685 case CmdTranslateC:
681 case CmdTest:686 case CmdTest:
682 if (!in_file) {687 if (!in_file) {
...@@ -731,8 +736,8 @@ int main(int argc, char **argv) {...@@ -731,8 +736,8 @@ int main(int argc, char **argv) {
731 }736 }
732 }737 }
733738
734
735 switch (cmd) {739 switch (cmd) {
740 case CmdRun:
736 case CmdBuild:741 case CmdBuild:
737 case CmdTranslateC:742 case CmdTranslateC:
738 case CmdTest:743 case CmdTest:
...@@ -740,7 +745,7 @@ int main(int argc, char **argv) {...@@ -740,7 +745,7 @@ int main(int argc, char **argv) {
740 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {745 if (cmd == CmdBuild && !in_file && objects.length == 0 && asm_files.length == 0) {
741 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");746 fprintf(stderr, "Expected source file argument or at least one --object or --assembly argument.\n");
742 return usage(arg0);747 return usage(arg0);
743 } else if ((cmd == CmdTranslateC || cmd == CmdTest) && !in_file) {748 } else if ((cmd == CmdTranslateC || cmd == CmdTest || cmd == CmdRun) && !in_file) {
744 fprintf(stderr, "Expected source file argument.\n");749 fprintf(stderr, "Expected source file argument.\n");
745 return usage(arg0);750 return usage(arg0);
746 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {751 } else if (cmd == CmdBuild && out_type == OutTypeObj && objects.length != 0) {
...@@ -752,6 +757,10 @@ int main(int argc, char **argv) {...@@ -752,6 +757,10 @@ int main(int argc, char **argv) {
752757
753 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);758 bool need_name = (cmd == CmdBuild || cmd == CmdTranslateC);
754759
760 if (cmd == CmdRun) {
761 out_name = "run";
762 }
763
755 Buf *in_file_buf = nullptr;764 Buf *in_file_buf = nullptr;
756765
757 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :766 Buf *buf_out_name = (cmd == CmdTest) ? buf_create_from_str("test") :
...@@ -776,9 +785,23 @@ int main(int argc, char **argv) {...@@ -776,9 +785,23 @@ int main(int argc, char **argv) {
776 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;785 Buf *zig_root_source_file = (cmd == CmdTranslateC) ? nullptr : in_file_buf;
777786
778 Buf *full_cache_dir = buf_alloc();787 Buf *full_cache_dir = buf_alloc();
779 os_path_resolve(buf_create_from_str("."),788 Buf *run_exec_path = buf_alloc();
780 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),789 if (cmd == CmdRun) {
781 full_cache_dir);790 if (buf_out_name == nullptr) {
791 buf_out_name = buf_create_from_str("run");
792 }
793
794 Buf *global_cache_dir = buf_alloc();
795 os_get_global_cache_directory(global_cache_dir);
796 os_path_join(global_cache_dir, buf_out_name, run_exec_path);
797 os_path_resolve(buf_create_from_str("."), global_cache_dir, full_cache_dir);
798
799 out_file = buf_ptr(run_exec_path);
800 } else {
801 os_path_resolve(buf_create_from_str("."),
802 buf_create_from_str((cache_dir == nullptr) ? default_zig_cache_name : cache_dir),
803 full_cache_dir);
804 }
782805
783 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);806 Buf *zig_lib_dir_buf = resolve_zig_lib_dir(zig_install_prefix);
784807
...@@ -862,7 +885,7 @@ int main(int argc, char **argv) {...@@ -862,7 +885,7 @@ int main(int argc, char **argv) {
862885
863 add_package(g, cur_pkg, g->root_package);886 add_package(g, cur_pkg, g->root_package);
864887
865 if (cmd == CmdBuild) {888 if (cmd == CmdBuild || cmd == CmdRun) {
866 codegen_set_emit_file_type(g, emit_file_type);889 codegen_set_emit_file_type(g, emit_file_type);
867890
868 for (size_t i = 0; i < objects.length; i += 1) {891 for (size_t i = 0; i < objects.length; i += 1) {
...@@ -875,6 +898,18 @@ int main(int argc, char **argv) {...@@ -875,6 +898,18 @@ int main(int argc, char **argv) {
875 codegen_link(g, out_file);898 codegen_link(g, out_file);
876 if (timing_info)899 if (timing_info)
877 codegen_print_timing_report(g, stdout);900 codegen_print_timing_report(g, stdout);
901
902 if (cmd == CmdRun) {
903 ZigList<const char*> args = {0};
904 for (int i = runtime_args_start; i < argc; ++i) {
905 args.append(argv[i]);
906 }
907
908 Termination term;
909 os_spawn_process(buf_ptr(run_exec_path), args, &term);
910 return term.code;
911 }
912
878 return EXIT_SUCCESS;913 return EXIT_SUCCESS;
879 } else if (cmd == CmdTranslateC) {914 } else if (cmd == CmdTranslateC) {
880 codegen_translate_c(g, in_file_buf);915 codegen_translate_c(g, in_file_buf);
src/os.cpp+90-11
...@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;...@@ -45,6 +45,7 @@ typedef SSIZE_T ssize_t;
45#if defined(__MACH__)45#if defined(__MACH__)
46#include <mach/clock.h>46#include <mach/clock.h>
47#include <mach/mach.h>47#include <mach/mach.h>
48#include <mach-o/dyld.h>
48#endif49#endif
4950
50#if defined(ZIG_OS_WINDOWS)51#if defined(ZIG_OS_WINDOWS)
...@@ -57,10 +58,6 @@ static clock_serv_t cclock;...@@ -57,10 +58,6 @@ static clock_serv_t cclock;
57#include <errno.h>58#include <errno.h>
58#include <time.h>59#include <time.h>
5960
60// these implementations are lazy. But who cares, we'll make a robust
61// implementation in the zig standard library and then this code all gets
62// deleted when we self-host. it works for now.
63
64#if defined(ZIG_OS_POSIX)61#if defined(ZIG_OS_POSIX)
65static void populate_termination(Termination *term, int status) {62static void populate_termination(Termination *term, int status) {
66 if (WIFEXITED(status)) {63 if (WIFEXITED(status)) {
...@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {...@@ -291,13 +288,39 @@ void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path) {
291 return;288 return;
292}289}
293290
294int os_fetch_file(FILE *f, Buf *out_buf) {291int os_fetch_file(FILE *f, Buf *out_buf, bool skip_shebang) {
295 static const ssize_t buf_size = 0x2000;292 static const ssize_t buf_size = 0x2000;
296 buf_resize(out_buf, buf_size);293 buf_resize(out_buf, buf_size);
297 ssize_t actual_buf_len = 0;294 ssize_t actual_buf_len = 0;
295
296 bool first_read = true;
297
298 for (;;) {298 for (;;) {
299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);299 size_t amt_read = fread(buf_ptr(out_buf) + actual_buf_len, 1, buf_size, f);
300 actual_buf_len += amt_read;300 actual_buf_len += amt_read;
301
302 if (skip_shebang && first_read && buf_starts_with_str(out_buf, "#!")) {
303 size_t i = 0;
304 while (true) {
305 if (i > buf_len(out_buf)) {
306 zig_panic("shebang line exceeded %zd characters", buf_size);
307 }
308
309 size_t current_pos = i;
310 i += 1;
311
312 if (out_buf->list.at(current_pos) == '\n') {
313 break;
314 }
315 }
316
317 ZigList<char> *list = &out_buf->list;
318 memmove(list->items, list->items + i, list->length - i);
319 list->length -= i;
320
321 actual_buf_len -= i;
322 }
323
301 if (amt_read != buf_size) {324 if (amt_read != buf_size) {
302 if (feof(f)) {325 if (feof(f)) {
303 buf_resize(out_buf, actual_buf_len);326 buf_resize(out_buf, actual_buf_len);
...@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {...@@ -308,6 +331,7 @@ int os_fetch_file(FILE *f, Buf *out_buf) {
308 }331 }
309332
310 buf_resize(out_buf, actual_buf_len + buf_size);333 buf_resize(out_buf, actual_buf_len + buf_size);
334 first_read = false;
311 }335 }
312 zig_unreachable();336 zig_unreachable();
313}337}
...@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,...@@ -377,8 +401,8 @@ static int os_exec_process_posix(const char *exe, ZigList<const char *> &args,
377401
378 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");402 FILE *stdout_f = fdopen(stdout_pipe[0], "rb");
379 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");403 FILE *stderr_f = fdopen(stderr_pipe[0], "rb");
380 os_fetch_file(stdout_f, out_stdout);404 os_fetch_file(stdout_f, out_stdout, false);
381 os_fetch_file(stderr_f, out_stderr);405 os_fetch_file(stderr_f, out_stderr, false);
382406
383 fclose(stdout_f);407 fclose(stdout_f);
384 fclose(stderr_f);408 fclose(stderr_f);
...@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {...@@ -591,7 +615,7 @@ int os_copy_file(Buf *src_path, Buf *dest_path) {
591 }615 }
592}616}
593617
594int os_fetch_file_path(Buf *full_path, Buf *out_contents) {618int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang) {
595 FILE *f = fopen(buf_ptr(full_path), "rb");619 FILE *f = fopen(buf_ptr(full_path), "rb");
596 if (!f) {620 if (!f) {
597 switch (errno) {621 switch (errno) {
...@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {...@@ -610,7 +634,7 @@ int os_fetch_file_path(Buf *full_path, Buf *out_contents) {
610 return ErrorFileSystem;634 return ErrorFileSystem;
611 }635 }
612 }636 }
613 int result = os_fetch_file(f, out_contents);637 int result = os_fetch_file(f, out_contents, skip_shebang);
614 fclose(f);638 fclose(f);
615 return result;639 return result;
616}640}
...@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {...@@ -783,6 +807,44 @@ int os_buf_to_tmp_file(Buf *contents, Buf *suffix, Buf *out_tmp_path) {
783#endif807#endif
784}808}
785809
810#if defined(ZIG_OS_POSIX)
811int os_get_global_cache_directory(Buf *out_tmp_path) {
812 const char *tmp_dir = getenv("TMPDIR");
813 if (!tmp_dir) {
814 tmp_dir = P_tmpdir;
815 }
816
817 Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
818 Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
819
820 buf_resize(out_tmp_path, 0);
821 os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
822
823 buf_deinit(tmp_dir_buf);
824 buf_deinit(cache_dirname_buf);
825 return 0;
826}
827#endif
828
829#if defined(ZIG_OS_WINDOWS)
830int os_get_global_cache_directory(Buf *out_tmp_path) {
831 char tmp_dir[MAX_PATH + 1];
832 if (GetTempPath(MAX_PATH, tmp_dir) == 0) {
833 zig_panic("GetTempPath failed");
834 }
835
836 Buf *tmp_dir_buf = buf_create_from_str(tmp_dir);
837 Buf *cache_dirname_buf = buf_create_from_str("zig-cache");
838
839 buf_resize(out_tmp_path, 0);
840 os_path_join(tmp_dir_buf, cache_dirname_buf, out_tmp_path);
841
842 buf_deinit(tmp_dir_buf);
843 buf_deinit(cache_dirname_buf);
844 return 0;
845}
846#endif
847
786int os_delete_file(Buf *path) {848int os_delete_file(Buf *path) {
787 if (remove(buf_ptr(path))) {849 if (remove(buf_ptr(path))) {
788 return ErrorFileSystem;850 return ErrorFileSystem;
...@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {...@@ -927,9 +989,26 @@ int os_self_exe_path(Buf *out_path) {
927 }989 }
928990
929#elif defined(ZIG_OS_DARWIN)991#elif defined(ZIG_OS_DARWIN)
930 return ErrorFileNotFound;992 uint32_t u32_len = 0;
993 int ret1 = _NSGetExecutablePath(nullptr, &u32_len);
994 assert(ret1 != 0);
995 buf_resize(out_path, u32_len);
996 int ret2 = _NSGetExecutablePath(buf_ptr(out_path), &u32_len);
997 assert(ret2 == 0);
998 return 0;
931#elif defined(ZIG_OS_LINUX)999#elif defined(ZIG_OS_LINUX)
932 return ErrorFileNotFound;1000 buf_resize(out_path, 256);
1001 for (;;) {
1002 ssize_t amt = readlink("/proc/self/exe", buf_ptr(out_path), buf_len(out_path));
1003 if (amt == -1) {
1004 return ErrorUnexpected;
1005 }
1006 if (amt == (ssize_t)buf_len(out_path)) {
1007 buf_resize(out_path, buf_len(out_path) * 2);
1008 continue;
1009 }
1010 return 0;
1011 }
933#endif1012#endif
934 return ErrorFileNotFound;1013 return ErrorFileNotFound;
935}1014}
src/os.hpp+4-2
...@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);...@@ -51,14 +51,16 @@ int os_path_real(Buf *rel_path, Buf *out_abs_path);
51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);51void os_path_resolve(Buf *ref_path, Buf *target_path, Buf *out_abs_path);
52bool os_path_is_absolute(Buf *path);52bool os_path_is_absolute(Buf *path);
5353
54int os_get_global_cache_directory(Buf *out_tmp_path);
55
54int os_make_path(Buf *path);56int os_make_path(Buf *path);
55int os_make_dir(Buf *path);57int os_make_dir(Buf *path);
5658
57void os_write_file(Buf *full_path, Buf *contents);59void os_write_file(Buf *full_path, Buf *contents);
58int os_copy_file(Buf *src_path, Buf *dest_path);60int os_copy_file(Buf *src_path, Buf *dest_path);
5961
60int os_fetch_file(FILE *file, Buf *out_contents);62int os_fetch_file(FILE *file, Buf *out_contents, bool skip_shebang);
61int os_fetch_file_path(Buf *full_path, Buf *out_contents);63int os_fetch_file_path(Buf *full_path, Buf *out_contents, bool skip_shebang);
6264
63int os_get_cwd(Buf *out_cwd);65int os_get_cwd(Buf *out_cwd);
6466
src/parser.cpp-3
...@@ -2923,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont...@@ -2923,9 +2923,6 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
2923 visit_field(&node->data.fn_def.fn_proto, visit, context);2923 visit_field(&node->data.fn_def.fn_proto, visit, context);
2924 visit_field(&node->data.fn_def.body, visit, context);2924 visit_field(&node->data.fn_def.body, visit, context);
2925 break;2925 break;
2926 case NodeTypeFnDecl:
2927 visit_field(&node->data.fn_decl.fn_proto, visit, context);
2928 break;
2929 case NodeTypeParamDecl:2926 case NodeTypeParamDecl:
2930 visit_field(&node->data.param_decl.type, visit, context);2927 visit_field(&node->data.param_decl.type, visit, context);
2931 break;2928 break;
src/target.cpp+4
...@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {...@@ -863,6 +863,10 @@ Buf *target_dynamic_linker(ZigTarget *target) {
863 env == ZigLLVM_GNUX32)863 env == ZigLLVM_GNUX32)
864 {864 {
865 return buf_create_from_str("/libx32/ld-linux-x32.so.2");865 return buf_create_from_str("/libx32/ld-linux-x32.so.2");
866 } else if (arch == ZigLLVM_x86_64 &&
867 (env == ZigLLVM_Musl || env == ZigLLVM_MuslEABI || env == ZigLLVM_MuslEABIHF))
868 {
869 return buf_create_from_str("/lib/ld-musl-x86_64.so.1");
866 } else {870 } else {
867 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");871 return buf_create_from_str("/lib64/ld-linux-x86-64.so.2");
868 }872 }
std/c/darwin.zig+18
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1extern "c" fn __error() &c_int;1extern "c" fn __error() &c_int;
2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;2pub extern "c" fn _NSGetExecutablePath(buf: &u8, bufsize: &u32) c_int;
33
4pub extern "c" fn __getdirentries64(fd: c_int, buf_ptr: &u8, buf_len: usize, basep: &i64) usize;
45
5pub use @import("../os/darwin_errno.zig");6pub use @import("../os/darwin_errno.zig");
67
...@@ -45,3 +46,20 @@ pub const Sigaction = extern struct {...@@ -45,3 +46,20 @@ pub const Sigaction = extern struct {
45 sa_mask: sigset_t,46 sa_mask: sigset_t,
46 sa_flags: c_int,47 sa_flags: c_int,
47};48};
49
50pub const dirent = extern struct {
51 d_ino: usize,
52 d_seekoff: usize,
53 d_reclen: u16,
54 d_namlen: u16,
55 d_type: u8,
56 d_name: u8, // field address is address of first byte of name
57};
58
59pub const sockaddr = extern struct {
60 sa_len: u8,
61 sa_family: sa_family_t,
62 sa_data: [14]u8,
63};
64
65pub const sa_family_t = u8;
std/c/index.zig+1
...@@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o...@@ -44,6 +44,7 @@ pub extern "c" fn sigaction(sig: c_int, noalias act: &const Sigaction, noalias o
44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;44pub extern "c" fn nanosleep(rqtp: &const timespec, rmtp: ?&timespec) c_int;
45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;45pub extern "c" fn setreuid(ruid: c_uint, euid: c_uint) c_int;
46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;46pub extern "c" fn setregid(rgid: c_uint, egid: c_uint) c_int;
47pub extern "c" fn rmdir(path: &const u8) c_int;
4748
48pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;49pub extern "c" fn aligned_alloc(alignment: usize, size: usize) ?&c_void;
49pub extern "c" fn malloc(usize) ?&c_void;50pub extern "c" fn malloc(usize) ?&c_void;
std/crypto/blake2.zig+20-2
...@@ -84,7 +84,7 @@ fn Blake2s(comptime out_len: usize) type { return struct {...@@ -84,7 +84,7 @@ fn Blake2s(comptime out_len: usize) type { return struct {
84 }84 }
8585
86 // Full middle blocks.86 // Full middle blocks.
87 while (off + 64 < b.len) : (off += 64) {87 while (off + 64 <= b.len) : (off += 64) {
88 d.t += 64;88 d.t += 64;
89 d.round(b[off..off + 64], false);89 d.round(b[off..off + 64], false);
90 }90 }
...@@ -229,6 +229,15 @@ test "blake2s256 streaming" {...@@ -229,6 +229,15 @@ test "blake2s256 streaming" {
229 htest.assertEqual(h2, out[0..]);229 htest.assertEqual(h2, out[0..]);
230}230}
231231
232test "blake2s256 aligned final" {
233 var block = []u8 {0} ** Blake2s256.block_size;
234 var out: [Blake2s256.digest_size]u8 = undefined;
235
236 var h = Blake2s256.init();
237 h.update(block);
238 h.final(out[0..]);
239}
240
232241
233/////////////////////242/////////////////////
234// Blake2b243// Blake2b
...@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {...@@ -305,7 +314,7 @@ fn Blake2b(comptime out_len: usize) type { return struct {
305 }314 }
306315
307 // Full middle blocks.316 // Full middle blocks.
308 while (off + 128 < b.len) : (off += 128) {317 while (off + 128 <= b.len) : (off += 128) {
309 d.t += 128;318 d.t += 128;
310 d.round(b[off..off + 128], false);319 d.round(b[off..off + 128], false);
311 }320 }
...@@ -447,3 +456,12 @@ test "blake2b512 streaming" {...@@ -447,3 +456,12 @@ test "blake2b512 streaming" {
447 h.final(out[0..]);456 h.final(out[0..]);
448 htest.assertEqual(h2, out[0..]);457 htest.assertEqual(h2, out[0..]);
449}458}
459
460test "blake2b512 aligned final" {
461 var block = []u8 {0} ** Blake2b512.block_size;
462 var out: [Blake2b512.digest_size]u8 = undefined;
463
464 var h = Blake2b512.init();
465 h.update(block);
466 h.final(out[0..]);
467}
std/crypto/hmac.zig created+81
...@@ -0,0 +1,81 @@
1const std = @import("../index.zig");
2const crypto = std.crypto;
3const debug = std.debug;
4const mem = std.mem;
5
6pub const HmacMd5 = Hmac(crypto.Md5);
7pub const HmacSha1 = Hmac(crypto.Sha1);
8pub const HmacSha256 = Hmac(crypto.Sha256);
9
10pub fn Hmac(comptime H: type) type {
11 return struct {
12 const digest_size = H.digest_size;
13
14 pub fn hash(output: []u8, key: []const u8, message: []const u8) void {
15 debug.assert(output.len >= H.digest_size);
16 debug.assert(H.digest_size <= H.block_size); // HMAC makes this assumption
17 var scratch: [H.block_size]u8 = undefined;
18
19 // Normalize key length to block size of hash
20 if (key.len > H.block_size) {
21 H.hash(key, scratch[0..H.digest_size]);
22 mem.set(u8, scratch[H.digest_size..H.block_size], 0);
23 } else if (key.len < H.block_size) {
24 mem.copy(u8, scratch[0..key.len], key);
25 mem.set(u8, scratch[key.len..H.block_size], 0);
26 } else {
27 mem.copy(u8, scratch[0..], key);
28 }
29
30 var o_key_pad: [H.block_size]u8 = undefined;
31 for (o_key_pad) |*b, i| {
32 *b = scratch[i] ^ 0x5c;
33 }
34
35 var i_key_pad: [H.block_size]u8 = undefined;
36 for (i_key_pad) |*b, i| {
37 *b = scratch[i] ^ 0x36;
38 }
39
40 // HMAC(k, m) = H(o_key_pad | H(i_key_pad | message)) where | is concatenation
41 var hmac = H.init();
42 hmac.update(i_key_pad[0..]);
43 hmac.update(message);
44 hmac.final(scratch[0..H.digest_size]);
45
46 hmac.reset();
47 hmac.update(o_key_pad[0..]);
48 hmac.update(scratch[0..H.digest_size]);
49 hmac.final(output[0..H.digest_size]);
50 }
51 };
52}
53
54const htest = @import("test.zig");
55
56test "hmac md5" {
57 var out: [crypto.Md5.digest_size]u8 = undefined;
58 HmacMd5.hash(out[0..], "", "");
59 htest.assertEqual("74e6f7298a9c2d168935f58c001bad88", out[0..]);
60
61 HmacMd5.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");
62 htest.assertEqual("80070713463e7749b90c2dc24911e275", out[0..]);
63}
64
65test "hmac sha1" {
66 var out: [crypto.Sha1.digest_size]u8 = undefined;
67 HmacSha1.hash(out[0..], "", "");
68 htest.assertEqual("fbdb1d1b18aa6c08324b7d64b71fb76370690e1d", out[0..]);
69
70 HmacSha1.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");
71 htest.assertEqual("de7c9b85b8b78aa6bc8a7a36f70a90701c9db4d9", out[0..]);
72}
73
74test "hmac sha256" {
75 var out: [crypto.Sha256.digest_size]u8 = undefined;
76 HmacSha256.hash(out[0..], "", "");
77 htest.assertEqual("b613679a0814d9ec772f95d778c35fc5ff1697c493715653c6c712144292c5ad", out[0..]);
78
79 HmacSha256.hash(out[0..], "key", "The quick brown fox jumps over the lazy dog");
80 htest.assertEqual("f7bc83f430538424b13298e6aa6fb143ef4d59a14946175997479dbc2d1a3cd8", out[0..]);
81}
std/crypto/index.zig+6
...@@ -19,10 +19,16 @@ pub const Blake2s256 = blake2.Blake2s256;...@@ -19,10 +19,16 @@ pub const Blake2s256 = blake2.Blake2s256;
19pub const Blake2b384 = blake2.Blake2b384;19pub const Blake2b384 = blake2.Blake2b384;
20pub const Blake2b512 = blake2.Blake2b512;20pub const Blake2b512 = blake2.Blake2b512;
2121
22const hmac = @import("hmac.zig");
23pub const HmacMd5 = hmac.HmacMd5;
24pub const HmacSha1 = hmac.Sha1;
25pub const HmacSha256 = hmac.Sha256;
26
22test "crypto" {27test "crypto" {
23 _ = @import("md5.zig");28 _ = @import("md5.zig");
24 _ = @import("sha1.zig");29 _ = @import("sha1.zig");
25 _ = @import("sha2.zig");30 _ = @import("sha2.zig");
26 _ = @import("sha3.zig");31 _ = @import("sha3.zig");
27 _ = @import("blake2.zig");32 _ = @import("blake2.zig");
33 _ = @import("hmac.zig");
28}34}
std/crypto/md5.zig+10-1
...@@ -59,7 +59,7 @@ pub const Md5 = struct {...@@ -59,7 +59,7 @@ pub const Md5 = struct {
59 }59 }
6060
61 // Full middle blocks.61 // Full middle blocks.
62 while (off + 64 < b.len) : (off += 64) {62 while (off + 64 <= b.len) : (off += 64) {
63 d.round(b[off..off + 64]);63 d.round(b[off..off + 64]);
64 }64 }
6565
...@@ -253,3 +253,12 @@ test "md5 streaming" {...@@ -253,3 +253,12 @@ test "md5 streaming" {
253253
254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);254 htest.assertEqual("900150983cd24fb0d6963f7d28e17f72", out[0..]);
255}255}
256
257test "md5 aligned final" {
258 var block = []u8 {0} ** Md5.block_size;
259 var out: [Md5.digest_size]u8 = undefined;
260
261 var h = Md5.init();
262 h.update(block);
263 h.final(out[0..]);
264}
std/crypto/sha1.zig+10-1
...@@ -60,7 +60,7 @@ pub const Sha1 = struct {...@@ -60,7 +60,7 @@ pub const Sha1 = struct {
60 }60 }
6161
62 // Full middle blocks.62 // Full middle blocks.
63 while (off + 64 < b.len) : (off += 64) {63 while (off + 64 <= b.len) : (off += 64) {
64 d.round(b[off..off + 64]);64 d.round(b[off..off + 64]);
65 }65 }
6666
...@@ -284,3 +284,12 @@ test "sha1 streaming" {...@@ -284,3 +284,12 @@ test "sha1 streaming" {
284 h.final(out[0..]);284 h.final(out[0..]);
285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);285 htest.assertEqual("a9993e364706816aba3e25717850c26c9cd0d89d", out[0..]);
286}286}
287
288test "sha1 aligned final" {
289 var block = []u8 {0} ** Sha1.block_size;
290 var out: [Sha1.digest_size]u8 = undefined;
291
292 var h = Sha1.init();
293 h.update(block);
294 h.final(out[0..]);
295}
std/crypto/sha2.zig+20-2
...@@ -105,7 +105,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { return struct {...@@ -105,7 +105,7 @@ fn Sha2_32(comptime params: Sha2Params32) type { return struct {
105 }105 }
106106
107 // Full middle blocks.107 // Full middle blocks.
108 while (off + 64 < b.len) : (off += 64) {108 while (off + 64 <= b.len) : (off += 64) {
109 d.round(b[off..off + 64]);109 d.round(b[off..off + 64]);
110 }110 }
111111
...@@ -319,6 +319,15 @@ test "sha256 streaming" {...@@ -319,6 +319,15 @@ test "sha256 streaming" {
319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);319 htest.assertEqual("ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", out[0..]);
320}320}
321321
322test "sha256 aligned final" {
323 var block = []u8 {0} ** Sha256.block_size;
324 var out: [Sha256.digest_size]u8 = undefined;
325
326 var h = Sha256.init();
327 h.update(block);
328 h.final(out[0..]);
329}
330
322331
323/////////////////////332/////////////////////
324// Sha384 + Sha512333// Sha384 + Sha512
...@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {...@@ -420,7 +429,7 @@ fn Sha2_64(comptime params: Sha2Params64) type { return struct {
420 }429 }
421430
422 // Full middle blocks.431 // Full middle blocks.
423 while (off + 128 < b.len) : (off += 128) {432 while (off + 128 <= b.len) : (off += 128) {
424 d.round(b[off..off + 128]);433 d.round(b[off..off + 128]);
425 }434 }
426435
...@@ -669,3 +678,12 @@ test "sha512 streaming" {...@@ -669,3 +678,12 @@ test "sha512 streaming" {
669 h.final(out[0..]);678 h.final(out[0..]);
670 htest.assertEqual(h2, out[0..]);679 htest.assertEqual(h2, out[0..]);
671}680}
681
682test "sha512 aligned final" {
683 var block = []u8 {0} ** Sha512.block_size;
684 var out: [Sha512.digest_size]u8 = undefined;
685
686 var h = Sha512.init();
687 h.update(block);
688 h.final(out[0..]);
689}
std/crypto/sha3.zig+18
...@@ -217,6 +217,15 @@ test "sha3-256 streaming" {...@@ -217,6 +217,15 @@ test "sha3-256 streaming" {
217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);217 htest.assertEqual("3a985da74fe225b2045c172d6bd390bd855f086e3e9d525b46bfe24511431532", out[0..]);
218}218}
219219
220test "sha3-256 aligned final" {
221 var block = []u8 {0} ** Sha3_256.block_size;
222 var out: [Sha3_256.digest_size]u8 = undefined;
223
224 var h = Sha3_256.init();
225 h.update(block);
226 h.final(out[0..]);
227}
228
220test "sha3-384 single" {229test "sha3-384 single" {
221 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";230 const h1 = "0c63a75b845e4f7d01107d852e4c2485c51a50aaaa94fc61995e71bbee983a2ac3713831264adb47fb6bd1e058d5f004";
222 htest.assertEqualHash(Sha3_384, h1 , "");231 htest.assertEqualHash(Sha3_384, h1 , "");
...@@ -278,3 +287,12 @@ test "sha3-512 streaming" {...@@ -278,3 +287,12 @@ test "sha3-512 streaming" {
278 h.final(out[0..]);287 h.final(out[0..]);
279 htest.assertEqual(h2, out[0..]);288 htest.assertEqual(h2, out[0..]);
280}289}
290
291test "sha3-512 aligned final" {
292 var block = []u8 {0} ** Sha3_512.block_size;
293 var out: [Sha3_512.digest_size]u8 = undefined;
294
295 var h = Sha3_512.init();
296 h.update(block);
297 h.final(out[0..]);
298}
std/endian.zig deleted-25
...@@ -1,25 +0,0 @@
1const mem = @import("mem.zig");
2const builtin = @import("builtin");
3
4pub fn swapIfLe(comptime T: type, x: T) T {
5 return swapIf(builtin.Endian.Little, T, x);
6}
7
8pub fn swapIfBe(comptime T: type, x: T) T {
9 return swapIf(builtin.Endian.Big, T, x);
10}
11
12pub fn swapIf(endian: builtin.Endian, comptime T: type, x: T) T {
13 return if (builtin.endian == endian) swap(T, x) else x;
14}
15
16pub fn swap(comptime T: type, x: T) T {
17 var buf: [@sizeOf(T)]u8 = undefined;
18 mem.writeInt(buf[0..], x, builtin.Endian.Little);
19 return mem.readInt(buf, T, builtin.Endian.Big);
20}
21
22test "swap" {
23 const debug = @import("debug/index.zig");
24 debug.assert(swap(u32, 0xDEADBEEF) == 0xEFBEADDE);
25}
std/event.zig created+235
...@@ -0,0 +1,235 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const event = this;
5const mem = std.mem;
6const posix = std.os.posix;
7
8pub const TcpServer = struct {
9 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File) void,
10
11 loop: &Loop,
12 sockfd: i32,
13 accept_coro: ?promise,
14 listen_address: std.net.Address,
15
16 waiting_for_emfile_node: PromiseNode,
17
18 const PromiseNode = std.LinkedList(promise).Node;
19
20 pub fn init(loop: &Loop) !TcpServer {
21 const sockfd = try std.os.posixSocket(posix.AF_INET,
22 posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK,
23 posix.PROTO_tcp);
24 errdefer std.os.close(sockfd);
25
26 // TODO can't initialize handler coroutine here because we need well defined copy elision
27 return TcpServer {
28 .loop = loop,
29 .sockfd = sockfd,
30 .accept_coro = null,
31 .handleRequestFn = undefined,
32 .waiting_for_emfile_node = undefined,
33 .listen_address = undefined,
34 };
35 }
36
37 pub fn listen(self: &TcpServer, address: &const std.net.Address,
38 handleRequestFn: async<&mem.Allocator> fn (&TcpServer, &const std.net.Address, &const std.os.File)void) !void
39 {
40 self.handleRequestFn = handleRequestFn;
41
42 try std.os.posixBind(self.sockfd, &address.os_addr);
43 try std.os.posixListen(self.sockfd, posix.SOMAXCONN);
44 self.listen_address = std.net.Address.initPosix(try std.os.posixGetSockName(self.sockfd));
45
46 self.accept_coro = try async<self.loop.allocator> TcpServer.handler(self);
47 errdefer cancel ??self.accept_coro;
48
49 try self.loop.addFd(self.sockfd, ??self.accept_coro);
50 errdefer self.loop.removeFd(self.sockfd);
51
52 }
53
54 pub fn deinit(self: &TcpServer) void {
55 self.loop.removeFd(self.sockfd);
56 if (self.accept_coro) |accept_coro| cancel accept_coro;
57 std.os.close(self.sockfd);
58 }
59
60 pub async fn handler(self: &TcpServer) void {
61 while (true) {
62 var accepted_addr: std.net.Address = undefined;
63 if (std.os.posixAccept(self.sockfd, &accepted_addr.os_addr,
64 posix.SOCK_NONBLOCK | posix.SOCK_CLOEXEC)) |accepted_fd|
65 {
66 var socket = std.os.File.openHandle(accepted_fd);
67 _ = async<self.loop.allocator> self.handleRequestFn(self, accepted_addr, socket) catch |err| switch (err) {
68 error.OutOfMemory => {
69 socket.close();
70 continue;
71 },
72 };
73 } else |err| switch (err) {
74 error.WouldBlock => {
75 suspend; // we will get resumed by epoll_wait in the event loop
76 continue;
77 },
78 error.ProcessFdQuotaExceeded => {
79 errdefer std.os.emfile_promise_queue.remove(&self.waiting_for_emfile_node);
80 suspend |p| {
81 self.waiting_for_emfile_node = PromiseNode.init(p);
82 std.os.emfile_promise_queue.append(&self.waiting_for_emfile_node);
83 }
84 continue;
85 },
86 error.ConnectionAborted,
87 error.FileDescriptorClosed => continue,
88
89 error.PageFault => unreachable,
90 error.InvalidSyscall => unreachable,
91 error.FileDescriptorNotASocket => unreachable,
92 error.OperationNotSupported => unreachable,
93
94 error.SystemFdQuotaExceeded,
95 error.SystemResources,
96 error.ProtocolFailure,
97 error.BlockedByFirewall,
98 error.Unexpected => {
99 @panic("TODO handle this error");
100 },
101 }
102 }
103 }
104};
105
106pub const Loop = struct {
107 allocator: &mem.Allocator,
108 epollfd: i32,
109 keep_running: bool,
110
111 fn init(allocator: &mem.Allocator) !Loop {
112 const epollfd = try std.os.linuxEpollCreate(std.os.linux.EPOLL_CLOEXEC);
113 return Loop {
114 .keep_running = true,
115 .allocator = allocator,
116 .epollfd = epollfd,
117 };
118 }
119
120 pub fn addFd(self: &Loop, fd: i32, prom: promise) !void {
121 var ev = std.os.linux.epoll_event {
122 .events = std.os.linux.EPOLLIN|std.os.linux.EPOLLOUT|std.os.linux.EPOLLET,
123 .data = std.os.linux.epoll_data {
124 .ptr = @ptrToInt(prom),
125 },
126 };
127 try std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_ADD, fd, &ev);
128 }
129
130 pub fn removeFd(self: &Loop, fd: i32) void {
131 std.os.linuxEpollCtl(self.epollfd, std.os.linux.EPOLL_CTL_DEL, fd, undefined) catch {};
132 }
133
134 async fn waitFd(self: &Loop, fd: i32) !void {
135 defer self.removeFd(fd);
136 suspend |p| {
137 try self.addFd(fd, p);
138 }
139 }
140
141 pub fn stop(self: &Loop) void {
142 // TODO make atomic
143 self.keep_running = false;
144 // TODO activate an fd in the epoll set
145 }
146
147 pub fn run(self: &Loop) void {
148 while (self.keep_running) {
149 var events: [16]std.os.linux.epoll_event = undefined;
150 const count = std.os.linuxEpollWait(self.epollfd, events[0..], -1);
151 for (events[0..count]) |ev| {
152 const p = @intToPtr(promise, ev.data.ptr);
153 resume p;
154 }
155 }
156 }
157};
158
159pub async fn connect(loop: &Loop, _address: &const std.net.Address) !std.os.File {
160 var address = *_address; // TODO https://github.com/zig-lang/zig/issues/733
161
162 const sockfd = try std.os.posixSocket(posix.AF_INET, posix.SOCK_STREAM|posix.SOCK_CLOEXEC|posix.SOCK_NONBLOCK, posix.PROTO_tcp);
163 errdefer std.os.close(sockfd);
164
165 try std.os.posixConnectAsync(sockfd, &address.os_addr);
166 try await try async loop.waitFd(sockfd);
167 try std.os.posixGetSockOptConnectError(sockfd);
168
169 return std.os.File.openHandle(sockfd);
170}
171
172test "listen on a port, send bytes, receive bytes" {
173 if (builtin.os != builtin.Os.linux) {
174 // TODO build abstractions for other operating systems
175 return;
176 }
177 const MyServer = struct {
178 tcp_server: TcpServer,
179
180 const Self = this;
181
182 async<&mem.Allocator> fn handler(tcp_server: &TcpServer, _addr: &const std.net.Address,
183 _socket: &const std.os.File) void
184 {
185 const self = @fieldParentPtr(Self, "tcp_server", tcp_server);
186 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
187 defer socket.close();
188 const next_handler = async errorableHandler(self, _addr, socket) catch |err| switch (err) {
189 error.OutOfMemory => @panic("unable to handle connection: out of memory"),
190 };
191 (await next_handler) catch |err| {
192 std.debug.panic("unable to handle connection: {}\n", err);
193 };
194 suspend |p| { cancel p; }
195 }
196
197 async fn errorableHandler(self: &Self, _addr: &const std.net.Address,
198 _socket: &const std.os.File) !void
199 {
200 const addr = *_addr; // TODO https://github.com/zig-lang/zig/issues/733
201 var socket = *_socket; // TODO https://github.com/zig-lang/zig/issues/733
202
203 var adapter = std.io.FileOutStream.init(&socket);
204 var stream = &adapter.stream;
205 try stream.print("hello from server\n");
206 }
207 };
208
209 const ip4addr = std.net.parseIp4("127.0.0.1") catch unreachable;
210 const addr = std.net.Address.initIp4(ip4addr, 0);
211
212 var loop = try Loop.init(std.debug.global_allocator);
213 var server = MyServer {
214 .tcp_server = try TcpServer.init(&loop),
215 };
216 defer server.tcp_server.deinit();
217 try server.tcp_server.listen(addr, MyServer.handler);
218
219 const p = try async<std.debug.global_allocator> doAsyncTest(&loop, server.tcp_server.listen_address);
220 defer cancel p;
221 loop.run();
222}
223
224async fn doAsyncTest(loop: &Loop, address: &const std.net.Address) void {
225 errdefer @panic("test failure");
226
227 var socket_file = try await try async event.connect(loop, address);
228 defer socket_file.close();
229
230 var buf: [512]u8 = undefined;
231 const amt_read = try socket_file.read(buf[0..]);
232 const msg = buf[0..amt_read];
233 assert(mem.eql(u8, msg, "hello from server\n"));
234 loop.stop();
235}
std/fmt/index.zig+1-1
...@@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned...@@ -465,7 +465,7 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
465 return x;465 return x;
466}466}
467467
468fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {468pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
469 const value = switch (c) {469 const value = switch (c) {
470 '0' ... '9' => c - '0',470 '0' ... '9' => c - '0',
471 'A' ... 'Z' => c - 'A' + 10,471 'A' ... 'Z' => c - 'A' + 10,
std/hash/adler.zig created+112
...@@ -0,0 +1,112 @@
1// Adler32 checksum.
2//
3// https://tools.ietf.org/html/rfc1950#section-9
4// https://github.com/madler/zlib/blob/master/adler32.c
5
6const std = @import("../index.zig");
7const debug = std.debug;
8
9pub const Adler32 = struct {
10 const base = 65521;
11 const nmax = 5552;
12
13 adler: u32,
14
15 pub fn init() Adler32 {
16 return Adler32 {
17 .adler = 1,
18 };
19 }
20
21 // This fast variant is taken from zlib. It reduces the required modulos and unrolls longer
22 // buffer inputs and should be much quicker.
23 pub fn update(self: &Adler32, input: []const u8) void {
24 var s1 = self.adler & 0xffff;
25 var s2 = (self.adler >> 16) & 0xffff;
26
27 if (input.len == 1) {
28 s1 +%= input[0];
29 if (s1 >= base) {
30 s1 -= base;
31 }
32 s2 +%= s1;
33 if (s2 >= base) {
34 s2 -= base;
35 }
36 }
37 else if (input.len < 16) {
38 for (input) |b| {
39 s1 +%= b;
40 s2 +%= s1;
41 }
42 if (s1 >= base) {
43 s1 -= base;
44 }
45
46 s2 %= base;
47 }
48 else {
49 var i: usize = 0;
50 while (i + nmax <= input.len) : (i += nmax) {
51 const n = nmax / 16; // note: 16 | nmax
52
53 var rounds: usize = 0;
54 while (rounds < n) : (rounds += 1) {
55 comptime var j: usize = 0;
56 inline while (j < 16) : (j += 1) {
57 s1 +%= input[i + n * j];
58 s2 +%= s1;
59 }
60 }
61 }
62
63 if (i < input.len) {
64 while (i + 16 <= input.len) : (i += 16) {
65 comptime var j: usize = 0;
66 inline while (j < 16) : (j += 1) {
67 s1 +%= input[i + j];
68 s2 +%= s1;
69 }
70 }
71 while (i < input.len) : (i += 1) {
72 s1 +%= input[i];
73 s2 +%= s1;
74 }
75
76 s1 %= base;
77 s2 %= base;
78 }
79 }
80
81 self.adler = s1 | (s2 << 16);
82 }
83
84 pub fn final(self: &Adler32) u32 {
85 return self.adler;
86 }
87
88 pub fn hash(input: []const u8) u32 {
89 var c = Adler32.init();
90 c.update(input);
91 return c.final();
92 }
93};
94
95test "adler32 sanity" {
96 debug.assert(Adler32.hash("a") == 0x620062);
97 debug.assert(Adler32.hash("example") == 0xbc002ed);
98}
99
100test "adler32 long" {
101 const long1 = []u8 {1} ** 1024;
102 debug.assert(Adler32.hash(long1[0..]) == 0x06780401);
103
104 const long2 = []u8 {1} ** 1025;
105 debug.assert(Adler32.hash(long2[0..]) == 0x0a7a0402);
106}
107
108test "adler32 very long" {
109 const long = []u8 {1} ** 5553;
110 debug.assert(Adler32.hash(long[0..]) == 0x707f15b2);
111}
112
std/hash/crc.zig created+180
...@@ -0,0 +1,180 @@
1// There are two implementations of CRC32 implemented with the following key characteristics:
2//
3// - Crc32WithPoly uses 8Kb of tables but is ~10x faster than the small method.
4//
5// - Crc32SmallWithPoly uses only 64 bytes of memory but is slower. Be aware that this is
6// still moderately fast just slow relative to the slicing approach.
7
8const std = @import("../index.zig");
9const debug = std.debug;
10
11pub const Polynomial = struct {
12 const IEEE = 0xedb88320;
13 const Castagnoli = 0x82f63b78;
14 const Koopman = 0xeb31d82e;
15};
16
17// IEEE is by far the most common CRC and so is aliased by default.
18pub const Crc32 = Crc32WithPoly(Polynomial.IEEE);
19
20// slicing-by-8 crc32 implementation.
21pub fn Crc32WithPoly(comptime poly: u32) type {
22 return struct {
23 const Self = this;
24 const lookup_tables = comptime block: {
25 @setEvalBranchQuota(20000);
26 var tables: [8][256]u32 = undefined;
27
28 for (tables[0]) |*e, i| {
29 var crc = u32(i);
30 var j: usize = 0; while (j < 8) : (j += 1) {
31 if (crc & 1 == 1) {
32 crc = (crc >> 1) ^ poly;
33 } else {
34 crc = (crc >> 1);
35 }
36 }
37 *e = crc;
38 }
39
40 var i: usize = 0;
41 while (i < 256) : (i += 1) {
42 var crc = tables[0][i];
43 var j: usize = 1; while (j < 8) : (j += 1) {
44 const index = @truncate(u8, crc);
45 crc = tables[0][index] ^ (crc >> 8);
46 tables[j][i] = crc;
47 }
48 }
49
50 break :block tables;
51 };
52
53 crc: u32,
54
55 pub fn init() Self {
56 return Self {
57 .crc = 0xffffffff,
58 };
59 }
60
61 pub fn update(self: &Self, input: []const u8) void {
62 var i: usize = 0;
63 while (i + 8 <= input.len) : (i += 8) {
64 const p = input[i..i+8];
65
66 // Unrolling this way gives ~50Mb/s increase
67 self.crc ^= (u32(p[0]) << 0);
68 self.crc ^= (u32(p[1]) << 8);
69 self.crc ^= (u32(p[2]) << 16);
70 self.crc ^= (u32(p[3]) << 24);
71
72 self.crc =
73 lookup_tables[0][p[7]] ^
74 lookup_tables[1][p[6]] ^
75 lookup_tables[2][p[5]] ^
76 lookup_tables[3][p[4]] ^
77 lookup_tables[4][@truncate(u8, self.crc >> 24)] ^
78 lookup_tables[5][@truncate(u8, self.crc >> 16)] ^
79 lookup_tables[6][@truncate(u8, self.crc >> 8)] ^
80 lookup_tables[7][@truncate(u8, self.crc >> 0)];
81 }
82
83 while (i < input.len) : (i += 1) {
84 const index = @truncate(u8, self.crc) ^ input[i];
85 self.crc = (self.crc >> 8) ^ lookup_tables[0][index];
86 }
87 }
88
89 pub fn final(self: &Self) u32 {
90 return ~self.crc;
91 }
92
93 pub fn hash(input: []const u8) u32 {
94 var c = Self.init();
95 c.update(input);
96 return c.final();
97 }
98 };
99}
100
101test "crc32 ieee" {
102 const Crc32Ieee = Crc32WithPoly(Polynomial.IEEE);
103
104 debug.assert(Crc32Ieee.hash("") == 0x00000000);
105 debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
106 debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
107}
108
109test "crc32 castagnoli" {
110 const Crc32Castagnoli = Crc32WithPoly(Polynomial.Castagnoli);
111
112 debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
113 debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
114 debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
115}
116
117// half-byte lookup table implementation.
118pub fn Crc32SmallWithPoly(comptime poly: u32) type {
119 return struct {
120 const Self = this;
121 const lookup_table = comptime block: {
122 var table: [16]u32 = undefined;
123
124 for (table) |*e, i| {
125 var crc = u32(i * 16);
126 var j: usize = 0; while (j < 8) : (j += 1) {
127 if (crc & 1 == 1) {
128 crc = (crc >> 1) ^ poly;
129 } else {
130 crc = (crc >> 1);
131 }
132 }
133 *e = crc;
134 }
135
136 break :block table;
137 };
138
139 crc: u32,
140
141 pub fn init() Self {
142 return Self {
143 .crc = 0xffffffff,
144 };
145 }
146
147 pub fn update(self: &Self, input: []const u8) void {
148 for (input) |b| {
149 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 0))] ^ (self.crc >> 4);
150 self.crc = lookup_table[@truncate(u4, self.crc ^ (b >> 4))] ^ (self.crc >> 4);
151 }
152 }
153
154 pub fn final(self: &Self) u32 {
155 return ~self.crc;
156 }
157
158 pub fn hash(input: []const u8) u32 {
159 var c = Self.init();
160 c.update(input);
161 return c.final();
162 }
163 };
164}
165
166test "small crc32 ieee" {
167 const Crc32Ieee = Crc32SmallWithPoly(Polynomial.IEEE);
168
169 debug.assert(Crc32Ieee.hash("") == 0x00000000);
170 debug.assert(Crc32Ieee.hash("a") == 0xe8b7be43);
171 debug.assert(Crc32Ieee.hash("abc") == 0x352441c2);
172}
173
174test "small crc32 castagnoli" {
175 const Crc32Castagnoli = Crc32SmallWithPoly(Polynomial.Castagnoli);
176
177 debug.assert(Crc32Castagnoli.hash("") == 0x00000000);
178 debug.assert(Crc32Castagnoli.hash("a") == 0xc1d04330);
179 debug.assert(Crc32Castagnoli.hash("abc") == 0x364b3fb7);
180}
std/hash/fnv.zig created+60
...@@ -0,0 +1,60 @@
1// FNV1a - Fowler-Noll-Vo hash function
2//
3// FNV1a is a fast, non-cryptographic hash function with fairly good distribution properties.
4//
5// https://tools.ietf.org/html/draft-eastlake-fnv-14
6
7const std = @import("../index.zig");
8const debug = std.debug;
9
10pub const Fnv1a_32 = Fnv1a(u32, 0x01000193 , 0x811c9dc5);
11pub const Fnv1a_64 = Fnv1a(u64, 0x100000001b3, 0xcbf29ce484222325);
12pub const Fnv1a_128 = Fnv1a(u128, 0x1000000000000000000013b, 0x6c62272e07bb014262b821756295c58d);
13
14fn Fnv1a(comptime T: type, comptime prime: T, comptime offset: T) type {
15 return struct {
16 const Self = this;
17
18 value: T,
19
20 pub fn init() Self {
21 return Self {
22 .value = offset,
23 };
24 }
25
26 pub fn update(self: &Self, input: []const u8) void {
27 for (input) |b| {
28 self.value ^= b;
29 self.value *%= prime;
30 }
31 }
32
33 pub fn final(self: &Self) T {
34 return self.value;
35 }
36
37 pub fn hash(input: []const u8) T {
38 var c = Self.init();
39 c.update(input);
40 return c.final();
41 }
42 };
43}
44
45test "fnv1a-32" {
46 debug.assert(Fnv1a_32.hash("") == 0x811c9dc5);
47 debug.assert(Fnv1a_32.hash("a") == 0xe40c292c);
48 debug.assert(Fnv1a_32.hash("foobar") == 0xbf9cf968);
49}
50
51test "fnv1a-64" {
52 debug.assert(Fnv1a_64.hash("") == 0xcbf29ce484222325);
53 debug.assert(Fnv1a_64.hash("a") == 0xaf63dc4c8601ec8c);
54 debug.assert(Fnv1a_64.hash("foobar") == 0x85944171f73967e8);
55}
56
57test "fnv1a-128" {
58 debug.assert(Fnv1a_128.hash("") == 0x6c62272e07bb014262b821756295c58d);
59 debug.assert(Fnv1a_128.hash("a") == 0xd228cb696f1a8caf78912b704e4a8964);
60}
std/hash/index.zig created+22
...@@ -0,0 +1,22 @@
1const adler = @import("adler.zig");
2pub const Adler32 = adler.Adler32;
3
4// pub for polynomials + generic crc32 construction
5pub const crc = @import("crc.zig");
6pub const Crc32 = crc.Crc32;
7
8const fnv = @import("fnv.zig");
9pub const Fnv1a_32 = fnv.Fnv1a_32;
10pub const Fnv1a_64 = fnv.Fnv1a_64;
11pub const Fnv1a_128 = fnv.Fnv1a_128;
12
13const siphash = @import("siphash.zig");
14pub const SipHash64 = siphash.SipHash64;
15pub const SipHash128 = siphash.SipHash128;
16
17test "hash" {
18 _ = @import("adler.zig");
19 _ = @import("crc.zig");
20 _ = @import("fnv.zig");
21 _ = @import("siphash.zig");
22}
std/hash/siphash.zig created+320
...@@ -0,0 +1,320 @@
1// Siphash
2//
3// SipHash is a moderately fast, non-cryptographic keyed hash function designed for resistance
4// against hash flooding DoS attacks.
5//
6// https://131002.net/siphash/
7
8const std = @import("../index.zig");
9const debug = std.debug;
10const math = std.math;
11const mem = std.mem;
12
13const Endian = @import("builtin").Endian;
14
15pub fn SipHash64(comptime c_rounds: usize, comptime d_rounds: usize) type {
16 return SipHash(u64, c_rounds, d_rounds);
17}
18
19pub fn SipHash128(comptime c_rounds: usize, comptime d_rounds: usize) type {
20 return SipHash(u128, c_rounds, d_rounds);
21}
22
23fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize) type {
24 debug.assert(T == u64 or T == u128);
25 debug.assert(c_rounds > 0 and d_rounds > 0);
26
27 return struct {
28 const Self = this;
29 const digest_size = 64;
30 const block_size = 64;
31
32 v0: u64,
33 v1: u64,
34 v2: u64,
35 v3: u64,
36
37 // streaming cache
38 buf: [8]u8,
39 buf_len: usize,
40 msg_len: u8,
41
42 pub fn init(key: []const u8) Self {
43 debug.assert(key.len >= 16);
44
45 const k0 = mem.readInt(key[0..8], u64, Endian.Little);
46 const k1 = mem.readInt(key[8..16], u64, Endian.Little);
47
48 var d = Self {
49 .v0 = k0 ^ 0x736f6d6570736575,
50 .v1 = k1 ^ 0x646f72616e646f6d,
51 .v2 = k0 ^ 0x6c7967656e657261,
52 .v3 = k1 ^ 0x7465646279746573,
53
54 .buf = undefined,
55 .buf_len = 0,
56 .msg_len = 0,
57 };
58
59 if (T == u128) {
60 d.v1 ^= 0xee;
61 }
62
63 return d;
64 }
65
66 pub fn update(d: &Self, b: []const u8) void {
67 var off: usize = 0;
68
69 // Partial from previous.
70 if (d.buf_len != 0 and d.buf_len + b.len > 8) {
71 off += 8 - d.buf_len;
72 mem.copy(u8, d.buf[d.buf_len..], b[0..off]);
73 d.round(d.buf[0..]);
74 d.buf_len = 0;
75 }
76
77 // Full middle blocks.
78 while (off + 8 <= b.len) : (off += 8) {
79 d.round(b[off..off + 8]);
80 }
81
82 // Remainder for next pass.
83 mem.copy(u8, d.buf[d.buf_len..], b[off..]);
84 d.buf_len += u8(b[off..].len);
85 d.msg_len +%= @truncate(u8, b.len);
86 }
87
88 pub fn final(d: &Self) T {
89 // Padding
90 mem.set(u8, d.buf[d.buf_len..], 0);
91 d.buf[7] = d.msg_len;
92 d.round(d.buf[0..]);
93
94 if (T == u128) {
95 d.v2 ^= 0xee;
96 } else {
97 d.v2 ^= 0xff;
98 }
99
100 comptime var i: usize = 0;
101 inline while (i < d_rounds) : (i += 1) {
102 @inlineCall(sipRound, d);
103 }
104
105 const b1 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3;
106 if (T == u64) {
107 return b1;
108 }
109
110 d.v1 ^= 0xdd;
111
112 comptime var j: usize = 0;
113 inline while (j < d_rounds) : (j += 1) {
114 @inlineCall(sipRound, d);
115 }
116
117 const b2 = d.v0 ^ d.v1 ^ d.v2 ^ d.v3;
118 return (u128(b2) << 64) | b1;
119 }
120
121 fn round(d: &Self, b: []const u8) void {
122 debug.assert(b.len == 8);
123
124 const m = mem.readInt(b[0..], u64, Endian.Little);
125 d.v3 ^= m;
126
127 comptime var i: usize = 0;
128 inline while (i < c_rounds) : (i += 1) {
129 @inlineCall(sipRound, d);
130 }
131
132 d.v0 ^= m;
133 }
134
135 fn sipRound(d: &Self) void {
136 d.v0 +%= d.v1;
137 d.v1 = math.rotl(u64, d.v1, u64(13));
138 d.v1 ^= d.v0;
139 d.v0 = math.rotl(u64, d.v0, u64(32));
140 d.v2 +%= d.v3;
141 d.v3 = math.rotl(u64, d.v3, u64(16));
142 d.v3 ^= d.v2;
143 d.v0 +%= d.v3;
144 d.v3 = math.rotl(u64, d.v3, u64(21));
145 d.v3 ^= d.v0;
146 d.v2 +%= d.v1;
147 d.v1 = math.rotl(u64, d.v1, u64(17));
148 d.v1 ^= d.v2;
149 d.v2 = math.rotl(u64, d.v2, u64(32));
150 }
151
152 pub fn hash(key: []const u8, input: []const u8) T {
153 var c = Self.init(key);
154 c.update(input);
155 return c.final();
156 }
157 };
158}
159
160// Test vectors from reference implementation.
161// https://github.com/veorq/SipHash/blob/master/vectors.h
162const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
163
164test "siphash64-2-4 sanity" {
165 const vectors = [][]const u8 {
166 "\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
167 "\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
168 "\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
169 "\x2d\x7e\xfb\xd7\x96\x66\x67\x85",
170 "\xb7\x87\x71\x27\xe0\x94\x27\xcf",
171 "\x8d\xa6\x99\xcd\x64\x55\x76\x18",
172 "\xce\xe3\xfe\x58\x6e\x46\xc9\xcb",
173 "\x37\xd1\x01\x8b\xf5\x00\x02\xab",
174 "\x62\x24\x93\x9a\x79\xf5\xf5\x93",
175 "\xb0\xe4\xa9\x0b\xdf\x82\x00\x9e",
176 "\xf3\xb9\xdd\x94\xc5\xbb\x5d\x7a",
177 "\xa7\xad\x6b\x22\x46\x2f\xb3\xf4",
178 "\xfb\xe5\x0e\x86\xbc\x8f\x1e\x75",
179 "\x90\x3d\x84\xc0\x27\x56\xea\x14",
180 "\xee\xf2\x7a\x8e\x90\xca\x23\xf7",
181 "\xe5\x45\xbe\x49\x61\xca\x29\xa1",
182 "\xdb\x9b\xc2\x57\x7f\xcc\x2a\x3f",
183 "\x94\x47\xbe\x2c\xf5\xe9\x9a\x69",
184 "\x9c\xd3\x8d\x96\xf0\xb3\xc1\x4b",
185 "\xbd\x61\x79\xa7\x1d\xc9\x6d\xbb",
186 "\x98\xee\xa2\x1a\xf2\x5c\xd6\xbe",
187 "\xc7\x67\x3b\x2e\xb0\xcb\xf2\xd0",
188 "\x88\x3e\xa3\xe3\x95\x67\x53\x93",
189 "\xc8\xce\x5c\xcd\x8c\x03\x0c\xa8",
190 "\x94\xaf\x49\xf6\xc6\x50\xad\xb8",
191 "\xea\xb8\x85\x8a\xde\x92\xe1\xbc",
192 "\xf3\x15\xbb\x5b\xb8\x35\xd8\x17",
193 "\xad\xcf\x6b\x07\x63\x61\x2e\x2f",
194 "\xa5\xc9\x1d\xa7\xac\xaa\x4d\xde",
195 "\x71\x65\x95\x87\x66\x50\xa2\xa6",
196 "\x28\xef\x49\x5c\x53\xa3\x87\xad",
197 "\x42\xc3\x41\xd8\xfa\x92\xd8\x32",
198 "\xce\x7c\xf2\x72\x2f\x51\x27\x71",
199 "\xe3\x78\x59\xf9\x46\x23\xf3\xa7",
200 "\x38\x12\x05\xbb\x1a\xb0\xe0\x12",
201 "\xae\x97\xa1\x0f\xd4\x34\xe0\x15",
202 "\xb4\xa3\x15\x08\xbe\xff\x4d\x31",
203 "\x81\x39\x62\x29\xf0\x90\x79\x02",
204 "\x4d\x0c\xf4\x9e\xe5\xd4\xdc\xca",
205 "\x5c\x73\x33\x6a\x76\xd8\xbf\x9a",
206 "\xd0\xa7\x04\x53\x6b\xa9\x3e\x0e",
207 "\x92\x59\x58\xfc\xd6\x42\x0c\xad",
208 "\xa9\x15\xc2\x9b\xc8\x06\x73\x18",
209 "\x95\x2b\x79\xf3\xbc\x0a\xa6\xd4",
210 "\xf2\x1d\xf2\xe4\x1d\x45\x35\xf9",
211 "\x87\x57\x75\x19\x04\x8f\x53\xa9",
212 "\x10\xa5\x6c\xf5\xdf\xcd\x9a\xdb",
213 "\xeb\x75\x09\x5c\xcd\x98\x6c\xd0",
214 "\x51\xa9\xcb\x9e\xcb\xa3\x12\xe6",
215 "\x96\xaf\xad\xfc\x2c\xe6\x66\xc7",
216 "\x72\xfe\x52\x97\x5a\x43\x64\xee",
217 "\x5a\x16\x45\xb2\x76\xd5\x92\xa1",
218 "\xb2\x74\xcb\x8e\xbf\x87\x87\x0a",
219 "\x6f\x9b\xb4\x20\x3d\xe7\xb3\x81",
220 "\xea\xec\xb2\xa3\x0b\x22\xa8\x7f",
221 "\x99\x24\xa4\x3c\xc1\x31\x57\x24",
222 "\xbd\x83\x8d\x3a\xaf\xbf\x8d\xb7",
223 "\x0b\x1a\x2a\x32\x65\xd5\x1a\xea",
224 "\x13\x50\x79\xa3\x23\x1c\xe6\x60",
225 "\x93\x2b\x28\x46\xe4\xd7\x06\x66",
226 "\xe1\x91\x5f\x5c\xb1\xec\xa4\x6c",
227 "\xf3\x25\x96\x5c\xa1\x6d\x62\x9f",
228 "\x57\x5f\xf2\x8e\x60\x38\x1b\xe5",
229 "\x72\x45\x06\xeb\x4c\x32\x8a\x95",
230 };
231
232 const siphash = SipHash64(2, 4);
233
234 var buffer: [64]u8 = undefined;
235 for (vectors) |vector, i| {
236 buffer[i] = u8(i);
237
238 const expected = mem.readInt(vector, u64, Endian.Little);
239 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
240 }
241}
242
243test "siphash128-2-4 sanity" {
244 const vectors = [][]const u8 {
245 "\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
246 "\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
247 "\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
248 "\x9c\x70\xb6\x0c\x52\x67\xa9\x4e\x5f\x33\xb6\xb0\x29\x85\xed\x51",
249 "\xf8\x81\x64\xc1\x2d\x9c\x8f\xaf\x7d\x0f\x6e\x7c\x7b\xcd\x55\x79",
250 "\x13\x68\x87\x59\x80\x77\x6f\x88\x54\x52\x7a\x07\x69\x0e\x96\x27",
251 "\x14\xee\xca\x33\x8b\x20\x86\x13\x48\x5e\xa0\x30\x8f\xd7\xa1\x5e",
252 "\xa1\xf1\xeb\xbe\xd8\xdb\xc1\x53\xc0\xb8\x4a\xa6\x1f\xf0\x82\x39",
253 "\x3b\x62\xa9\xba\x62\x58\xf5\x61\x0f\x83\xe2\x64\xf3\x14\x97\xb4",
254 "\x26\x44\x99\x06\x0a\xd9\xba\xab\xc4\x7f\x8b\x02\xbb\x6d\x71\xed",
255 "\x00\x11\x0d\xc3\x78\x14\x69\x56\xc9\x54\x47\xd3\xf3\xd0\xfb\xba",
256 "\x01\x51\xc5\x68\x38\x6b\x66\x77\xa2\xb4\xdc\x6f\x81\xe5\xdc\x18",
257 "\xd6\x26\xb2\x66\x90\x5e\xf3\x58\x82\x63\x4d\xf6\x85\x32\xc1\x25",
258 "\x98\x69\xe2\x47\xe9\xc0\x8b\x10\xd0\x29\x93\x4f\xc4\xb9\x52\xf7",
259 "\x31\xfc\xef\xac\x66\xd7\xde\x9c\x7e\xc7\x48\x5f\xe4\x49\x49\x02",
260 "\x54\x93\xe9\x99\x33\xb0\xa8\x11\x7e\x08\xec\x0f\x97\xcf\xc3\xd9",
261 "\x6e\xe2\xa4\xca\x67\xb0\x54\xbb\xfd\x33\x15\xbf\x85\x23\x05\x77",
262 "\x47\x3d\x06\xe8\x73\x8d\xb8\x98\x54\xc0\x66\xc4\x7a\xe4\x77\x40",
263 "\xa4\x26\xe5\xe4\x23\xbf\x48\x85\x29\x4d\xa4\x81\xfe\xae\xf7\x23",
264 "\x78\x01\x77\x31\xcf\x65\xfa\xb0\x74\xd5\x20\x89\x52\x51\x2e\xb1",
265 "\x9e\x25\xfc\x83\x3f\x22\x90\x73\x3e\x93\x44\xa5\xe8\x38\x39\xeb",
266 "\x56\x8e\x49\x5a\xbe\x52\x5a\x21\x8a\x22\x14\xcd\x3e\x07\x1d\x12",
267 "\x4a\x29\xb5\x45\x52\xd1\x6b\x9a\x46\x9c\x10\x52\x8e\xff\x0a\xae",
268 "\xc9\xd1\x84\xdd\xd5\xa9\xf5\xe0\xcf\x8c\xe2\x9a\x9a\xbf\x69\x1c",
269 "\x2d\xb4\x79\xae\x78\xbd\x50\xd8\x88\x2a\x8a\x17\x8a\x61\x32\xad",
270 "\x8e\xce\x5f\x04\x2d\x5e\x44\x7b\x50\x51\xb9\xea\xcb\x8d\x8f\x6f",
271 "\x9c\x0b\x53\xb4\xb3\xc3\x07\xe8\x7e\xae\xe0\x86\x78\x14\x1f\x66",
272 "\xab\xf2\x48\xaf\x69\xa6\xea\xe4\xbf\xd3\xeb\x2f\x12\x9e\xeb\x94",
273 "\x06\x64\xda\x16\x68\x57\x4b\x88\xb9\x35\xf3\x02\x73\x58\xae\xf4",
274 "\xaa\x4b\x9d\xc4\xbf\x33\x7d\xe9\x0c\xd4\xfd\x3c\x46\x7c\x6a\xb7",
275 "\xea\x5c\x7f\x47\x1f\xaf\x6b\xde\x2b\x1a\xd7\xd4\x68\x6d\x22\x87",
276 "\x29\x39\xb0\x18\x32\x23\xfa\xfc\x17\x23\xde\x4f\x52\xc4\x3d\x35",
277 "\x7c\x39\x56\xca\x5e\xea\xfc\x3e\x36\x3e\x9d\x55\x65\x46\xeb\x68",
278 "\x77\xc6\x07\x71\x46\xf0\x1c\x32\xb6\xb6\x9d\x5f\x4e\xa9\xff\xcf",
279 "\x37\xa6\x98\x6c\xb8\x84\x7e\xdf\x09\x25\xf0\xf1\x30\x9b\x54\xde",
280 "\xa7\x05\xf0\xe6\x9d\xa9\xa8\xf9\x07\x24\x1a\x2e\x92\x3c\x8c\xc8",
281 "\x3d\xc4\x7d\x1f\x29\xc4\x48\x46\x1e\x9e\x76\xed\x90\x4f\x67\x11",
282 "\x0d\x62\xbf\x01\xe6\xfc\x0e\x1a\x0d\x3c\x47\x51\xc5\xd3\x69\x2b",
283 "\x8c\x03\x46\x8b\xca\x7c\x66\x9e\xe4\xfd\x5e\x08\x4b\xbe\xe7\xb5",
284 "\x52\x8a\x5b\xb9\x3b\xaf\x2c\x9c\x44\x73\xcc\xe5\xd0\xd2\x2b\xd9",
285 "\xdf\x6a\x30\x1e\x95\xc9\x5d\xad\x97\xae\x0c\xc8\xc6\x91\x3b\xd8",
286 "\x80\x11\x89\x90\x2c\x85\x7f\x39\xe7\x35\x91\x28\x5e\x70\xb6\xdb",
287 "\xe6\x17\x34\x6a\xc9\xc2\x31\xbb\x36\x50\xae\x34\xcc\xca\x0c\x5b",
288 "\x27\xd9\x34\x37\xef\xb7\x21\xaa\x40\x18\x21\xdc\xec\x5a\xdf\x89",
289 "\x89\x23\x7d\x9d\xed\x9c\x5e\x78\xd8\xb1\xc9\xb1\x66\xcc\x73\x42",
290 "\x4a\x6d\x80\x91\xbf\x5e\x7d\x65\x11\x89\xfa\x94\xa2\x50\xb1\x4c",
291 "\x0e\x33\xf9\x60\x55\xe7\xae\x89\x3f\xfc\x0e\x3d\xcf\x49\x29\x02",
292 "\xe6\x1c\x43\x2b\x72\x0b\x19\xd1\x8e\xc8\xd8\x4b\xdc\x63\x15\x1b",
293 "\xf7\xe5\xae\xf5\x49\xf7\x82\xcf\x37\x90\x55\xa6\x08\x26\x9b\x16",
294 "\x43\x8d\x03\x0f\xd0\xb7\xa5\x4f\xa8\x37\xf2\xad\x20\x1a\x64\x03",
295 "\xa5\x90\xd3\xee\x4f\xbf\x04\xe3\x24\x7e\x0d\x27\xf2\x86\x42\x3f",
296 "\x5f\xe2\xc1\xa1\x72\xfe\x93\xc4\xb1\x5c\xd3\x7c\xae\xf9\xf5\x38",
297 "\x2c\x97\x32\x5c\xbd\x06\xb3\x6e\xb2\x13\x3d\xd0\x8b\x3a\x01\x7c",
298 "\x92\xc8\x14\x22\x7a\x6b\xca\x94\x9f\xf0\x65\x9f\x00\x2a\xd3\x9e",
299 "\xdc\xe8\x50\x11\x0b\xd8\x32\x8c\xfb\xd5\x08\x41\xd6\x91\x1d\x87",
300 "\x67\xf1\x49\x84\xc7\xda\x79\x12\x48\xe3\x2b\xb5\x92\x25\x83\xda",
301 "\x19\x38\xf2\xcf\x72\xd5\x4e\xe9\x7e\x94\x16\x6f\xa9\x1d\x2a\x36",
302 "\x74\x48\x1e\x96\x46\xed\x49\xfe\x0f\x62\x24\x30\x16\x04\x69\x8e",
303 "\x57\xfc\xa5\xde\x98\xa9\xd6\xd8\x00\x64\x38\xd0\x58\x3d\x8a\x1d",
304 "\x9f\xec\xde\x1c\xef\xdc\x1c\xbe\xd4\x76\x36\x74\xd9\x57\x53\x59",
305 "\xe3\x04\x0c\x00\xeb\x28\xf1\x53\x66\xca\x73\xcb\xd8\x72\xe7\x40",
306 "\x76\x97\x00\x9a\x6a\x83\x1d\xfe\xcc\xa9\x1c\x59\x93\x67\x0f\x7a",
307 "\x58\x53\x54\x23\x21\xf5\x67\xa0\x05\xd5\x47\xa4\xf0\x47\x59\xbd",
308 "\x51\x50\xd1\x77\x2f\x50\x83\x4a\x50\x3e\x06\x9a\x97\x3f\xbd\x7c",
309 };
310
311 const siphash = SipHash128(2, 4);
312
313 var buffer: [64]u8 = undefined;
314 for (vectors) |vector, i| {
315 buffer[i] = u8(i);
316
317 const expected = mem.readInt(vector, u128, Endian.Little);
318 debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
319 }
320}
std/index.zig+5-3
...@@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig");...@@ -17,8 +17,9 @@ pub const debug = @import("debug/index.zig");
17pub const dwarf = @import("dwarf.zig");17pub const dwarf = @import("dwarf.zig");
18pub const elf = @import("elf.zig");18pub const elf = @import("elf.zig");
19pub const empty_import = @import("empty.zig");19pub const empty_import = @import("empty.zig");
20pub const endian = @import("endian.zig");20pub const event = @import("event.zig");
21pub const fmt = @import("fmt/index.zig");21pub const fmt = @import("fmt/index.zig");
22pub const hash = @import("hash/index.zig");
22pub const heap = @import("heap.zig");23pub const heap = @import("heap.zig");
23pub const io = @import("io.zig");24pub const io = @import("io.zig");
24pub const macho = @import("macho.zig");25pub const macho = @import("macho.zig");
...@@ -49,14 +50,15 @@ test "std" {...@@ -49,14 +50,15 @@ test "std" {
49 _ = @import("dwarf.zig");50 _ = @import("dwarf.zig");
50 _ = @import("elf.zig");51 _ = @import("elf.zig");
51 _ = @import("empty.zig");52 _ = @import("empty.zig");
52 _ = @import("endian.zig");53 _ = @import("event.zig");
53 _ = @import("fmt/index.zig");54 _ = @import("fmt/index.zig");
55 _ = @import("hash/index.zig");
54 _ = @import("io.zig");56 _ = @import("io.zig");
55 _ = @import("macho.zig");57 _ = @import("macho.zig");
56 _ = @import("math/index.zig");58 _ = @import("math/index.zig");
57 _ = @import("mem.zig");59 _ = @import("mem.zig");
58 _ = @import("heap.zig");
59 _ = @import("net.zig");60 _ = @import("net.zig");
61 _ = @import("heap.zig");
60 _ = @import("os/index.zig");62 _ = @import("os/index.zig");
61 _ = @import("rand/index.zig");63 _ = @import("rand/index.zig");
62 _ = @import("sort.zig");64 _ = @import("sort.zig");
std/io.zig+26-4
...@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -144,7 +144,7 @@ pub fn InStream(comptime ReadError: type) type {
144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents144 /// If `buffer.len()` would exceed `max_size`, `error.StreamTooLong` is returned and the contents
145 /// read from the stream so far are lost.145 /// read from the stream so far are lost.
146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {146 pub fn readUntilDelimiterBuffer(self: &Self, buffer: &Buffer, delimiter: u8, max_size: usize) !void {
147 try buf.resize(0);147 try buffer.resize(0);
148148
149 while (true) {149 while (true) {
150 var byte: u8 = try self.readByte();150 var byte: u8 = try self.readByte();
...@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {...@@ -153,11 +153,11 @@ pub fn InStream(comptime ReadError: type) type {
153 return;153 return;
154 }154 }
155155
156 if (buf.len() == max_size) {156 if (buffer.len() == max_size) {
157 return error.StreamTooLong;157 return error.StreamTooLong;
158 }158 }
159159
160 try buf.appendByte(byte);160 try buffer.appendByte(byte);
161 }161 }
162 }162 }
163163
...@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {...@@ -171,7 +171,7 @@ pub fn InStream(comptime ReadError: type) type {
171 var buf = Buffer.initNull(allocator);171 var buf = Buffer.initNull(allocator);
172 defer buf.deinit();172 defer buf.deinit();
173173
174 try self.readUntilDelimiterBuffer(self, &buf, delimiter, max_size);174 try self.readUntilDelimiterBuffer(&buf, delimiter, max_size);
175 return buf.toOwnedSlice();175 return buf.toOwnedSlice();
176 }176 }
177177
...@@ -478,3 +478,25 @@ test "import io tests" {...@@ -478,3 +478,25 @@ test "import io tests" {
478 }478 }
479}479}
480480
481pub fn readLine(buf: []u8) !usize {
482 var stdin = getStdIn() catch return error.StdInUnavailable;
483 var adapter = FileInStream.init(&stdin);
484 var stream = &adapter.stream;
485 var index: usize = 0;
486 while (true) {
487 const byte = stream.readByte() catch return error.EndOfFile;
488 switch (byte) {
489 '\r' => {
490 // trash the following \n
491 _ = stream.readByte() catch return error.EndOfFile;
492 return index;
493 },
494 '\n' => return index,
495 else => {
496 if (index == buf.len) return error.InputTooLong;
497 buf[index] = byte;
498 index += 1;
499 },
500 }
501 }
502}
std/linked_list.zig+1
...@@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na...@@ -161,6 +161,7 @@ fn BaseLinkedList(comptime T: type, comptime ParentType: type, comptime field_na
161 }161 }
162162
163 list.len -= 1;163 list.len -= 1;
164 assert(list.len == 0 or (list.first != null and list.last != null));
164 }165 }
165166
166 /// Remove and return the last node in the list.167 /// Remove and return the last node in the list.
std/mem.zig+26
...@@ -3,6 +3,7 @@ const debug = std.debug;...@@ -3,6 +3,7 @@ const debug = std.debug;
3const assert = debug.assert;3const assert = debug.assert;
4const math = std.math;4const math = std.math;
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const mem = this;
67
7pub const Allocator = struct {8pub const Allocator = struct {
8 const Error = error {OutOfMemory};9 const Error = error {OutOfMemory};
...@@ -550,3 +551,28 @@ test "std.mem.rotate" {...@@ -550,3 +551,28 @@ test "std.mem.rotate" {
550551
551 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));552 assert(eql(i32, arr, []i32{ 1, 2, 4, 5, 3 }));
552}553}
554
555// TODO: When https://github.com/zig-lang/zig/issues/649 is solved these can be done by
556// endian-casting the pointer and then dereferencing
557
558pub fn endianSwapIfLe(comptime T: type, x: T) T {
559 return endianSwapIf(builtin.Endian.Little, T, x);
560}
561
562pub fn endianSwapIfBe(comptime T: type, x: T) T {
563 return endianSwapIf(builtin.Endian.Big, T, x);
564}
565
566pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T {
567 return if (builtin.endian == endian) endianSwap(T, x) else x;
568}
569
570pub fn endianSwap(comptime T: type, x: T) T {
571 var buf: [@sizeOf(T)]u8 = undefined;
572 mem.writeInt(buf[0..], x, builtin.Endian.Little);
573 return mem.readInt(buf, T, builtin.Endian.Big);
574}
575
576test "std.mem.endianSwap" {
577 assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
578}
std/net.zig+121-162
...@@ -1,143 +1,120 @@...@@ -1,143 +1,120 @@
1const std = @import("index.zig");1const std = @import("index.zig");
2const linux = std.os.linux;2const builtin = @import("builtin");
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const endian = std.endian;4const net = this;
5const posix = std.os.posix;
6const mem = std.mem;
57
6// TODO don't trust this file, it bit rotted. start over8pub const TmpWinAddr = struct {
79 family: u8,
8const Connection = struct {10 data: [14]u8,
9 socket_fd: i32,
10
11 pub fn send(c: Connection, buf: []const u8) !usize {
12 const send_ret = linux.sendto(c.socket_fd, buf.ptr, buf.len, 0, null, 0);
13 const send_err = linux.getErrno(send_ret);
14 switch (send_err) {
15 0 => return send_ret,
16 linux.EINVAL => unreachable,
17 linux.EFAULT => unreachable,
18 linux.ECONNRESET => return error.ConnectionReset,
19 linux.EINTR => return error.SigInterrupt,
20 // TODO there are more possible errors
21 else => return error.Unexpected,
22 }
23 }
24
25 pub fn recv(c: Connection, buf: []u8) ![]u8 {
26 const recv_ret = linux.recvfrom(c.socket_fd, buf.ptr, buf.len, 0, null, null);
27 const recv_err = linux.getErrno(recv_ret);
28 switch (recv_err) {
29 0 => return buf[0..recv_ret],
30 linux.EINVAL => unreachable,
31 linux.EFAULT => unreachable,
32 linux.ENOTSOCK => return error.NotSocket,
33 linux.EINTR => return error.SigInterrupt,
34 linux.ENOMEM => return error.OutOfMemory,
35 linux.ECONNREFUSED => return error.ConnectionRefused,
36 linux.EBADF => return error.BadFd,
37 // TODO more error values
38 else => return error.Unexpected,
39 }
40 }
41
42 pub fn close(c: Connection) !void {
43 switch (linux.getErrno(linux.close(c.socket_fd))) {
44 0 => return,
45 linux.EBADF => unreachable,
46 linux.EINTR => return error.SigInterrupt,
47 linux.EIO => return error.Io,
48 else => return error.Unexpected,
49 }
50 }
51};11};
5212
53const Address = struct {13pub const OsAddress = switch (builtin.os) {
54 family: u16,14 builtin.Os.windows => TmpWinAddr,
55 scope_id: u32,15 else => posix.sockaddr,
56 addr: [16]u8,
57 sort_key: i32,
58};16};
5917
60pub fn lookup(hostname: []const u8, out_addrs: []Address) ![]Address {18pub const Address = struct {
61 if (hostname.len == 0) {19 os_addr: OsAddress,
6220
63 unreachable; // TODO21 pub fn initIp4(ip4: u32, port: u16) Address {
22 return Address {
23 .os_addr = posix.sockaddr {
24 .in = posix.sockaddr_in {
25 .family = posix.AF_INET,
26 .port = std.mem.endianSwapIfLe(u16, port),
27 .addr = ip4,
28 .zero = []u8{0} ** 8,
29 },
30 },
31 };
64 }32 }
6533
66 unreachable; // TODO34 pub fn initIp6(ip6: &const Ip6Addr, port: u16) Address {
67}35 return Address {
36 .family = posix.AF_INET6,
37 .os_addr = posix.sockaddr {
38 .in6 = posix.sockaddr_in6 {
39 .family = posix.AF_INET6,
40 .port = std.mem.endianSwapIfLe(u16, port),
41 .flowinfo = 0,
42 .addr = ip6.addr,
43 .scope_id = ip6.scope_id,
44 },
45 },
46 };
47 }
6848
69pub fn connectAddr(addr: &Address, port: u16) !Connection {49 pub fn initPosix(addr: &const posix.sockaddr) Address {
70 const socket_ret = linux.socket(addr.family, linux.SOCK_STREAM, linux.PROTO_tcp);50 return Address {
71 const socket_err = linux.getErrno(socket_ret);51 .os_addr = *addr,
72 if (socket_err > 0) {52 };
73 // TODO figure out possible errors from socket()
74 return error.Unexpected;
75 }53 }
76 const socket_fd = i32(socket_ret);
7754
78 const connect_ret = if (addr.family == linux.AF_INET) x: {55 pub fn format(self: &const Address, out_stream: var) !void {
79 var os_addr: linux.sockaddr_in = undefined;56 switch (self.os_addr.in.family) {
80 os_addr.family = addr.family;57 posix.AF_INET => {
81 os_addr.port = endian.swapIfLe(u16, port);58 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
82 @memcpy((&u8)(&os_addr.addr), &addr.addr[0], 4);59 const bytes = ([]const u8)((&self.os_addr.in.addr)[0..1]);
83 @memset(&os_addr.zero[0], 0, @sizeOf(@typeOf(os_addr.zero)));60 try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
84 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in));61 },
85 } else if (addr.family == linux.AF_INET6) x: {62 posix.AF_INET6 => {
86 var os_addr: linux.sockaddr_in6 = undefined;63 const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
87 os_addr.family = addr.family;64 try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
88 os_addr.port = endian.swapIfLe(u16, port);
89 os_addr.flowinfo = 0;
90 os_addr.scope_id = addr.scope_id;
91 @memcpy(&os_addr.addr[0], &addr.addr[0], 16);
92 break :x linux.connect(socket_fd, (&linux.sockaddr)(&os_addr), @sizeOf(linux.sockaddr_in6));
93 } else {
94 unreachable;
95 };
96 const connect_err = linux.getErrno(connect_ret);
97 if (connect_err > 0) {
98 switch (connect_err) {
99 linux.ETIMEDOUT => return error.TimedOut,
100 else => {
101 // TODO figure out possible errors from connect()
102 return error.Unexpected;
103 },65 },
66 else => try out_stream.write("(unrecognized address family)"),
104 }67 }
105 }68 }
69};
10670
107 return Connection {71pub fn parseIp4(buf: []const u8) !u32 {
108 .socket_fd = socket_fd,72 var result: u32 = undefined;
109 };73 const out_ptr = ([]u8)((&result)[0..1]);
110}
111
112pub fn connect(hostname: []const u8, port: u16) !Connection {
113 var addrs_buf: [1]Address = undefined;
114 const addrs_slice = try lookup(hostname, addrs_buf[0..]);
115 const main_addr = &addrs_slice[0];
116
117 return connectAddr(main_addr, port);
118}
11974
120pub fn parseIpLiteral(buf: []const u8) !Address {75 var x: u8 = 0;
76 var index: u8 = 0;
77 var saw_any_digits = false;
78 for (buf) |c| {
79 if (c == '.') {
80 if (!saw_any_digits) {
81 return error.InvalidCharacter;
82 }
83 if (index == 3) {
84 return error.InvalidEnd;
85 }
86 out_ptr[index] = x;
87 index += 1;
88 x = 0;
89 saw_any_digits = false;
90 } else if (c >= '0' and c <= '9') {
91 saw_any_digits = true;
92 const digit = c - '0';
93 if (@mulWithOverflow(u8, x, 10, &x)) {
94 return error.Overflow;
95 }
96 if (@addWithOverflow(u8, x, digit, &x)) {
97 return error.Overflow;
98 }
99 } else {
100 return error.InvalidCharacter;
101 }
102 }
103 if (index == 3 and saw_any_digits) {
104 out_ptr[index] = x;
105 return result;
106 }
121107
122 return error.InvalidIpLiteral;108 return error.Incomplete;
123}109}
124110
125fn hexDigit(c: u8) u8 {111pub const Ip6Addr = struct {
126 // TODO use switch with range112 scope_id: u32,
127 if ('0' <= c and c <= '9') {113 addr: [16]u8,
128 return c - '0';114};
129 } else if ('A' <= c and c <= 'Z') {
130 return c - 'A' + 10;
131 } else if ('a' <= c and c <= 'z') {
132 return c - 'a' + 10;
133 } else {
134 return @maxValue(u8);
135 }
136}
137115
138fn parseIp6(buf: []const u8) !Address {116pub fn parseIp6(buf: []const u8) !Ip6Addr {
139 var result: Address = undefined;117 var result: Ip6Addr = undefined;
140 result.family = linux.AF_INET6;
141 result.scope_id = 0;118 result.scope_id = 0;
142 const ip_slice = result.addr[0..];119 const ip_slice = result.addr[0..];
143120
...@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {...@@ -156,14 +133,14 @@ fn parseIp6(buf: []const u8) !Address {
156 return error.Overflow;133 return error.Overflow;
157 }134 }
158 } else {135 } else {
159 return error.InvalidChar;136 return error.InvalidCharacter;
160 }137 }
161 } else if (c == ':') {138 } else if (c == ':') {
162 if (!saw_any_digits) {139 if (!saw_any_digits) {
163 return error.InvalidChar;140 return error.InvalidCharacter;
164 }141 }
165 if (index == 14) {142 if (index == 14) {
166 return error.JunkAtEnd;143 return error.InvalidEnd;
167 }144 }
168 ip_slice[index] = @truncate(u8, x >> 8);145 ip_slice[index] = @truncate(u8, x >> 8);
169 index += 1;146 index += 1;
...@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {...@@ -174,7 +151,7 @@ fn parseIp6(buf: []const u8) !Address {
174 saw_any_digits = false;151 saw_any_digits = false;
175 } else if (c == '%') {152 } else if (c == '%') {
176 if (!saw_any_digits) {153 if (!saw_any_digits) {
177 return error.InvalidChar;154 return error.InvalidCharacter;
178 }155 }
179 if (index == 14) {156 if (index == 14) {
180 ip_slice[index] = @truncate(u8, x >> 8);157 ip_slice[index] = @truncate(u8, x >> 8);
...@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {...@@ -185,10 +162,7 @@ fn parseIp6(buf: []const u8) !Address {
185 scope_id = true;162 scope_id = true;
186 saw_any_digits = false;163 saw_any_digits = false;
187 } else {164 } else {
188 const digit = hexDigit(c);165 const digit = try std.fmt.charToDigit(c, 16);
189 if (digit == @maxValue(u8)) {
190 return error.InvalidChar;
191 }
192 if (@mulWithOverflow(u16, x, 16, &x)) {166 if (@mulWithOverflow(u16, x, 16, &x)) {
193 return error.Overflow;167 return error.Overflow;
194 }168 }
...@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {...@@ -216,42 +190,27 @@ fn parseIp6(buf: []const u8) !Address {
216 return error.Incomplete;190 return error.Incomplete;
217}191}
218192
219fn parseIp4(buf: []const u8) !u32 {193test "std.net.parseIp4" {
220 var result: u32 = undefined;194 assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
221 const out_ptr = ([]u8)((&result)[0..1]);
222195
223 var x: u8 = 0;196 testParseIp4Fail("256.0.0.1", error.Overflow);
224 var index: u8 = 0;197 testParseIp4Fail("x.0.0.1", error.InvalidCharacter);
225 var saw_any_digits = false;198 testParseIp4Fail("127.0.0.1.1", error.InvalidEnd);
226 for (buf) |c| {199 testParseIp4Fail("127.0.0.", error.Incomplete);
227 if (c == '.') {200 testParseIp4Fail("100..0.1", error.InvalidCharacter);
228 if (!saw_any_digits) {201}
229 return error.InvalidChar;202
230 }203fn testParseIp4Fail(buf: []const u8, expected_err: error) void {
231 if (index == 3) {204 if (parseIp4(buf)) |_| {
232 return error.JunkAtEnd;205 @panic("expected error");
233 }206 } else |e| {
234 out_ptr[index] = x;207 assert(e == expected_err);
235 index += 1;
236 x = 0;
237 saw_any_digits = false;
238 } else if (c >= '0' and c <= '9') {
239 saw_any_digits = true;
240 const digit = c - '0';
241 if (@mulWithOverflow(u8, x, 10, &x)) {
242 return error.Overflow;
243 }
244 if (@addWithOverflow(u8, x, digit, &x)) {
245 return error.Overflow;
246 }
247 } else {
248 return error.InvalidChar;
249 }
250 }
251 if (index == 3 and saw_any_digits) {
252 out_ptr[index] = x;
253 return result;
254 }208 }
209}
255210
256 return error.Incomplete;211test "std.net.parseIp6" {
212 const addr = try parseIp6("FF01:0:0:0:0:0:0:FB");
213 assert(addr.addr[0] == 0xff);
214 assert(addr.addr[1] == 0x01);
215 assert(addr.addr[2] == 0x00);
257}216}
std/os/child_process.zig-35
...@@ -13,8 +13,6 @@ const builtin = @import("builtin");...@@ -13,8 +13,6 @@ const builtin = @import("builtin");
13const Os = builtin.Os;13const Os = builtin.Os;
14const LinkedList = std.LinkedList;14const LinkedList = std.LinkedList;
1515
16var children_nodes = LinkedList(&ChildProcess).init();
17
18const is_windows = builtin.os == Os.windows;16const is_windows = builtin.os == Os.windows;
1917
20pub const ChildProcess = struct {18pub const ChildProcess = struct {
...@@ -296,8 +294,6 @@ pub const ChildProcess = struct {...@@ -296,8 +294,6 @@ pub const ChildProcess = struct {
296 }294 }
297295
298 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {296 fn cleanupAfterWait(self: &ChildProcess, status: i32) !Term {
299 children_nodes.remove(&self.llnode);
300
301 defer {297 defer {
302 os.close(self.err_pipe[0]);298 os.close(self.err_pipe[0]);
303 os.close(self.err_pipe[1]);299 os.close(self.err_pipe[1]);
...@@ -427,9 +423,6 @@ pub const ChildProcess = struct {...@@ -427,9 +423,6 @@ pub const ChildProcess = struct {
427 self.llnode = LinkedList(&ChildProcess).Node.init(self);423 self.llnode = LinkedList(&ChildProcess).Node.init(self);
428 self.term = null;424 self.term = null;
429425
430 // TODO make this atomic so it works even with threads
431 children_nodes.prepend(&self.llnode);
432
433 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }426 if (self.stdin_behavior == StdIo.Pipe) { os.close(stdin_pipe[0]); }
434 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }427 if (self.stdout_behavior == StdIo.Pipe) { os.close(stdout_pipe[1]); }
435 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }428 if (self.stderr_behavior == StdIo.Pipe) { os.close(stderr_pipe[1]); }
...@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {...@@ -773,31 +766,3 @@ fn readIntFd(fd: i32) !ErrInt {
773 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;766 os.posixRead(fd, bytes[0..]) catch return error.SystemResources;
774 return mem.readInt(bytes[0..], ErrInt, builtin.endian);767 return mem.readInt(bytes[0..], ErrInt, builtin.endian);
775}768}
776
777extern fn sigchld_handler(_: i32) void {
778 while (true) {
779 var status: i32 = undefined;
780 const pid_result = posix.waitpid(-1, &status, posix.WNOHANG);
781 if (pid_result == 0) {
782 return;
783 }
784 const err = posix.getErrno(pid_result);
785 if (err > 0) {
786 if (err == posix.ECHILD) {
787 return;
788 }
789 unreachable;
790 }
791 handleTerm(i32(pid_result), status);
792 }
793}
794
795fn handleTerm(pid: i32, status: i32) void {
796 var it = children_nodes.first;
797 while (it) |node| : (it = node.next) {
798 if (node.data.pid == pid) {
799 node.data.handleWaitResult(status);
800 return;
801 }
802 }
803}
std/os/darwin.zig+35
...@@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks...@@ -56,10 +56,32 @@ pub const O_SYMLINK = 0x200000; /// allow open of symlinks
56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only56pub const O_EVTONLY = 0x8000; /// descriptor requested for event notifications only
57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec57pub const O_CLOEXEC = 0x1000000; /// mark as close-on-exec
5858
59pub const O_ACCMODE = 3;
60pub const O_ALERT = 536870912;
61pub const O_ASYNC = 64;
62pub const O_DIRECTORY = 1048576;
63pub const O_DP_GETRAWENCRYPTED = 1;
64pub const O_DP_GETRAWUNENCRYPTED = 2;
65pub const O_DSYNC = 4194304;
66pub const O_FSYNC = O_SYNC;
67pub const O_NOCTTY = 131072;
68pub const O_POPUP = 2147483648;
69pub const O_SYNC = 128;
70
59pub const SEEK_SET = 0x0;71pub const SEEK_SET = 0x0;
60pub const SEEK_CUR = 0x1;72pub const SEEK_CUR = 0x1;
61pub const SEEK_END = 0x2;73pub const SEEK_END = 0x2;
6274
75pub const DT_UNKNOWN = 0;
76pub const DT_FIFO = 1;
77pub const DT_CHR = 2;
78pub const DT_DIR = 4;
79pub const DT_BLK = 6;
80pub const DT_REG = 8;
81pub const DT_LNK = 10;
82pub const DT_SOCK = 12;
83pub const DT_WHT = 14;
84
63pub const SIG_BLOCK = 1; /// block specified signal set85pub const SIG_BLOCK = 1; /// block specified signal set
64pub const SIG_UNBLOCK = 2; /// unblock specified signal set86pub const SIG_UNBLOCK = 2; /// unblock specified signal set
65pub const SIG_SETMASK = 3; /// set specified signal set87pub const SIG_SETMASK = 3; /// set specified signal set
...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {...@@ -192,6 +214,11 @@ pub fn pipe(fds: &[2]i32) usize {
192 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));214 return errnoWrap(c.pipe(@ptrCast(&c_int, fds)));
193}215}
194216
217
218pub fn getdirentries64(fd: i32, buf_ptr: &u8, buf_len: usize, basep: &i64) usize {
219 return errnoWrap(@bitCast(isize, c.__getdirentries64(fd, buf_ptr, buf_len, basep)));
220}
221
195pub fn mkdir(path: &const u8, mode: u32) usize {222pub fn mkdir(path: &const u8, mode: u32) usize {
196 return errnoWrap(c.mkdir(path, mode));223 return errnoWrap(c.mkdir(path, mode));
197}224}
...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {...@@ -204,6 +231,10 @@ pub fn rename(old: &const u8, new: &const u8) usize {
204 return errnoWrap(c.rename(old, new));231 return errnoWrap(c.rename(old, new));
205}232}
206233
234pub fn rmdir(path: &const u8) usize {
235 return errnoWrap(c.rmdir(path));
236}
237
207pub fn chdir(path: &const u8) usize {238pub fn chdir(path: &const u8) usize {
208 return errnoWrap(c.chdir(path));239 return errnoWrap(c.chdir(path));
209}240}
...@@ -268,6 +299,10 @@ pub const empty_sigset = sigset_t(0);...@@ -268,6 +299,10 @@ pub const empty_sigset = sigset_t(0);
268299
269pub const timespec = c.timespec;300pub const timespec = c.timespec;
270pub const Stat = c.Stat;301pub const Stat = c.Stat;
302pub const dirent = c.dirent;
303
304pub const sa_family_t = c.sa_family_t;
305pub const sockaddr = c.sockaddr;
271306
272/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.307/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
273pub const Sigaction = struct {308pub const Sigaction = struct {
std/os/index.zig+603-31
...@@ -4,6 +4,19 @@ const Os = builtin.Os;...@@ -4,6 +4,19 @@ const Os = builtin.Os;
4const is_windows = builtin.os == Os.windows;4const is_windows = builtin.os == Os.windows;
5const os = this;5const os = this;
66
7test "std.os" {
8 _ = @import("child_process.zig");
9 _ = @import("darwin.zig");
10 _ = @import("darwin_errno.zig");
11 _ = @import("get_user_id.zig");
12 _ = @import("linux/errno.zig");
13 _ = @import("linux/index.zig");
14 _ = @import("linux/x86_64.zig");
15 _ = @import("path.zig");
16 _ = @import("test.zig");
17 _ = @import("windows/index.zig");
18}
19
7pub const windows = @import("windows/index.zig");20pub const windows = @import("windows/index.zig");
8pub const darwin = @import("darwin.zig");21pub const darwin = @import("darwin.zig");
9pub const linux = @import("linux/index.zig");22pub const linux = @import("linux/index.zig");
...@@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {...@@ -14,6 +27,7 @@ pub const posix = switch(builtin.os) {
14 Os.zen => zen,27 Os.zen => zen,
15 else => @compileError("Unsupported OS"),28 else => @compileError("Unsupported OS"),
16};29};
30pub const net = @import("net.zig");
1731
18pub const ChildProcess = @import("child_process.zig").ChildProcess;32pub const ChildProcess = @import("child_process.zig").ChildProcess;
19pub const path = @import("path.zig");33pub const path = @import("path.zig");
...@@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {...@@ -173,6 +187,13 @@ pub fn exit(status: u8) noreturn {
173 }187 }
174}188}
175189
190/// When a file descriptor is closed on linux, it pops the first
191/// node from this queue and resumes it.
192/// Async functions which get the EMFILE error code can suspend,
193/// putting their coroutine handle into this list.
194/// TODO make this an atomic linked list
195pub var emfile_promise_queue = std.LinkedList(promise).init();
196
176/// Closes the file handle. Keeps trying if it gets interrupted by a signal.197/// Closes the file handle. Keeps trying if it gets interrupted by a signal.
177pub fn close(handle: FileHandle) void {198pub fn close(handle: FileHandle) void {
178 if (is_windows) {199 if (is_windows) {
...@@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {...@@ -180,10 +201,12 @@ pub fn close(handle: FileHandle) void {
180 } else {201 } else {
181 while (true) {202 while (true) {
182 const err = posix.getErrno(posix.close(handle));203 const err = posix.getErrno(posix.close(handle));
183 if (err == posix.EINTR) {204 switch (err) {
184 continue;205 posix.EINTR => continue,
185 } else {206 else => {
186 return;207 if (emfile_promise_queue.popFirst()) |p| resume p.data;
208 return;
209 },
187 }210 }
188 }211 }
189 }212 }
...@@ -1050,15 +1073,16 @@ const DeleteTreeError = error {...@@ -1050,15 +1073,16 @@ const DeleteTreeError = error {
1050};1073};
1051pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {1074pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!void {
1052 start_over: while (true) {1075 start_over: while (true) {
1076 var got_access_denied = false;
1053 // First, try deleting the item as a file. This way we don't follow sym links.1077 // First, try deleting the item as a file. This way we don't follow sym links.
1054 if (deleteFile(allocator, full_path)) {1078 if (deleteFile(allocator, full_path)) {
1055 return;1079 return;
1056 } else |err| switch (err) {1080 } else |err| switch (err) {
1057 error.FileNotFound => return,1081 error.FileNotFound => return,
1058 error.IsDir => {},1082 error.IsDir => {},
1083 error.AccessDenied => got_access_denied = true,
10591084
1060 error.OutOfMemory,1085 error.OutOfMemory,
1061 error.AccessDenied,
1062 error.SymLinkLoop,1086 error.SymLinkLoop,
1063 error.NameTooLong,1087 error.NameTooLong,
1064 error.SystemResources,1088 error.SystemResources,
...@@ -1071,7 +1095,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1071,7 +1095,12 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1071 }1095 }
1072 {1096 {
1073 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {1097 var dir = Dir.open(allocator, full_path) catch |err| switch (err) {
1074 error.NotDir => continue :start_over,1098 error.NotDir => {
1099 if (got_access_denied) {
1100 return error.AccessDenied;
1101 }
1102 continue :start_over;
1103 },
10751104
1076 error.OutOfMemory,1105 error.OutOfMemory,
1077 error.AccessDenied,1106 error.AccessDenied,
...@@ -1109,18 +1138,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!...@@ -1109,18 +1138,16 @@ pub fn deleteTree(allocator: &Allocator, full_path: []const u8) DeleteTreeError!
1109}1138}
11101139
1111pub const Dir = struct {1140pub const Dir = struct {
1112 // See man getdents
1113 fd: i32,1141 fd: i32,
1142 darwin_seek: darwin_seek_t,
1114 allocator: &Allocator,1143 allocator: &Allocator,
1115 buf: []u8,1144 buf: []u8,
1116 index: usize,1145 index: usize,
1117 end_index: usize,1146 end_index: usize,
11181147
1119 const LinuxEntry = extern struct {1148 const darwin_seek_t = switch (builtin.os) {
1120 d_ino: usize,1149 Os.macosx, Os.ios => i64,
1121 d_off: usize,1150 else => void,
1122 d_reclen: u16,
1123 d_name: u8, // field address is the address of first byte of name
1124 };1151 };
11251152
1126 pub const Entry = struct {1153 pub const Entry = struct {
...@@ -1135,15 +1162,26 @@ pub const Dir = struct {...@@ -1135,15 +1162,26 @@ pub const Dir = struct {
1135 SymLink,1162 SymLink,
1136 File,1163 File,
1137 UnixDomainSocket,1164 UnixDomainSocket,
1165 Whiteout,
1138 Unknown,1166 Unknown,
1139 };1167 };
1140 };1168 };
11411169
1142 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {1170 pub fn open(allocator: &Allocator, dir_path: []const u8) !Dir {
1143 const fd = try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0);1171 const fd = switch (builtin.os) {
1172 Os.windows => @compileError("TODO support Dir.open for windows"),
1173 Os.linux => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
1174 Os.macosx, Os.ios => try posixOpen(allocator, dir_path, posix.O_RDONLY|posix.O_NONBLOCK|posix.O_DIRECTORY|posix.O_CLOEXEC, 0),
1175 else => @compileError("Dir.open is not supported for this platform"),
1176 };
1177 const darwin_seek_init = switch (builtin.os) {
1178 Os.macosx, Os.ios => 0,
1179 else => {},
1180 };
1144 return Dir {1181 return Dir {
1145 .allocator = allocator,1182 .allocator = allocator,
1146 .fd = fd,1183 .fd = fd,
1184 .darwin_seek = darwin_seek_init,
1147 .index = 0,1185 .index = 0,
1148 .end_index = 0,1186 .end_index = 0,
1149 .buf = []u8{},1187 .buf = []u8{},
...@@ -1158,6 +1196,76 @@ pub const Dir = struct {...@@ -1158,6 +1196,76 @@ pub const Dir = struct {
1158 /// Memory such as file names referenced in this returned entry becomes invalid1196 /// Memory such as file names referenced in this returned entry becomes invalid
1159 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.1197 /// with subsequent calls to next, as well as when this ::Dir is deinitialized.
1160 pub fn next(self: &Dir) !?Entry {1198 pub fn next(self: &Dir) !?Entry {
1199 switch (builtin.os) {
1200 Os.linux => return self.nextLinux(),
1201 Os.macosx, Os.ios => return self.nextDarwin(),
1202 Os.windows => return self.nextWindows(),
1203 else => @compileError("Dir.next not supported on " ++ @tagName(builtin.os)),
1204 }
1205 }
1206
1207 fn nextDarwin(self: &Dir) !?Entry {
1208 start_over: while (true) {
1209 if (self.index >= self.end_index) {
1210 if (self.buf.len == 0) {
1211 self.buf = try self.allocator.alloc(u8, page_size);
1212 }
1213
1214 while (true) {
1215 const result = posix.getdirentries64(self.fd, self.buf.ptr, self.buf.len,
1216 &self.darwin_seek);
1217 const err = posix.getErrno(result);
1218 if (err > 0) {
1219 switch (err) {
1220 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
1221 posix.EINVAL => {
1222 self.buf = try self.allocator.realloc(u8, self.buf, self.buf.len * 2);
1223 continue;
1224 },
1225 else => return unexpectedErrorPosix(err),
1226 }
1227 }
1228 if (result == 0)
1229 return null;
1230 self.index = 0;
1231 self.end_index = result;
1232 break;
1233 }
1234 }
1235 const darwin_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1236 const next_index = self.index + darwin_entry.d_reclen;
1237 self.index = next_index;
1238
1239 const name = (&darwin_entry.d_name)[0..darwin_entry.d_namlen];
1240
1241 // skip . and .. entries
1242 if (mem.eql(u8, name, ".") or mem.eql(u8, name, "..")) {
1243 continue :start_over;
1244 }
1245
1246 const entry_kind = switch (darwin_entry.d_type) {
1247 posix.DT_BLK => Entry.Kind.BlockDevice,
1248 posix.DT_CHR => Entry.Kind.CharacterDevice,
1249 posix.DT_DIR => Entry.Kind.Directory,
1250 posix.DT_FIFO => Entry.Kind.NamedPipe,
1251 posix.DT_LNK => Entry.Kind.SymLink,
1252 posix.DT_REG => Entry.Kind.File,
1253 posix.DT_SOCK => Entry.Kind.UnixDomainSocket,
1254 posix.DT_WHT => Entry.Kind.Whiteout,
1255 else => Entry.Kind.Unknown,
1256 };
1257 return Entry {
1258 .name = name,
1259 .kind = entry_kind,
1260 };
1261 }
1262 }
1263
1264 fn nextWindows(self: &Dir) !?Entry {
1265 @compileError("TODO support Dir.next for windows");
1266 }
1267
1268 fn nextLinux(self: &Dir) !?Entry {
1161 start_over: while (true) {1269 start_over: while (true) {
1162 if (self.index >= self.end_index) {1270 if (self.index >= self.end_index) {
1163 if (self.buf.len == 0) {1271 if (self.buf.len == 0) {
...@@ -1166,7 +1274,7 @@ pub const Dir = struct {...@@ -1166,7 +1274,7 @@ pub const Dir = struct {
11661274
1167 while (true) {1275 while (true) {
1168 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);1276 const result = posix.getdents(self.fd, self.buf.ptr, self.buf.len);
1169 const err = linux.getErrno(result);1277 const err = posix.getErrno(result);
1170 if (err > 0) {1278 if (err > 0) {
1171 switch (err) {1279 switch (err) {
1172 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,1280 posix.EBADF, posix.EFAULT, posix.ENOTDIR => unreachable,
...@@ -1184,7 +1292,7 @@ pub const Dir = struct {...@@ -1184,7 +1292,7 @@ pub const Dir = struct {
1184 break;1292 break;
1185 }1293 }
1186 }1294 }
1187 const linux_entry = @ptrCast(& align(1) LinuxEntry, &self.buf[self.index]);1295 const linux_entry = @ptrCast(& align(1) posix.dirent, &self.buf[self.index]);
1188 const next_index = self.index + linux_entry.d_reclen;1296 const next_index = self.index + linux_entry.d_reclen;
1189 self.index = next_index;1297 self.index = next_index;
11901298
...@@ -1668,26 +1776,16 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const...@@ -1668,26 +1776,16 @@ fn testWindowsCmdLine(input_cmd_line: &const u8, expected_args: []const []const
1668 assert(it.next(debug.global_allocator) == null);1776 assert(it.next(debug.global_allocator) == null);
1669}1777}
16701778
1671test "std.os" {
1672 _ = @import("child_process.zig");
1673 _ = @import("darwin_errno.zig");
1674 _ = @import("darwin.zig");
1675 _ = @import("get_user_id.zig");
1676 _ = @import("linux/errno.zig");
1677 //_ = @import("linux_i386.zig");
1678 _ = @import("linux/x86_64.zig");
1679 _ = @import("linux/index.zig");
1680 _ = @import("path.zig");
1681 _ = @import("windows/index.zig");
1682}
1683
1684
1685// TODO make this a build variable that you can set1779// TODO make this a build variable that you can set
1686const unexpected_error_tracing = false;1780const unexpected_error_tracing = false;
1781const UnexpectedError = error {
1782 /// The Operating System returned an undocumented error code.
1783 Unexpected,
1784};
16871785
1688/// Call this when you made a syscall or something that sets errno1786/// Call this when you made a syscall or something that sets errno
1689/// and you get an unexpected error.1787/// and you get an unexpected error.
1690pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {1788pub fn unexpectedErrorPosix(errno: usize) UnexpectedError {
1691 if (unexpected_error_tracing) {1789 if (unexpected_error_tracing) {
1692 debug.warn("unexpected errno: {}\n", errno);1790 debug.warn("unexpected errno: {}\n", errno);
1693 debug.dumpCurrentStackTrace(null);1791 debug.dumpCurrentStackTrace(null);
...@@ -1697,7 +1795,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {...@@ -1697,7 +1795,7 @@ pub fn unexpectedErrorPosix(errno: usize) (error{Unexpected}) {
16971795
1698/// Call this when you made a windows DLL call or something that does SetLastError1796/// Call this when you made a windows DLL call or something that does SetLastError
1699/// and you get an unexpected error.1797/// and you get an unexpected error.
1700pub fn unexpectedErrorWindows(err: windows.DWORD) (error{Unexpected}) {1798pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
1701 if (unexpected_error_tracing) {1799 if (unexpected_error_tracing) {
1702 debug.warn("unexpected GetLastError(): {}\n", err);1800 debug.warn("unexpected GetLastError(): {}\n", err);
1703 debug.dumpCurrentStackTrace(null);1801 debug.dumpCurrentStackTrace(null);
...@@ -1812,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool {...@@ -1812,3 +1910,477 @@ pub fn isTty(handle: FileHandle) bool {
1812 }1910 }
1813 }1911 }
1814}1912}
1913
1914pub const PosixSocketError = error {
1915 /// Permission to create a socket of the specified type and/or
1916 /// pro‐tocol is denied.
1917 PermissionDenied,
1918
1919 /// The implementation does not support the specified address family.
1920 AddressFamilyNotSupported,
1921
1922 /// Unknown protocol, or protocol family not available.
1923 ProtocolFamilyNotAvailable,
1924
1925 /// The per-process limit on the number of open file descriptors has been reached.
1926 ProcessFdQuotaExceeded,
1927
1928 /// The system-wide limit on the total number of open files has been reached.
1929 SystemFdQuotaExceeded,
1930
1931 /// Insufficient memory is available. The socket cannot be created until sufficient
1932 /// resources are freed.
1933 SystemResources,
1934
1935 /// The protocol type or the specified protocol is not supported within this domain.
1936 ProtocolNotSupported,
1937};
1938
1939pub fn posixSocket(domain: u32, socket_type: u32, protocol: u32) !i32 {
1940 const rc = posix.socket(domain, socket_type, protocol);
1941 const err = posix.getErrno(rc);
1942 switch (err) {
1943 0 => return i32(rc),
1944 posix.EACCES => return PosixSocketError.PermissionDenied,
1945 posix.EAFNOSUPPORT => return PosixSocketError.AddressFamilyNotSupported,
1946 posix.EINVAL => return PosixSocketError.ProtocolFamilyNotAvailable,
1947 posix.EMFILE => return PosixSocketError.ProcessFdQuotaExceeded,
1948 posix.ENFILE => return PosixSocketError.SystemFdQuotaExceeded,
1949 posix.ENOBUFS, posix.ENOMEM => return PosixSocketError.SystemResources,
1950 posix.EPROTONOSUPPORT => return PosixSocketError.ProtocolNotSupported,
1951 else => return unexpectedErrorPosix(err),
1952 }
1953}
1954
1955pub const PosixBindError = error {
1956 /// The address is protected, and the user is not the superuser.
1957 /// For UNIX domain sockets: Search permission is denied on a component
1958 /// of the path prefix.
1959 AccessDenied,
1960
1961 /// The given address is already in use, or in the case of Internet domain sockets,
1962 /// The port number was specified as zero in the socket
1963 /// address structure, but, upon attempting to bind to an ephemeral port, it was
1964 /// determined that all port numbers in the ephemeral port range are currently in
1965 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range ip(7).
1966 AddressInUse,
1967
1968 /// sockfd is not a valid file descriptor.
1969 InvalidFileDescriptor,
1970
1971 /// The socket is already bound to an address, or addrlen is wrong, or addr is not
1972 /// a valid address for this socket's domain.
1973 InvalidSocketOrAddress,
1974
1975 /// The file descriptor sockfd does not refer to a socket.
1976 FileDescriptorNotASocket,
1977
1978 /// A nonexistent interface was requested or the requested address was not local.
1979 AddressNotAvailable,
1980
1981 /// addr points outside the user's accessible address space.
1982 PageFault,
1983
1984 /// Too many symbolic links were encountered in resolving addr.
1985 SymLinkLoop,
1986
1987 /// addr is too long.
1988 NameTooLong,
1989
1990 /// A component in the directory prefix of the socket pathname does not exist.
1991 FileNotFound,
1992
1993 /// Insufficient kernel memory was available.
1994 SystemResources,
1995
1996 /// A component of the path prefix is not a directory.
1997 NotDir,
1998
1999 /// The socket inode would reside on a read-only filesystem.
2000 ReadOnlyFileSystem,
2001
2002 Unexpected,
2003};
2004
2005/// addr is `&const T` where T is one of the sockaddr
2006pub fn posixBind(fd: i32, addr: &const posix.sockaddr) PosixBindError!void {
2007 const rc = posix.bind(fd, addr, @sizeOf(posix.sockaddr));
2008 const err = posix.getErrno(rc);
2009 switch (err) {
2010 0 => return,
2011 posix.EACCES => return PosixBindError.AccessDenied,
2012 posix.EADDRINUSE => return PosixBindError.AddressInUse,
2013 posix.EBADF => return PosixBindError.InvalidFileDescriptor,
2014 posix.EINVAL => return PosixBindError.InvalidSocketOrAddress,
2015 posix.ENOTSOCK => return PosixBindError.FileDescriptorNotASocket,
2016 posix.EADDRNOTAVAIL => return PosixBindError.AddressNotAvailable,
2017 posix.EFAULT => return PosixBindError.PageFault,
2018 posix.ELOOP => return PosixBindError.SymLinkLoop,
2019 posix.ENAMETOOLONG => return PosixBindError.NameTooLong,
2020 posix.ENOENT => return PosixBindError.FileNotFound,
2021 posix.ENOMEM => return PosixBindError.SystemResources,
2022 posix.ENOTDIR => return PosixBindError.NotDir,
2023 posix.EROFS => return PosixBindError.ReadOnlyFileSystem,
2024 else => return unexpectedErrorPosix(err),
2025 }
2026}
2027
2028const PosixListenError = error {
2029 /// Another socket is already listening on the same port.
2030 /// For Internet domain sockets, the socket referred to by sockfd had not previously
2031 /// been bound to an address and, upon attempting to bind it to an ephemeral port, it
2032 /// was determined that all port numbers in the ephemeral port range are currently in
2033 /// use. See the discussion of /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2034 AddressInUse,
2035
2036 /// The argument sockfd is not a valid file descriptor.
2037 InvalidFileDescriptor,
2038
2039 /// The file descriptor sockfd does not refer to a socket.
2040 FileDescriptorNotASocket,
2041
2042 /// The socket is not of a type that supports the listen() operation.
2043 OperationNotSupported,
2044
2045 Unexpected,
2046};
2047
2048pub fn posixListen(sockfd: i32, backlog: u32) PosixListenError!void {
2049 const rc = posix.listen(sockfd, backlog);
2050 const err = posix.getErrno(rc);
2051 switch (err) {
2052 0 => return,
2053 posix.EADDRINUSE => return PosixListenError.AddressInUse,
2054 posix.EBADF => return PosixListenError.InvalidFileDescriptor,
2055 posix.ENOTSOCK => return PosixListenError.FileDescriptorNotASocket,
2056 posix.EOPNOTSUPP => return PosixListenError.OperationNotSupported,
2057 else => return unexpectedErrorPosix(err),
2058 }
2059}
2060
2061pub const PosixAcceptError = error {
2062 /// The socket is marked nonblocking and no connections are present to be accepted.
2063 WouldBlock,
2064
2065 /// sockfd is not an open file descriptor.
2066 FileDescriptorClosed,
2067
2068 ConnectionAborted,
2069
2070 /// The addr argument is not in a writable part of the user address space.
2071 PageFault,
2072
2073 /// Socket is not listening for connections, or addrlen is invalid (e.g., is negative),
2074 /// or invalid value in flags.
2075 InvalidSyscall,
2076
2077 /// The per-process limit on the number of open file descriptors has been reached.
2078 ProcessFdQuotaExceeded,
2079
2080 /// The system-wide limit on the total number of open files has been reached.
2081 SystemFdQuotaExceeded,
2082
2083 /// Not enough free memory. This often means that the memory allocation is limited
2084 /// by the socket buffer limits, not by the system memory.
2085 SystemResources,
2086
2087 /// The file descriptor sockfd does not refer to a socket.
2088 FileDescriptorNotASocket,
2089
2090 /// The referenced socket is not of type SOCK_STREAM.
2091 OperationNotSupported,
2092
2093 ProtocolFailure,
2094
2095 /// Firewall rules forbid connection.
2096 BlockedByFirewall,
2097
2098 Unexpected,
2099};
2100
2101pub fn posixAccept(fd: i32, addr: &posix.sockaddr, flags: u32) PosixAcceptError!i32 {
2102 while (true) {
2103 var sockaddr_size = u32(@sizeOf(posix.sockaddr));
2104 const rc = posix.accept4(fd, addr, &sockaddr_size, flags);
2105 const err = posix.getErrno(rc);
2106 switch (err) {
2107 0 => return i32(rc),
2108 posix.EINTR => continue,
2109 else => return unexpectedErrorPosix(err),
2110
2111 posix.EAGAIN => return PosixAcceptError.WouldBlock,
2112 posix.EBADF => return PosixAcceptError.FileDescriptorClosed,
2113 posix.ECONNABORTED => return PosixAcceptError.ConnectionAborted,
2114 posix.EFAULT => return PosixAcceptError.PageFault,
2115 posix.EINVAL => return PosixAcceptError.InvalidSyscall,
2116 posix.EMFILE => return PosixAcceptError.ProcessFdQuotaExceeded,
2117 posix.ENFILE => return PosixAcceptError.SystemFdQuotaExceeded,
2118 posix.ENOBUFS, posix.ENOMEM => return PosixAcceptError.SystemResources,
2119 posix.ENOTSOCK => return PosixAcceptError.FileDescriptorNotASocket,
2120 posix.EOPNOTSUPP => return PosixAcceptError.OperationNotSupported,
2121 posix.EPROTO => return PosixAcceptError.ProtocolFailure,
2122 posix.EPERM => return PosixAcceptError.BlockedByFirewall,
2123 }
2124 }
2125}
2126
2127pub const LinuxEpollCreateError = error {
2128 /// Invalid value specified in flags.
2129 InvalidSyscall,
2130
2131 /// The per-user limit on the number of epoll instances imposed by
2132 /// /proc/sys/fs/epoll/max_user_instances was encountered. See epoll(7) for further
2133 /// details.
2134 /// Or, The per-process limit on the number of open file descriptors has been reached.
2135 ProcessFdQuotaExceeded,
2136
2137 /// The system-wide limit on the total number of open files has been reached.
2138 SystemFdQuotaExceeded,
2139
2140 /// There was insufficient memory to create the kernel object.
2141 SystemResources,
2142
2143 Unexpected,
2144};
2145
2146pub fn linuxEpollCreate(flags: u32) LinuxEpollCreateError!i32 {
2147 const rc = posix.epoll_create1(flags);
2148 const err = posix.getErrno(rc);
2149 switch (err) {
2150 0 => return i32(rc),
2151 else => return unexpectedErrorPosix(err),
2152
2153 posix.EINVAL => return LinuxEpollCreateError.InvalidSyscall,
2154 posix.EMFILE => return LinuxEpollCreateError.ProcessFdQuotaExceeded,
2155 posix.ENFILE => return LinuxEpollCreateError.SystemFdQuotaExceeded,
2156 posix.ENOMEM => return LinuxEpollCreateError.SystemResources,
2157 }
2158}
2159
2160pub const LinuxEpollCtlError = error {
2161 /// epfd or fd is not a valid file descriptor.
2162 InvalidFileDescriptor,
2163
2164 /// op was EPOLL_CTL_ADD, and the supplied file descriptor fd is already registered
2165 /// with this epoll instance.
2166 FileDescriptorAlreadyPresentInSet,
2167
2168 /// epfd is not an epoll file descriptor, or fd is the same as epfd, or the requested
2169 /// operation op is not supported by this interface, or
2170 /// An invalid event type was specified along with EPOLLEXCLUSIVE in events, or
2171 /// op was EPOLL_CTL_MOD and events included EPOLLEXCLUSIVE, or
2172 /// op was EPOLL_CTL_MOD and the EPOLLEXCLUSIVE flag has previously been applied to
2173 /// this epfd, fd pair, or
2174 /// EPOLLEXCLUSIVE was specified in event and fd refers to an epoll instance.
2175 InvalidSyscall,
2176
2177 /// fd refers to an epoll instance and this EPOLL_CTL_ADD operation would result in a
2178 /// circular loop of epoll instances monitoring one another.
2179 OperationCausesCircularLoop,
2180
2181 /// op was EPOLL_CTL_MOD or EPOLL_CTL_DEL, and fd is not registered with this epoll
2182 /// instance.
2183 FileDescriptorNotRegistered,
2184
2185 /// There was insufficient memory to handle the requested op control operation.
2186 SystemResources,
2187
2188 /// The limit imposed by /proc/sys/fs/epoll/max_user_watches was encountered while
2189 /// trying to register (EPOLL_CTL_ADD) a new file descriptor on an epoll instance.
2190 /// See epoll(7) for further details.
2191 UserResourceLimitReached,
2192
2193 /// The target file fd does not support epoll. This error can occur if fd refers to,
2194 /// for example, a regular file or a directory.
2195 FileDescriptorIncompatibleWithEpoll,
2196
2197 Unexpected,
2198};
2199
2200pub fn linuxEpollCtl(epfd: i32, op: u32, fd: i32, event: &linux.epoll_event) LinuxEpollCtlError!void {
2201 const rc = posix.epoll_ctl(epfd, op, fd, event);
2202 const err = posix.getErrno(rc);
2203 switch (err) {
2204 0 => return,
2205 else => return unexpectedErrorPosix(err),
2206
2207 posix.EBADF => return LinuxEpollCtlError.InvalidFileDescriptor,
2208 posix.EEXIST => return LinuxEpollCtlError.FileDescriptorAlreadyPresentInSet,
2209 posix.EINVAL => return LinuxEpollCtlError.InvalidSyscall,
2210 posix.ELOOP => return LinuxEpollCtlError.OperationCausesCircularLoop,
2211 posix.ENOENT => return LinuxEpollCtlError.FileDescriptorNotRegistered,
2212 posix.ENOMEM => return LinuxEpollCtlError.SystemResources,
2213 posix.ENOSPC => return LinuxEpollCtlError.UserResourceLimitReached,
2214 posix.EPERM => return LinuxEpollCtlError.FileDescriptorIncompatibleWithEpoll,
2215 }
2216}
2217
2218pub fn linuxEpollWait(epfd: i32, events: []linux.epoll_event, timeout: i32) usize {
2219 while (true) {
2220 const rc = posix.epoll_wait(epfd, events.ptr, u32(events.len), timeout);
2221 const err = posix.getErrno(rc);
2222 switch (err) {
2223 0 => return rc,
2224 posix.EINTR => continue,
2225 posix.EBADF => unreachable,
2226 posix.EFAULT => unreachable,
2227 posix.EINVAL => unreachable,
2228 else => unreachable,
2229 }
2230 }
2231}
2232
2233pub const PosixGetSockNameError = error {
2234 /// Insufficient resources were available in the system to perform the operation.
2235 SystemResources,
2236
2237 Unexpected,
2238};
2239
2240pub fn posixGetSockName(sockfd: i32) PosixGetSockNameError!posix.sockaddr {
2241 var addr: posix.sockaddr = undefined;
2242 var addrlen: posix.socklen_t = @sizeOf(posix.sockaddr);
2243 const rc = posix.getsockname(sockfd, &addr, &addrlen);
2244 const err = posix.getErrno(rc);
2245 switch (err) {
2246 0 => return addr,
2247 else => return unexpectedErrorPosix(err),
2248
2249 posix.EBADF => unreachable,
2250 posix.EFAULT => unreachable,
2251 posix.EINVAL => unreachable,
2252 posix.ENOTSOCK => unreachable,
2253 posix.ENOBUFS => return PosixGetSockNameError.SystemResources,
2254 }
2255}
2256
2257pub const PosixConnectError = error {
2258 /// For UNIX domain sockets, which are identified by pathname: Write permission is denied on the socket
2259 /// file, or search permission is denied for one of the directories in the path prefix.
2260 /// or
2261 /// The user tried to connect to a broadcast address without having the socket broadcast flag enabled or
2262 /// the connection request failed because of a local firewall rule.
2263 PermissionDenied,
2264
2265 /// Local address is already in use.
2266 AddressInUse,
2267
2268 /// (Internet domain sockets) The socket referred to by sockfd had not previously been bound to an
2269 /// address and, upon attempting to bind it to an ephemeral port, it was determined that all port numbers
2270 /// in the ephemeral port range are currently in use. See the discussion of
2271 /// /proc/sys/net/ipv4/ip_local_port_range in ip(7).
2272 AddressNotAvailable,
2273
2274 /// The passed address didn't have the correct address family in its sa_family field.
2275 AddressFamilyNotSupported,
2276
2277 /// Insufficient entries in the routing cache.
2278 SystemResources,
2279
2280 /// A connect() on a stream socket found no one listening on the remote address.
2281 ConnectionRefused,
2282
2283 /// Network is unreachable.
2284 NetworkUnreachable,
2285
2286 /// Timeout while attempting connection. The server may be too busy to accept new connections. Note
2287 /// that for IP sockets the timeout may be very long when syncookies are enabled on the server.
2288 ConnectionTimedOut,
2289
2290 Unexpected,
2291};
2292
2293pub fn posixConnect(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2294 while (true) {
2295 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2296 const err = posix.getErrno(rc);
2297 switch (err) {
2298 0 => return,
2299 else => return unexpectedErrorPosix(err),
2300
2301 posix.EACCES => return PosixConnectError.PermissionDenied,
2302 posix.EPERM => return PosixConnectError.PermissionDenied,
2303 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2304 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2305 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2306 posix.EAGAIN => return PosixConnectError.SystemResources,
2307 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2308 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2309 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2310 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2311 posix.EINPROGRESS => unreachable, // The socket is nonblocking and the connection cannot be completed immediately.
2312 posix.EINTR => continue,
2313 posix.EISCONN => unreachable, // The socket is already connected.
2314 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2315 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2316 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2317 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2318 }
2319 }
2320}
2321
2322/// Same as posixConnect except it is for blocking socket file descriptors.
2323/// It expects to receive EINPROGRESS.
2324pub fn posixConnectAsync(sockfd: i32, sockaddr: &const posix.sockaddr) PosixConnectError!void {
2325 while (true) {
2326 const rc = posix.connect(sockfd, sockaddr, @sizeOf(posix.sockaddr));
2327 const err = posix.getErrno(rc);
2328 switch (err) {
2329 0, posix.EINPROGRESS => return,
2330 else => return unexpectedErrorPosix(err),
2331
2332 posix.EACCES => return PosixConnectError.PermissionDenied,
2333 posix.EPERM => return PosixConnectError.PermissionDenied,
2334 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2335 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2336 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2337 posix.EAGAIN => return PosixConnectError.SystemResources,
2338 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2339 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2340 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2341 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2342 posix.EINTR => continue,
2343 posix.EISCONN => unreachable, // The socket is already connected.
2344 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2345 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2346 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2347 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2348 }
2349 }
2350}
2351
2352pub fn posixGetSockOptConnectError(sockfd: i32) PosixConnectError!void {
2353 var err_code: i32 = undefined;
2354 var size: u32 = @sizeOf(i32);
2355 const rc = posix.getsockopt(sockfd, posix.SOL_SOCKET, posix.SO_ERROR, @ptrCast(&u8, &err_code), &size);
2356 assert(size == 4);
2357 const err = posix.getErrno(rc);
2358 switch (err) {
2359 0 => switch (err_code) {
2360 0 => return,
2361 else => return unexpectedErrorPosix(err),
2362
2363 posix.EACCES => return PosixConnectError.PermissionDenied,
2364 posix.EPERM => return PosixConnectError.PermissionDenied,
2365 posix.EADDRINUSE => return PosixConnectError.AddressInUse,
2366 posix.EADDRNOTAVAIL => return PosixConnectError.AddressNotAvailable,
2367 posix.EAFNOSUPPORT => return PosixConnectError.AddressFamilyNotSupported,
2368 posix.EAGAIN => return PosixConnectError.SystemResources,
2369 posix.EALREADY => unreachable, // The socket is nonblocking and a previous connection attempt has not yet been completed.
2370 posix.EBADF => unreachable, // sockfd is not a valid open file descriptor.
2371 posix.ECONNREFUSED => return PosixConnectError.ConnectionRefused,
2372 posix.EFAULT => unreachable, // The socket structure address is outside the user's address space.
2373 posix.EISCONN => unreachable, // The socket is already connected.
2374 posix.ENETUNREACH => return PosixConnectError.NetworkUnreachable,
2375 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2376 posix.EPROTOTYPE => unreachable, // The socket type does not support the requested communications protocol.
2377 posix.ETIMEDOUT => return PosixConnectError.ConnectionTimedOut,
2378 },
2379 else => return unexpectedErrorPosix(err),
2380 posix.EBADF => unreachable, // The argument sockfd is not a valid file descriptor.
2381 posix.EFAULT => unreachable, // The address pointed to by optval or optlen is not in a valid part of the process address space.
2382 posix.EINVAL => unreachable,
2383 posix.ENOPROTOOPT => unreachable, // The option is unknown at the level indicated.
2384 posix.ENOTSOCK => unreachable, // The file descriptor sockfd does not refer to a socket.
2385 }
2386}
std/os/linux/i386.zig deleted-505
...@@ -1,505 +0,0 @@
1const std = @import("../../index.zig");
2const linux = std.os.linux;
3const socklen_t = linux.socklen_t;
4const iovec = linux.iovec;
5
6pub const SYS_restart_syscall = 0;
7pub const SYS_exit = 1;
8pub const SYS_fork = 2;
9pub const SYS_read = 3;
10pub const SYS_write = 4;
11pub const SYS_open = 5;
12pub const SYS_close = 6;
13pub const SYS_waitpid = 7;
14pub const SYS_creat = 8;
15pub const SYS_link = 9;
16pub const SYS_unlink = 10;
17pub const SYS_execve = 11;
18pub const SYS_chdir = 12;
19pub const SYS_time = 13;
20pub const SYS_mknod = 14;
21pub const SYS_chmod = 15;
22pub const SYS_lchown = 16;
23pub const SYS_break = 17;
24pub const SYS_oldstat = 18;
25pub const SYS_lseek = 19;
26pub const SYS_getpid = 20;
27pub const SYS_mount = 21;
28pub const SYS_umount = 22;
29pub const SYS_setuid = 23;
30pub const SYS_getuid = 24;
31pub const SYS_stime = 25;
32pub const SYS_ptrace = 26;
33pub const SYS_alarm = 27;
34pub const SYS_oldfstat = 28;
35pub const SYS_pause = 29;
36pub const SYS_utime = 30;
37pub const SYS_stty = 31;
38pub const SYS_gtty = 32;
39pub const SYS_access = 33;
40pub const SYS_nice = 34;
41pub const SYS_ftime = 35;
42pub const SYS_sync = 36;
43pub const SYS_kill = 37;
44pub const SYS_rename = 38;
45pub const SYS_mkdir = 39;
46pub const SYS_rmdir = 40;
47pub const SYS_dup = 41;
48pub const SYS_pipe = 42;
49pub const SYS_times = 43;
50pub const SYS_prof = 44;
51pub const SYS_brk = 45;
52pub const SYS_setgid = 46;
53pub const SYS_getgid = 47;
54pub const SYS_signal = 48;
55pub const SYS_geteuid = 49;
56pub const SYS_getegid = 50;
57pub const SYS_acct = 51;
58pub const SYS_umount2 = 52;
59pub const SYS_lock = 53;
60pub const SYS_ioctl = 54;
61pub const SYS_fcntl = 55;
62pub const SYS_mpx = 56;
63pub const SYS_setpgid = 57;
64pub const SYS_ulimit = 58;
65pub const SYS_oldolduname = 59;
66pub const SYS_umask = 60;
67pub const SYS_chroot = 61;
68pub const SYS_ustat = 62;
69pub const SYS_dup2 = 63;
70pub const SYS_getppid = 64;
71pub const SYS_getpgrp = 65;
72pub const SYS_setsid = 66;
73pub const SYS_sigaction = 67;
74pub const SYS_sgetmask = 68;
75pub const SYS_ssetmask = 69;
76pub const SYS_setreuid = 70;
77pub const SYS_setregid = 71;
78pub const SYS_sigsuspend = 72;
79pub const SYS_sigpending = 73;
80pub const SYS_sethostname = 74;
81pub const SYS_setrlimit = 75;
82pub const SYS_getrlimit = 76;
83pub const SYS_getrusage = 77;
84pub const SYS_gettimeofday = 78;
85pub const SYS_settimeofday = 79;
86pub const SYS_getgroups = 80;
87pub const SYS_setgroups = 81;
88pub const SYS_select = 82;
89pub const SYS_symlink = 83;
90pub const SYS_oldlstat = 84;
91pub const SYS_readlink = 85;
92pub const SYS_uselib = 86;
93pub const SYS_swapon = 87;
94pub const SYS_reboot = 88;
95pub const SYS_readdir = 89;
96pub const SYS_mmap = 90;
97pub const SYS_munmap = 91;
98pub const SYS_truncate = 92;
99pub const SYS_ftruncate = 93;
100pub const SYS_fchmod = 94;
101pub const SYS_fchown = 95;
102pub const SYS_getpriority = 96;
103pub const SYS_setpriority = 97;
104pub const SYS_profil = 98;
105pub const SYS_statfs = 99;
106pub const SYS_fstatfs = 100;
107pub const SYS_ioperm = 101;
108pub const SYS_socketcall = 102;
109pub const SYS_syslog = 103;
110pub const SYS_setitimer = 104;
111pub const SYS_getitimer = 105;
112pub const SYS_stat = 106;
113pub const SYS_lstat = 107;
114pub const SYS_fstat = 108;
115pub const SYS_olduname = 109;
116pub const SYS_iopl = 110;
117pub const SYS_vhangup = 111;
118pub const SYS_idle = 112;
119pub const SYS_vm86old = 113;
120pub const SYS_wait4 = 114;
121pub const SYS_swapoff = 115;
122pub const SYS_sysinfo = 116;
123pub const SYS_ipc = 117;
124pub const SYS_fsync = 118;
125pub const SYS_sigreturn = 119;
126pub const SYS_clone = 120;
127pub const SYS_setdomainname = 121;
128pub const SYS_uname = 122;
129pub const SYS_modify_ldt = 123;
130pub const SYS_adjtimex = 124;
131pub const SYS_mprotect = 125;
132pub const SYS_sigprocmask = 126;
133pub const SYS_create_module = 127;
134pub const SYS_init_module = 128;
135pub const SYS_delete_module = 129;
136pub const SYS_get_kernel_syms = 130;
137pub const SYS_quotactl = 131;
138pub const SYS_getpgid = 132;
139pub const SYS_fchdir = 133;
140pub const SYS_bdflush = 134;
141pub const SYS_sysfs = 135;
142pub const SYS_personality = 136;
143pub const SYS_afs_syscall = 137;
144pub const SYS_setfsuid = 138;
145pub const SYS_setfsgid = 139;
146pub const SYS__llseek = 140;
147pub const SYS_getdents = 141;
148pub const SYS__newselect = 142;
149pub const SYS_flock = 143;
150pub const SYS_msync = 144;
151pub const SYS_readv = 145;
152pub const SYS_writev = 146;
153pub const SYS_getsid = 147;
154pub const SYS_fdatasync = 148;
155pub const SYS__sysctl = 149;
156pub const SYS_mlock = 150;
157pub const SYS_munlock = 151;
158pub const SYS_mlockall = 152;
159pub const SYS_munlockall = 153;
160pub const SYS_sched_setparam = 154;
161pub const SYS_sched_getparam = 155;
162pub const SYS_sched_setscheduler = 156;
163pub const SYS_sched_getscheduler = 157;
164pub const SYS_sched_yield = 158;
165pub const SYS_sched_get_priority_max = 159;
166pub const SYS_sched_get_priority_min = 160;
167pub const SYS_sched_rr_get_interval = 161;
168pub const SYS_nanosleep = 162;
169pub const SYS_mremap = 163;
170pub const SYS_setresuid = 164;
171pub const SYS_getresuid = 165;
172pub const SYS_vm86 = 166;
173pub const SYS_query_module = 167;
174pub const SYS_poll = 168;
175pub const SYS_nfsservctl = 169;
176pub const SYS_setresgid = 170;
177pub const SYS_getresgid = 171;
178pub const SYS_prctl = 172;
179pub const SYS_rt_sigreturn = 173;
180pub const SYS_rt_sigaction = 174;
181pub const SYS_rt_sigprocmask = 175;
182pub const SYS_rt_sigpending = 176;
183pub const SYS_rt_sigtimedwait = 177;
184pub const SYS_rt_sigqueueinfo = 178;
185pub const SYS_rt_sigsuspend = 179;
186pub const SYS_pread64 = 180;
187pub const SYS_pwrite64 = 181;
188pub const SYS_chown = 182;
189pub const SYS_getcwd = 183;
190pub const SYS_capget = 184;
191pub const SYS_capset = 185;
192pub const SYS_sigaltstack = 186;
193pub const SYS_sendfile = 187;
194pub const SYS_getpmsg = 188;
195pub const SYS_putpmsg = 189;
196pub const SYS_vfork = 190;
197pub const SYS_ugetrlimit = 191;
198pub const SYS_mmap2 = 192;
199pub const SYS_truncate64 = 193;
200pub const SYS_ftruncate64 = 194;
201pub const SYS_stat64 = 195;
202pub const SYS_lstat64 = 196;
203pub const SYS_fstat64 = 197;
204pub const SYS_lchown32 = 198;
205pub const SYS_getuid32 = 199;
206pub const SYS_getgid32 = 200;
207pub const SYS_geteuid32 = 201;
208pub const SYS_getegid32 = 202;
209pub const SYS_setreuid32 = 203;
210pub const SYS_setregid32 = 204;
211pub const SYS_getgroups32 = 205;
212pub const SYS_setgroups32 = 206;
213pub const SYS_fchown32 = 207;
214pub const SYS_setresuid32 = 208;
215pub const SYS_getresuid32 = 209;
216pub const SYS_setresgid32 = 210;
217pub const SYS_getresgid32 = 211;
218pub const SYS_chown32 = 212;
219pub const SYS_setuid32 = 213;
220pub const SYS_setgid32 = 214;
221pub const SYS_setfsuid32 = 215;
222pub const SYS_setfsgid32 = 216;
223pub const SYS_pivot_root = 217;
224pub const SYS_mincore = 218;
225pub const SYS_madvise = 219;
226pub const SYS_madvise1 = 219;
227pub const SYS_getdents64 = 220;
228pub const SYS_fcntl64 = 221;
229pub const SYS_gettid = 224;
230pub const SYS_readahead = 225;
231pub const SYS_setxattr = 226;
232pub const SYS_lsetxattr = 227;
233pub const SYS_fsetxattr = 228;
234pub const SYS_getxattr = 229;
235pub const SYS_lgetxattr = 230;
236pub const SYS_fgetxattr = 231;
237pub const SYS_listxattr = 232;
238pub const SYS_llistxattr = 233;
239pub const SYS_flistxattr = 234;
240pub const SYS_removexattr = 235;
241pub const SYS_lremovexattr = 236;
242pub const SYS_fremovexattr = 237;
243pub const SYS_tkill = 238;
244pub const SYS_sendfile64 = 239;
245pub const SYS_futex = 240;
246pub const SYS_sched_setaffinity = 241;
247pub const SYS_sched_getaffinity = 242;
248pub const SYS_set_thread_area = 243;
249pub const SYS_get_thread_area = 244;
250pub const SYS_io_setup = 245;
251pub const SYS_io_destroy = 246;
252pub const SYS_io_getevents = 247;
253pub const SYS_io_submit = 248;
254pub const SYS_io_cancel = 249;
255pub const SYS_fadvise64 = 250;
256pub const SYS_exit_group = 252;
257pub const SYS_lookup_dcookie = 253;
258pub const SYS_epoll_create = 254;
259pub const SYS_epoll_ctl = 255;
260pub const SYS_epoll_wait = 256;
261pub const SYS_remap_file_pages = 257;
262pub const SYS_set_tid_address = 258;
263pub const SYS_timer_create = 259;
264pub const SYS_timer_settime = SYS_timer_create+1;
265pub const SYS_timer_gettime = SYS_timer_create+2;
266pub const SYS_timer_getoverrun = SYS_timer_create+3;
267pub const SYS_timer_delete = SYS_timer_create+4;
268pub const SYS_clock_settime = SYS_timer_create+5;
269pub const SYS_clock_gettime = SYS_timer_create+6;
270pub const SYS_clock_getres = SYS_timer_create+7;
271pub const SYS_clock_nanosleep = SYS_timer_create+8;
272pub const SYS_statfs64 = 268;
273pub const SYS_fstatfs64 = 269;
274pub const SYS_tgkill = 270;
275pub const SYS_utimes = 271;
276pub const SYS_fadvise64_64 = 272;
277pub const SYS_vserver = 273;
278pub const SYS_mbind = 274;
279pub const SYS_get_mempolicy = 275;
280pub const SYS_set_mempolicy = 276;
281pub const SYS_mq_open = 277;
282pub const SYS_mq_unlink = SYS_mq_open+1;
283pub const SYS_mq_timedsend = SYS_mq_open+2;
284pub const SYS_mq_timedreceive = SYS_mq_open+3;
285pub const SYS_mq_notify = SYS_mq_open+4;
286pub const SYS_mq_getsetattr = SYS_mq_open+5;
287pub const SYS_kexec_load = 283;
288pub const SYS_waitid = 284;
289pub const SYS_add_key = 286;
290pub const SYS_request_key = 287;
291pub const SYS_keyctl = 288;
292pub const SYS_ioprio_set = 289;
293pub const SYS_ioprio_get = 290;
294pub const SYS_inotify_init = 291;
295pub const SYS_inotify_add_watch = 292;
296pub const SYS_inotify_rm_watch = 293;
297pub const SYS_migrate_pages = 294;
298pub const SYS_openat = 295;
299pub const SYS_mkdirat = 296;
300pub const SYS_mknodat = 297;
301pub const SYS_fchownat = 298;
302pub const SYS_futimesat = 299;
303pub const SYS_fstatat64 = 300;
304pub const SYS_unlinkat = 301;
305pub const SYS_renameat = 302;
306pub const SYS_linkat = 303;
307pub const SYS_symlinkat = 304;
308pub const SYS_readlinkat = 305;
309pub const SYS_fchmodat = 306;
310pub const SYS_faccessat = 307;
311pub const SYS_pselect6 = 308;
312pub const SYS_ppoll = 309;
313pub const SYS_unshare = 310;
314pub const SYS_set_robust_list = 311;
315pub const SYS_get_robust_list = 312;
316pub const SYS_splice = 313;
317pub const SYS_sync_file_range = 314;
318pub const SYS_tee = 315;
319pub const SYS_vmsplice = 316;
320pub const SYS_move_pages = 317;
321pub const SYS_getcpu = 318;
322pub const SYS_epoll_pwait = 319;
323pub const SYS_utimensat = 320;
324pub const SYS_signalfd = 321;
325pub const SYS_timerfd_create = 322;
326pub const SYS_eventfd = 323;
327pub const SYS_fallocate = 324;
328pub const SYS_timerfd_settime = 325;
329pub const SYS_timerfd_gettime = 326;
330pub const SYS_signalfd4 = 327;
331pub const SYS_eventfd2 = 328;
332pub const SYS_epoll_create1 = 329;
333pub const SYS_dup3 = 330;
334pub const SYS_pipe2 = 331;
335pub const SYS_inotify_init1 = 332;
336pub const SYS_preadv = 333;
337pub const SYS_pwritev = 334;
338pub const SYS_rt_tgsigqueueinfo = 335;
339pub const SYS_perf_event_open = 336;
340pub const SYS_recvmmsg = 337;
341pub const SYS_fanotify_init = 338;
342pub const SYS_fanotify_mark = 339;
343pub const SYS_prlimit64 = 340;
344pub const SYS_name_to_handle_at = 341;
345pub const SYS_open_by_handle_at = 342;
346pub const SYS_clock_adjtime = 343;
347pub const SYS_syncfs = 344;
348pub const SYS_sendmmsg = 345;
349pub const SYS_setns = 346;
350pub const SYS_process_vm_readv = 347;
351pub const SYS_process_vm_writev = 348;
352pub const SYS_kcmp = 349;
353pub const SYS_finit_module = 350;
354pub const SYS_sched_setattr = 351;
355pub const SYS_sched_getattr = 352;
356pub const SYS_renameat2 = 353;
357pub const SYS_seccomp = 354;
358pub const SYS_getrandom = 355;
359pub const SYS_memfd_create = 356;
360pub const SYS_bpf = 357;
361pub const SYS_execveat = 358;
362pub const SYS_socket = 359;
363pub const SYS_socketpair = 360;
364pub const SYS_bind = 361;
365pub const SYS_connect = 362;
366pub const SYS_listen = 363;
367pub const SYS_accept4 = 364;
368pub const SYS_getsockopt = 365;
369pub const SYS_setsockopt = 366;
370pub const SYS_getsockname = 367;
371pub const SYS_getpeername = 368;
372pub const SYS_sendto = 369;
373pub const SYS_sendmsg = 370;
374pub const SYS_recvfrom = 371;
375pub const SYS_recvmsg = 372;
376pub const SYS_shutdown = 373;
377pub const SYS_userfaultfd = 374;
378pub const SYS_membarrier = 375;
379pub const SYS_mlock2 = 376;
380
381
382pub const O_CREAT = 0o100;
383pub const O_EXCL = 0o200;
384pub const O_NOCTTY = 0o400;
385pub const O_TRUNC = 0o1000;
386pub const O_APPEND = 0o2000;
387pub const O_NONBLOCK = 0o4000;
388pub const O_DSYNC = 0o10000;
389pub const O_SYNC = 0o4010000;
390pub const O_RSYNC = 0o4010000;
391pub const O_DIRECTORY = 0o200000;
392pub const O_NOFOLLOW = 0o400000;
393pub const O_CLOEXEC = 0o2000000;
394
395pub const O_ASYNC = 0o20000;
396pub const O_DIRECT = 0o40000;
397pub const O_LARGEFILE = 0o100000;
398pub const O_NOATIME = 0o1000000;
399pub const O_PATH = 0o10000000;
400pub const O_TMPFILE = 0o20200000;
401pub const O_NDELAY = O_NONBLOCK;
402
403pub const F_DUPFD = 0;
404pub const F_GETFD = 1;
405pub const F_SETFD = 2;
406pub const F_GETFL = 3;
407pub const F_SETFL = 4;
408
409pub const F_SETOWN = 8;
410pub const F_GETOWN = 9;
411pub const F_SETSIG = 10;
412pub const F_GETSIG = 11;
413
414pub const F_GETLK = 12;
415pub const F_SETLK = 13;
416pub const F_SETLKW = 14;
417
418pub const F_SETOWN_EX = 15;
419pub const F_GETOWN_EX = 16;
420
421pub const F_GETOWNER_UIDS = 17;
422
423pub inline fn syscall0(number: usize) usize {
424 return asm volatile ("int $0x80"
425 : [ret] "={eax}" (-> usize)
426 : [number] "{eax}" (number));
427}
428
429pub inline fn syscall1(number: usize, arg1: usize) usize {
430 return asm volatile ("int $0x80"
431 : [ret] "={eax}" (-> usize)
432 : [number] "{eax}" (number),
433 [arg1] "{ebx}" (arg1));
434}
435
436pub inline fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
437 return asm volatile ("int $0x80"
438 : [ret] "={eax}" (-> usize)
439 : [number] "{eax}" (number),
440 [arg1] "{ebx}" (arg1),
441 [arg2] "{ecx}" (arg2));
442}
443
444pub inline fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
445 return asm volatile ("int $0x80"
446 : [ret] "={eax}" (-> usize)
447 : [number] "{eax}" (number),
448 [arg1] "{ebx}" (arg1),
449 [arg2] "{ecx}" (arg2),
450 [arg3] "{edx}" (arg3));
451}
452
453pub inline fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
454 return asm volatile ("int $0x80"
455 : [ret] "={eax}" (-> usize)
456 : [number] "{eax}" (number),
457 [arg1] "{ebx}" (arg1),
458 [arg2] "{ecx}" (arg2),
459 [arg3] "{edx}" (arg3),
460 [arg4] "{esi}" (arg4));
461}
462
463pub inline fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize,
464 arg4: usize, arg5: usize) usize
465{
466 return asm volatile ("int $0x80"
467 : [ret] "={eax}" (-> usize)
468 : [number] "{eax}" (number),
469 [arg1] "{ebx}" (arg1),
470 [arg2] "{ecx}" (arg2),
471 [arg3] "{edx}" (arg3),
472 [arg4] "{esi}" (arg4),
473 [arg5] "{edi}" (arg5));
474}
475
476pub inline fn syscall6(number: usize, arg1: usize, arg2: usize, arg3: usize,
477 arg4: usize, arg5: usize, arg6: usize) usize
478{
479 return asm volatile ("int $0x80"
480 : [ret] "={eax}" (-> usize)
481 : [number] "{eax}" (number),
482 [arg1] "{ebx}" (arg1),
483 [arg2] "{ecx}" (arg2),
484 [arg3] "{edx}" (arg3),
485 [arg4] "{esi}" (arg4),
486 [arg5] "{edi}" (arg5),
487 [arg6] "{ebp}" (arg6));
488}
489
490pub nakedcc fn restore() void {
491 asm volatile (
492 \\popl %%eax
493 \\movl $119, %%eax
494 \\int $0x80
495 :
496 :
497 : "rcx", "r11");
498}
499
500pub nakedcc fn restore_rt() void {
501 asm volatile ("int $0x80"
502 :
503 : [number] "{eax}" (usize(SYS_rt_sigreturn))
504 : "rcx", "r11");
505}
std/os/linux/index.zig+166-62
...@@ -101,17 +101,6 @@ pub const SIG_BLOCK = 0;...@@ -101,17 +101,6 @@ pub const SIG_BLOCK = 0;
101pub const SIG_UNBLOCK = 1;101pub const SIG_UNBLOCK = 1;
102pub const SIG_SETMASK = 2;102pub const SIG_SETMASK = 2;
103103
104pub const SOCK_STREAM = 1;
105pub const SOCK_DGRAM = 2;
106pub const SOCK_RAW = 3;
107pub const SOCK_RDM = 4;
108pub const SOCK_SEQPACKET = 5;
109pub const SOCK_DCCP = 6;
110pub const SOCK_PACKET = 10;
111pub const SOCK_CLOEXEC = 0o2000000;
112pub const SOCK_NONBLOCK = 0o4000;
113
114
115pub const PROTO_ip = 0o000;104pub const PROTO_ip = 0o000;
116pub const PROTO_icmp = 0o001;105pub const PROTO_icmp = 0o001;
117pub const PROTO_igmp = 0o002;106pub const PROTO_igmp = 0o002;
...@@ -149,6 +138,20 @@ pub const PROTO_encap = 0o142;...@@ -149,6 +138,20 @@ pub const PROTO_encap = 0o142;
149pub const PROTO_pim = 0o147;138pub const PROTO_pim = 0o147;
150pub const PROTO_raw = 0o377;139pub const PROTO_raw = 0o377;
151140
141pub const SHUT_RD = 0;
142pub const SHUT_WR = 1;
143pub const SHUT_RDWR = 2;
144
145pub const SOCK_STREAM = 1;
146pub const SOCK_DGRAM = 2;
147pub const SOCK_RAW = 3;
148pub const SOCK_RDM = 4;
149pub const SOCK_SEQPACKET = 5;
150pub const SOCK_DCCP = 6;
151pub const SOCK_PACKET = 10;
152pub const SOCK_CLOEXEC = 0o2000000;
153pub const SOCK_NONBLOCK = 0o4000;
154
152pub const PF_UNSPEC = 0;155pub const PF_UNSPEC = 0;
153pub const PF_LOCAL = 1;156pub const PF_LOCAL = 1;
154pub const PF_UNIX = PF_LOCAL;157pub const PF_UNIX = PF_LOCAL;
...@@ -193,7 +196,10 @@ pub const PF_CAIF = 37;...@@ -193,7 +196,10 @@ pub const PF_CAIF = 37;
193pub const PF_ALG = 38;196pub const PF_ALG = 38;
194pub const PF_NFC = 39;197pub const PF_NFC = 39;
195pub const PF_VSOCK = 40;198pub const PF_VSOCK = 40;
196pub const PF_MAX = 41;199pub const PF_KCM = 41;
200pub const PF_QIPCRTR = 42;
201pub const PF_SMC = 43;
202pub const PF_MAX = 44;
197203
198pub const AF_UNSPEC = PF_UNSPEC;204pub const AF_UNSPEC = PF_UNSPEC;
199pub const AF_LOCAL = PF_LOCAL;205pub const AF_LOCAL = PF_LOCAL;
...@@ -239,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;...@@ -239,8 +245,137 @@ pub const AF_CAIF = PF_CAIF;
239pub const AF_ALG = PF_ALG;245pub const AF_ALG = PF_ALG;
240pub const AF_NFC = PF_NFC;246pub const AF_NFC = PF_NFC;
241pub const AF_VSOCK = PF_VSOCK;247pub const AF_VSOCK = PF_VSOCK;
248pub const AF_KCM = PF_KCM;
249pub const AF_QIPCRTR = PF_QIPCRTR;
250pub const AF_SMC = PF_SMC;
242pub const AF_MAX = PF_MAX;251pub const AF_MAX = PF_MAX;
243252
253pub const SO_DEBUG = 1;
254pub const SO_REUSEADDR = 2;
255pub const SO_TYPE = 3;
256pub const SO_ERROR = 4;
257pub const SO_DONTROUTE = 5;
258pub const SO_BROADCAST = 6;
259pub const SO_SNDBUF = 7;
260pub const SO_RCVBUF = 8;
261pub const SO_KEEPALIVE = 9;
262pub const SO_OOBINLINE = 10;
263pub const SO_NO_CHECK = 11;
264pub const SO_PRIORITY = 12;
265pub const SO_LINGER = 13;
266pub const SO_BSDCOMPAT = 14;
267pub const SO_REUSEPORT = 15;
268pub const SO_PASSCRED = 16;
269pub const SO_PEERCRED = 17;
270pub const SO_RCVLOWAT = 18;
271pub const SO_SNDLOWAT = 19;
272pub const SO_RCVTIMEO = 20;
273pub const SO_SNDTIMEO = 21;
274pub const SO_ACCEPTCONN = 30;
275pub const SO_SNDBUFFORCE = 32;
276pub const SO_RCVBUFFORCE = 33;
277pub const SO_PROTOCOL = 38;
278pub const SO_DOMAIN = 39;
279
280pub const SO_SECURITY_AUTHENTICATION = 22;
281pub const SO_SECURITY_ENCRYPTION_TRANSPORT = 23;
282pub const SO_SECURITY_ENCRYPTION_NETWORK = 24;
283
284pub const SO_BINDTODEVICE = 25;
285
286pub const SO_ATTACH_FILTER = 26;
287pub const SO_DETACH_FILTER = 27;
288pub const SO_GET_FILTER = SO_ATTACH_FILTER;
289
290pub const SO_PEERNAME = 28;
291pub const SO_TIMESTAMP = 29;
292pub const SCM_TIMESTAMP = SO_TIMESTAMP;
293
294pub const SO_PEERSEC = 31;
295pub const SO_PASSSEC = 34;
296pub const SO_TIMESTAMPNS = 35;
297pub const SCM_TIMESTAMPNS = SO_TIMESTAMPNS;
298pub const SO_MARK = 36;
299pub const SO_TIMESTAMPING = 37;
300pub const SCM_TIMESTAMPING = SO_TIMESTAMPING;
301pub const SO_RXQ_OVFL = 40;
302pub const SO_WIFI_STATUS = 41;
303pub const SCM_WIFI_STATUS = SO_WIFI_STATUS;
304pub const SO_PEEK_OFF = 42;
305pub const SO_NOFCS = 43;
306pub const SO_LOCK_FILTER = 44;
307pub const SO_SELECT_ERR_QUEUE = 45;
308pub const SO_BUSY_POLL = 46;
309pub const SO_MAX_PACING_RATE = 47;
310pub const SO_BPF_EXTENSIONS = 48;
311pub const SO_INCOMING_CPU = 49;
312pub const SO_ATTACH_BPF = 50;
313pub const SO_DETACH_BPF = SO_DETACH_FILTER;
314pub const SO_ATTACH_REUSEPORT_CBPF = 51;
315pub const SO_ATTACH_REUSEPORT_EBPF = 52;
316pub const SO_CNX_ADVICE = 53;
317pub const SCM_TIMESTAMPING_OPT_STATS = 54;
318pub const SO_MEMINFO = 55;
319pub const SO_INCOMING_NAPI_ID = 56;
320pub const SO_COOKIE = 57;
321pub const SCM_TIMESTAMPING_PKTINFO = 58;
322pub const SO_PEERGROUPS = 59;
323pub const SO_ZEROCOPY = 60;
324
325pub const SOL_SOCKET = 1;
326
327pub const SOL_IP = 0;
328pub const SOL_IPV6 = 41;
329pub const SOL_ICMPV6 = 58;
330
331pub const SOL_RAW = 255;
332pub const SOL_DECNET = 261;
333pub const SOL_X25 = 262;
334pub const SOL_PACKET = 263;
335pub const SOL_ATM = 264;
336pub const SOL_AAL = 265;
337pub const SOL_IRDA = 266;
338pub const SOL_NETBEUI = 267;
339pub const SOL_LLC = 268;
340pub const SOL_DCCP = 269;
341pub const SOL_NETLINK = 270;
342pub const SOL_TIPC = 271;
343pub const SOL_RXRPC = 272;
344pub const SOL_PPPOL2TP = 273;
345pub const SOL_BLUETOOTH = 274;
346pub const SOL_PNPIPE = 275;
347pub const SOL_RDS = 276;
348pub const SOL_IUCV = 277;
349pub const SOL_CAIF = 278;
350pub const SOL_ALG = 279;
351pub const SOL_NFC = 280;
352pub const SOL_KCM = 281;
353pub const SOL_TLS = 282;
354
355pub const SOMAXCONN = 128;
356
357pub const MSG_OOB = 0x0001;
358pub const MSG_PEEK = 0x0002;
359pub const MSG_DONTROUTE = 0x0004;
360pub const MSG_CTRUNC = 0x0008;
361pub const MSG_PROXY = 0x0010;
362pub const MSG_TRUNC = 0x0020;
363pub const MSG_DONTWAIT = 0x0040;
364pub const MSG_EOR = 0x0080;
365pub const MSG_WAITALL = 0x0100;
366pub const MSG_FIN = 0x0200;
367pub const MSG_SYN = 0x0400;
368pub const MSG_CONFIRM = 0x0800;
369pub const MSG_RST = 0x1000;
370pub const MSG_ERRQUEUE = 0x2000;
371pub const MSG_NOSIGNAL = 0x4000;
372pub const MSG_MORE = 0x8000;
373pub const MSG_WAITFORONE = 0x10000;
374pub const MSG_BATCH = 0x40000;
375pub const MSG_ZEROCOPY = 0x4000000;
376pub const MSG_FASTOPEN = 0x20000000;
377pub const MSG_CMSG_CLOEXEC = 0x40000000;
378
244pub const DT_UNKNOWN = 0;379pub const DT_UNKNOWN = 0;
245pub const DT_FIFO = 1;380pub const DT_FIFO = 1;
246pub const DT_CHR = 2;381pub const DT_CHR = 2;
...@@ -599,30 +734,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {...@@ -599,30 +734,27 @@ pub fn sigismember(set: &const sigset_t, sig: u6) bool {
599 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;734 return ((*set)[usize(s) / usize.bit_count] & (usize(1) << (s & (usize.bit_count - 1)))) != 0;
600}735}
601736
602737pub const in_port_t = u16;
603pub const sa_family_t = u16;738pub const sa_family_t = u16;
604pub const socklen_t = u32;739pub const socklen_t = u32;
605pub const in_addr = u32;
606pub const in6_addr = [16]u8;
607740
608pub const sockaddr = extern struct {741pub const sockaddr = extern union {
609 family: sa_family_t,742 in: sockaddr_in,
610 port: u16,743 in6: sockaddr_in6,
611 data: [12]u8,
612};744};
613745
614pub const sockaddr_in = extern struct {746pub const sockaddr_in = extern struct {
615 family: sa_family_t,747 family: sa_family_t,
616 port: u16,748 port: in_port_t,
617 addr: in_addr,749 addr: u32,
618 zero: [8]u8,750 zero: [8]u8,
619};751};
620752
621pub const sockaddr_in6 = extern struct {753pub const sockaddr_in6 = extern struct {
622 family: sa_family_t,754 family: sa_family_t,
623 port: u16,755 port: in_port_t,
624 flowinfo: u32,756 flowinfo: u32,
625 addr: in6_addr,757 addr: [16]u8,
626 scope_id: u32,758 scope_id: u32,
627};759};
628760
...@@ -639,16 +771,16 @@ pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) us...@@ -639,16 +771,16 @@ pub fn getpeername(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t) us
639 return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));771 return syscall3(SYS_getpeername, usize(fd), @ptrToInt(addr), @ptrToInt(len));
640}772}
641773
642pub fn socket(domain: i32, socket_type: i32, protocol: i32) usize {774pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
643 return syscall3(SYS_socket, usize(domain), usize(socket_type), usize(protocol));775 return syscall3(SYS_socket, domain, socket_type, protocol);
644}776}
645777
646pub fn setsockopt(fd: i32, level: i32, optname: i32, optval: &const u8, optlen: socklen_t) usize {778pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: &const u8, optlen: socklen_t) usize {
647 return syscall5(SYS_setsockopt, usize(fd), usize(level), usize(optname), usize(optval), @ptrToInt(optlen));779 return syscall5(SYS_setsockopt, usize(fd), level, optname, usize(optval), @ptrToInt(optlen));
648}780}
649781
650pub fn getsockopt(fd: i32, level: i32, optname: i32, noalias optval: &u8, noalias optlen: &socklen_t) usize {782pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: &u8, noalias optlen: &socklen_t) usize {
651 return syscall5(SYS_getsockopt, usize(fd), usize(level), usize(optname), @ptrToInt(optval), @ptrToInt(optlen));783 return syscall5(SYS_getsockopt, usize(fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
652}784}
653785
654pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {786pub fn sendmsg(fd: i32, msg: &const msghdr, flags: u32) usize {
...@@ -677,8 +809,8 @@ pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {...@@ -677,8 +809,8 @@ pub fn bind(fd: i32, addr: &const sockaddr, len: socklen_t) usize {
677 return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));809 return syscall3(SYS_bind, usize(fd), @ptrToInt(addr), usize(len));
678}810}
679811
680pub fn listen(fd: i32, backlog: i32) usize {812pub fn listen(fd: i32, backlog: u32) usize {
681 return syscall2(SYS_listen, usize(fd), usize(backlog));813 return syscall2(SYS_listen, usize(fd), backlog);
682}814}
683815
684pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {816pub fn sendto(fd: i32, buf: &const u8, len: usize, flags: u32, addr: ?&const sockaddr, alen: socklen_t) usize {
...@@ -697,46 +829,18 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:...@@ -697,46 +829,18 @@ pub fn accept4(fd: i32, noalias addr: &sockaddr, noalias len: &socklen_t, flags:
697 return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);829 return syscall4(SYS_accept4, usize(fd), @ptrToInt(addr), @ptrToInt(len), flags);
698}830}
699831
700// error NameTooLong;
701// error SystemResources;
702// error Io;
703//
704// pub fn if_nametoindex(name: []u8) !u32 {
705// var ifr: ifreq = undefined;
706//
707// if (name.len >= ifr.ifr_name.len) {
708// return error.NameTooLong;
709// }
710//
711// const socket_ret = socket(AF_UNIX, SOCK_DGRAM|SOCK_CLOEXEC, 0);
712// const socket_err = getErrno(socket_ret);
713// if (socket_err > 0) {
714// return error.SystemResources;
715// }
716// const socket_fd = i32(socket_ret);
717// @memcpy(&ifr.ifr_name[0], &name[0], name.len);
718// ifr.ifr_name[name.len] = 0;
719// const ioctl_ret = ioctl(socket_fd, SIOCGIFINDEX, &ifr);
720// close(socket_fd);
721// const ioctl_err = getErrno(ioctl_ret);
722// if (ioctl_err > 0) {
723// return error.Io;
724// }
725// return ifr.ifr_ifindex;
726// }
727
728pub fn fstat(fd: i32, stat_buf: &Stat) usize {832pub fn fstat(fd: i32, stat_buf: &Stat) usize {
729 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));833 return syscall2(SYS_fstat, usize(fd), @ptrToInt(stat_buf));
730}834}
731835
732pub const epoll_data = extern union {836pub const epoll_data = packed union {
733 ptr: usize,837 ptr: usize,
734 fd: i32,838 fd: i32,
735 @"u32": u32,839 @"u32": u32,
736 @"u64": u64,840 @"u64": u64,
737};841};
738842
739pub const epoll_event = extern struct {843pub const epoll_event = packed struct {
740 events: u32,844 events: u32,
741 data: epoll_data,845 data: epoll_data,
742};846};
...@@ -749,7 +853,7 @@ pub fn epoll_create1(flags: usize) usize {...@@ -749,7 +853,7 @@ pub fn epoll_create1(flags: usize) usize {
749 return syscall1(SYS_epoll_create1, flags);853 return syscall1(SYS_epoll_create1, flags);
750}854}
751855
752pub fn epoll_ctl(epoll_fd: i32, op: i32, fd: i32, ev: &epoll_event) usize {856pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: &epoll_event) usize {
753 return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));857 return syscall4(SYS_epoll_ctl, usize(epoll_fd), usize(op), usize(fd), @ptrToInt(ev));
754}858}
755859
std/os/linux/x86_64.zig+8
...@@ -488,3 +488,11 @@ pub const timespec = extern struct {...@@ -488,3 +488,11 @@ pub const timespec = extern struct {
488 tv_sec: isize,488 tv_sec: isize,
489 tv_nsec: isize,489 tv_nsec: isize,
490};490};
491
492pub const dirent = extern struct {
493 d_ino: usize,
494 d_off: usize,
495 d_reclen: u16,
496 d_name: u8, // field address is the address of first byte of name
497};
498
std/os/test.zig created+25
...@@ -0,0 +1,25 @@
1const std = @import("../index.zig");
2const os = std.os;
3const assert = std.debug.assert;
4const io = std.io;
5
6const a = std.debug.global_allocator;
7
8const builtin = @import("builtin");
9
10test "makePath, put some files in it, deleteTree" {
11 if (builtin.os == builtin.Os.windows) {
12 // TODO implement os.Dir for windows
13 // https://github.com/zig-lang/zig/issues/709
14 return;
15 }
16 try os.makePath(a, "os_test_tmp/b/c");
17 try io.writeFile(a, "os_test_tmp/b/c/file.txt", "nonsense");
18 try io.writeFile(a, "os_test_tmp/b/file2.txt", "blah");
19 try os.deleteTree(a, "os_test_tmp");
20 if (os.Dir.open(a, "os_test_tmp")) |dir| {
21 @panic("expected error");
22 } else |err| {
23 assert(err == error.PathNotFound);
24 }
25}
test/cases/coroutines.zig+35
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const assert = std.debug.assert;3const assert = std.debug.assert;
34
4var x: i32 = 1;5var x: i32 = 1;
...@@ -189,3 +190,37 @@ async fn failing() !void {...@@ -189,3 +190,37 @@ async fn failing() !void {
189 suspend;190 suspend;
190 return error.Fail;191 return error.Fail;
191}192}
193
194test "error return trace across suspend points - early return" {
195 const p = nonFailing();
196 resume p;
197 const p2 = try async<std.debug.global_allocator> printTrace(p);
198 cancel p2;
199}
200
201test "error return trace across suspend points - async return" {
202 const p = nonFailing();
203 const p2 = try async<std.debug.global_allocator> printTrace(p);
204 resume p;
205 cancel p2;
206}
207
208fn nonFailing() promise->error!void {
209 return async<std.debug.global_allocator> suspendThenFail() catch unreachable;
210}
211
212async fn suspendThenFail() error!void {
213 suspend;
214 return error.Fail;
215}
216
217async fn printTrace(p: promise->error!void) void {
218 (await p) catch |e| {
219 std.debug.assert(e == error.Fail);
220 if (@errorReturnTrace()) |trace| {
221 assert(trace.index == 1);
222 } else if (builtin.mode != builtin.Mode.ReleaseFast) {
223 @panic("expected return trace");
224 }
225 };
226}