Merge remote-tracking branch 'origin/master' into llvm8

master
Andrew Kelley 2018-12-23 17:04:26 -05:00
commit c00216701c
124 changed files with 6601 additions and 1907 deletions

22
.builds/freebsd.yml Normal file
View File

@ -0,0 +1,22 @@
arch: x86_64
image: freebsd
packages:
- cmake
- ninja
- llvm70
sources:
- https://github.com/ziglang/zig.git
tasks:
- build: |
cd zig && mkdir build && cd build
cmake .. -GNinja -DCMAKE_BUILD_TYPE=Release
ninja install
- test: |
cd zig/build
bin/zig test ../test/behavior.zig
# TODO enable all tests
#bin/zig build --build-file ../build.zig test
# TODO integrate with the download page updater and make a
# static build available to download for FreeBSD.
# This will require setting up a cache of LLVM/Clang built
# statically.

View File

@ -444,6 +444,7 @@ set(ZIG_STD_FILES
"buffer.zig"
"build.zig"
"c/darwin.zig"
"c/freebsd.zig"
"c/index.zig"
"c/linux.zig"
"c/windows.zig"
@ -490,6 +491,7 @@ set(ZIG_STD_FILES
"heap.zig"
"index.zig"
"io.zig"
"io/seekable_stream.zig"
"json.zig"
"lazy_init.zig"
"linked_list.zig"
@ -582,6 +584,10 @@ set(ZIG_STD_FILES
"os/linux/vdso.zig"
"os/linux/x86_64.zig"
"os/linux/arm64.zig"
"os/freebsd/errno.zig"
"os/freebsd/index.zig"
"os/freebsd/syscall.zig"
"os/freebsd/x86_64.zig"
"os/path.zig"
"os/time.zig"
"os/windows/advapi32.zig"
@ -617,6 +623,16 @@ set(ZIG_STD_FILES
"special/compiler_rt/fixunstfdi.zig"
"special/compiler_rt/fixunstfsi.zig"
"special/compiler_rt/fixunstfti.zig"
"special/compiler_rt/fixint.zig"
"special/compiler_rt/fixdfdi.zig"
"special/compiler_rt/fixdfsi.zig"
"special/compiler_rt/fixdfti.zig"
"special/compiler_rt/fixsfdi.zig"
"special/compiler_rt/fixsfsi.zig"
"special/compiler_rt/fixsfti.zig"
"special/compiler_rt/fixtfdi.zig"
"special/compiler_rt/fixtfsi.zig"
"special/compiler_rt/fixtfti.zig"
"special/compiler_rt/floattidf.zig"
"special/compiler_rt/floattisf.zig"
"special/compiler_rt/floattitf.zig"

View File

@ -42,33 +42,71 @@ clarity.
* In addition to creating executables, creating a C library is a primary use
case. You can export an auto-generated .h file.
### Support Table
### Supported Targets
Freestanding means that you do not directly interact with the OS
or you are writing your own OS.
#### Tier 1 Support
Note that if you use libc or other libraries to interact with the OS,
that counts as "freestanding" for the purposes of this table.
* Not only can Zig generate machine code for these targets, but the standard
library cross-platform abstractions have implementations for these targets.
Thus it is practical to write a pure Zig application with no dependency on
libc.
* The CI server automatically tests these targets on every commit to master
branch, and updates ziglang.org/download with links to pre-built binaries.
* These targets have debug info capabilities and therefore produce stack
traces on failed assertions.
| | freestanding | linux | macosx | windows | other |
|-------------|--------------|---------|---------|---------|---------|
|i386 | OK | planned | OK | planned | planned |
|x86_64 | OK | OK | OK | OK | planned |
|arm | OK | planned | planned | planned | planned |
|bpf | OK | planned | N/A | N/A | planned |
|hexagon | OK | planned | N/A | N/A | planned |
|mips | OK | planned | N/A | N/A | planned |
|powerpc | OK | planned | N/A | N/A | planned |
|r600 | OK | planned | N/A | N/A | planned |
|amdgcn | OK | planned | N/A | N/A | planned |
|sparc | OK | planned | N/A | N/A | planned |
|s390x | OK | planned | N/A | N/A | planned |
|spir | OK | planned | N/A | N/A | planned |
|lanai | OK | planned | N/A | N/A | planned |
|wasm32 | planned | N/A | N/A | N/A | N/A |
|wasm64 | planned | N/A | N/A | N/A | N/A |
|riscv32 | planned | planned | N/A | N/A | planned |
|riscv64 | planned | planned | N/A | N/A | planned |
#### Tier 2 Support
* There may be some standard library implementations, but many abstractions
will give an "Unsupported OS" compile error. One can link with libc or other
libraries to fill in the gaps in the standard library.
* These targets are known to work, but are not automatically tested, so there
are occasional regressions.
* Some tests may be disabled for these targets as we work toward Tier 1
support.
#### Tier 3 Support
* The standard library has little to no knowledge of the existence of this
target.
* Because Zig is based on LLVM, it has the capability to build for these
targets, and LLVM has the target enabled by default.
* These targets are not frequently tested; one will likely need to contribute
to Zig in order to build for these targets.
* The Zig compiler might need to be updated with a few things such as
- what sizes are the C integer types
- C ABI calling convention for this target
- bootstrap code and default panic handler
#### Tier 4 Support
* Support for these targets is entirely experimental.
* LLVM may have the target as an experimental target, which means that you
need to use Zig-provided binaries for the target to be available, or
build LLVM from source with special configure flags.
#### Support Table
| | freestanding | linux | macosx | windows | freebsd | other |
|--------|--------------|--------|--------|---------|---------|--------|
|x86_64 | Tier 2 | Tier 1 | Tier 1 | Tier 1 | Tier 2 | Tier 3 |
|i386 | Tier 2 | Tier 2 | Tier 2 | Tier 2 | Tier 3 | Tier 3 |
|arm | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|arm64 | Tier 2 | Tier 2 | Tier 3 | Tier 3 | Tier 3 | Tier 3 |
|bpf | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|hexagon | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|mips | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|powerpc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|r600 | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|amdgcn | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|sparc | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|s390x | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|spir | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|lanai | Tier 3 | Tier 3 | N/A | N/A | Tier 3 | Tier 3 |
|wasm32 | Tier 4 | N/A | N/A | N/A | N/A | N/A |
|wasm64 | Tier 4 | N/A | N/A | N/A | N/A | N/A |
|riscv32 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 |
|riscv64 | Tier 4 | Tier 4 | N/A | N/A | Tier 4 | Tier 4 |
## Community
@ -133,7 +171,8 @@ See https://github.com/ziglang/zig/wiki/Building-Zig-on-Windows
*Note: Stage 2 compiler is not complete. Beta users of Zig should use the
Stage 1 compiler for now.*
Dependencies are the same as Stage 1, except now you have a working zig compiler.
Dependencies are the same as Stage 1, except now you can use stage 1 to compile
Zig code.
```
bin/zig build --build-file ../build.zig --prefix $(pwd)/stage2 install
@ -145,11 +184,13 @@ binary.
### Stage 3: Rebuild Self-Hosted Zig Using the Self-Hosted Compiler
This is the actual compiler binary that we will install to the system.
*Note: Stage 2 compiler is not yet able to build Stage 3. Building Stage 3 is
not yet supported.*
Once the self-hosted compiler can build itself, this will be the actual
compiler binary that we will install to the system. Until then, users should
use stage 1.
#### Debug / Development Build
```

View File

@ -297,7 +297,7 @@ fn configureStage2(b: *Builder, exe: var, ctx: Context) !void {
);
exe.linkSystemLibrary("pthread");
} else if (exe.target.isDarwin()) {
} else if (exe.target.isDarwin() or exe.target.isFreeBSD()) {
if (addCxxKnownPath(b, ctx, exe, "libgcc_eh.a", "")) {
// Compiler is GCC.
try addCxxKnownPath(b, ctx, exe, "libstdc++.a", null);

View File

@ -34,6 +34,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
SHASUM=$(sha256sum $ARTIFACTSDIR/$TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $ARTIFACTSDIR/$TARBALL)
# `set -x` causes these variables to be mangled.
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
set +x
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"

View File

@ -98,6 +98,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $TARBALL)
# `set -x` causes these variables to be mangled.
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
set +x
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"

View File

@ -3,6 +3,7 @@
set -x
set -e
pacman -Su --needed --noconfirm
pacman -S --needed --noconfirm wget p7zip python3-pip
pip install s3cmd
wget -nv "https://ziglang.org/deps/llvm%2bclang-8.0.0-win64-msvc-release.tar.xz"

View File

@ -25,6 +25,9 @@ if [ "${BUILD_REASON}" != "PullRequest" ]; then
SHASUM=$(sha256sum $TARBALL | cut '-d ' -f1)
BYTESIZE=$(wc -c < $TARBALL)
# `set -x` causes these variables to be mangled.
# See https://developercommunity.visualstudio.com/content/problem/375679/pipeline-variable-incorrectly-inserts-single-quote.html
set +x
echo "##vso[task.setvariable variable=tarball;isOutput=true]$TARBALL"
echo "##vso[task.setvariable variable=shasum;isOutput=true]$SHASUM"
echo "##vso[task.setvariable variable=bytesize;isOutput=true]$BYTESIZE"

View File

@ -30,6 +30,7 @@ else()
/usr/lib/llvm/8/include
/usr/lib/llvm-8/include
/usr/lib/llvm-8.0/include
/usr/local/llvm80/include
/mingw64/include)
macro(FIND_AND_ADD_CLANG_LIB _libname_)
@ -40,6 +41,7 @@ else()
/usr/lib/llvm/8/lib
/usr/lib/llvm-8/lib
/usr/lib/llvm-8.0/lib
/usr/local/llvm80/lib
/mingw64/lib
/c/msys64/mingw64/lib
c:\\msys64\\mingw64\\lib)

View File

@ -9,9 +9,14 @@
find_path(LLD_INCLUDE_DIRS NAMES lld/Common/Driver.h
PATHS
/usr/lib/llvm-8.0/include
/usr/local/llvm80/include
/mingw64/include)
find_library(LLD_LIBRARY NAMES lld-8.0 lld PATHS /usr/lib/llvm-8.0/lib)
find_library(LLD_LIBRARY NAMES lld-8.0 lld80 lld
PATHS
/usr/lib/llvm-8.0/lib
/usr/local/llvm80/lib
)
if(EXISTS ${LLD_LIBRARY})
set(LLD_LIBRARIES ${LLD_LIBRARY})
else()
@ -20,6 +25,7 @@ else()
find_library(LLD_${_prettylibname_}_LIB NAMES ${_libname_}
PATHS
/usr/lib/llvm-8.0/lib
/usr/local/llvm80/lib
/mingw64/lib
/c/msys64/mingw64/lib
c:/msys64/mingw64/lib)

View File

@ -8,7 +8,7 @@
# LLVM_LIBDIRS
find_program(LLVM_CONFIG_EXE
NAMES llvm-config-8 llvm-config-8.0 llvm-config
NAMES llvm-config-8 llvm-config-8.0 llvm-config80 llvm-config
PATHS
"/mingw64/bin"
"/c/msys64/mingw64/bin"

View File

@ -95,7 +95,7 @@ void OutputSection::addSection(InputSection *IS) {
Flags = IS->Flags;
} else {
// Otherwise, check if new type or flags are compatible with existing ones.
unsigned Mask = SHF_ALLOC | SHF_TLS | SHF_LINK_ORDER;
unsigned Mask = SHF_TLS | SHF_LINK_ORDER;
if ((Flags & Mask) != (IS->Flags & Mask))
error("incompatible section flags for " + Name + "\n>>> " + toString(IS) +
": 0x" + utohexstr(IS->Flags) + "\n>>> output section " + Name +

View File

@ -8,7 +8,13 @@
body{
background-color:#111;
color: #bbb;
font-family: sans-serif;
font-family: system-ui,
/* Fallbacks for browsers that don't support system-ui */
/* https://caniuse.com/#search=system-ui */
-apple-system, /* iOS and macOS */
Roboto, /* Android */
"Segoe UI", /* Windows */
sans-serif;
}
a {
color: #88f;
@ -159,7 +165,7 @@ const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
var stdout_file = try std.io.getStdOut();
const stdout_file = try std.io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");
@ -3273,13 +3279,13 @@ const err = (error {FileNotFound}).FileNotFound;
This becomes useful when using {#link|Inferred Error Sets#}.
</p>
{#header_open|The Global Error Set#}
<p>{#syntax#}error{#endsyntax#} refers to the global error set.
<p>{#syntax#}anyerror{#endsyntax#} refers to the global error set.
This is the error set that contains all errors in the entire compilation unit.
It is a superset of all other error sets and a subset of none of them.
</p>
<p>
You can implicitly cast any error set to the global one, and you can explicitly
cast an error of global error set to a non-global one. This inserts a language-level
cast an error of the global error set to a non-global one. This inserts a language-level
assert to make sure the error value is in fact in the destination error set.
</p>
<p>
@ -4264,13 +4270,21 @@ fn foo() i32 {
return 1234;
}
{#code_end#}
<p>However, if the expression has type {#syntax#}void{#endsyntax#}:</p>
<p>However, if the expression has type {#syntax#}void{#endsyntax#}, there will be no error. Function return values can also be explicitly ignored by assigning them to {#syntax#}_{#endsyntax#}. </p>
{#code_begin|test#}
test "ignoring expression value" {
foo();
test "void is ignored" {
returnsVoid();
}
fn foo() void {}
test "explicitly ignoring expression value" {
_ = foo();
}
fn returnsVoid() void {}
fn foo() i32 {
return 1234;
}
{#code_end#}
{#header_close#}
@ -5155,6 +5169,34 @@ fn seq(c: u8) void {
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
</p>
{#header_close#}
{#header_open|@alignCast#}
<pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>
<p>
{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#},
{#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#}
except with the alignment adjusted to the new value.
</p>
<p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added
to the generated code to make sure the pointer is aligned as promised.</p>
{#header_close#}
{#header_open|@alignOf#}
<pre>{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}</pre>
<p>
This function returns the number of bytes that this type should be aligned to
for the current target to match the C ABI. When the child type of a pointer has
this alignment, the alignment can be omitted from the type.
</p>
<pre>{#syntax#}const assert = @import("std").debug.assert;
comptime {
assert(*u32 == *align(@alignOf(u32)) u32);
}{#endsyntax#}</pre>
<p>
The result is a target-specific compile time constant. It is guaranteed to be
less than or equal to {#link|@sizeOf(T)|@sizeOf#}.
</p>
{#see_also|Alignment#}
{#header_close#}
{#header_open|@ArgType#}
<pre>{#syntax#}@ArgType(comptime T: type, comptime n: usize) type{#endsyntax#}</pre>
<p>
@ -5227,6 +5269,7 @@ fn seq(c: u8) void {
Works at compile-time if {#syntax#}value{#endsyntax#} is known at compile time. It's a compile error to bitcast a struct to a scalar type of the same size since structs have undefined layout. However if the struct is packed then it works.
</p>
{#header_close#}
{#header_open|@bitOffsetOf#}
<pre>{#syntax#}@bitOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
<p>
@ -5239,52 +5282,6 @@ fn seq(c: u8) void {
</p>
{#see_also|@byteOffsetOf#}
{#header_close#}
{#header_open|@breakpoint#}
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
<p>
This function inserts a platform-specific debug trap instruction which causes
debuggers to break there.
</p>
<p>
This function is only valid within function scope.
</p>
{#header_close#}
{#header_open|@byteOffsetOf#}
<pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
<p>
Returns the byte offset of a field relative to its containing struct.
</p>
{#see_also|@bitOffsetOf#}
{#header_close#}
{#header_open|@alignCast#}
<pre>{#syntax#}@alignCast(comptime alignment: u29, ptr: var) var{#endsyntax#}</pre>
<p>
{#syntax#}ptr{#endsyntax#} can be {#syntax#}*T{#endsyntax#}, {#syntax#}fn(){#endsyntax#}, {#syntax#}?*T{#endsyntax#},
{#syntax#}?fn(){#endsyntax#}, or {#syntax#}[]T{#endsyntax#}. It returns the same type as {#syntax#}ptr{#endsyntax#}
except with the alignment adjusted to the new value.
</p>
<p>A {#link|pointer alignment safety check|Incorrect Pointer Alignment#} is added
to the generated code to make sure the pointer is aligned as promised.</p>
{#header_close#}
{#header_open|@alignOf#}
<pre>{#syntax#}@alignOf(comptime T: type) comptime_int{#endsyntax#}</pre>
<p>
This function returns the number of bytes that this type should be aligned to
for the current target to match the C ABI. When the child type of a pointer has
this alignment, the alignment can be omitted from the type.
</p>
<pre>{#syntax#}const assert = @import("std").debug.assert;
comptime {
assert(*u32 == *align(@alignOf(u32)) u32);
}{#endsyntax#}</pre>
<p>
The result is a target-specific compile time constant. It is guaranteed to be
less than or equal to {#link|@sizeOf(T)|@sizeOf#}.
</p>
{#see_also|Alignment#}
{#header_close#}
{#header_open|@boolToInt#}
<pre>{#syntax#}@boolToInt(value: bool) u1{#endsyntax#}</pre>
@ -5298,6 +5295,35 @@ comptime {
</p>
{#header_close#}
{#header_open|@breakpoint#}
<pre>{#syntax#}@breakpoint(){#endsyntax#}</pre>
<p>
This function inserts a platform-specific debug trap instruction which causes
debuggers to break there.
</p>
<p>
This function is only valid within function scope.
</p>
{#header_close#}
{#header_open|@bswap#}
<pre>{#syntax#}@bswap(comptime T: type, value: T) T{#endsyntax#}</pre>
<p>{#syntax#}T{#endsyntax#} must be an integer type with bit count evenly divisible by 8.</p>
<p>
Swaps the byte order of the integer. This converts a big endian integer to a little endian integer,
and converts a little endian integer to a big endian integer.
</p>
{#header_close#}
{#header_open|@byteOffsetOf#}
<pre>{#syntax#}@byteOffsetOf(comptime T: type, comptime field_name: [] const u8) comptime_int{#endsyntax#}</pre>
<p>
Returns the byte offset of a field relative to its containing struct.
</p>
{#see_also|@bitOffsetOf#}
{#header_close#}
{#header_open|@bytesToSlice#}
<pre>{#syntax#}@bytesToSlice(comptime Element: type, bytes: []u8) []Element{#endsyntax#}</pre>
<p>
@ -5364,17 +5390,7 @@ comptime {
</p>
{#see_also|Import from C Header File|@cImport|@cDefine|@cUndef#}
{#header_close#}
{#header_open|@cUndef#}
<pre>{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}</pre>
<p>
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
</p>
<p>
This appends <code>#undef $name</code> to the {#syntax#}@cImport{#endsyntax#}
temporary buffer.
</p>
{#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
{#header_close#}
{#header_open|@clz#}
<pre>{#syntax#}@clz(x: T) U{#endsyntax#}</pre>
<p>
@ -5390,6 +5406,7 @@ comptime {
</p>
{#see_also|@ctz|@popCount#}
{#header_close#}
{#header_open|@cmpxchgStrong#}
<pre>{#syntax#}@cmpxchgStrong(comptime T: type, ptr: *T, expected_value: T, new_value: T, success_order: AtomicOrder, fail_order: AtomicOrder) ?T{#endsyntax#}</pre>
<p>
@ -5445,6 +5462,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
<p>{#syntax#}@typeOf(ptr).alignment{#endsyntax#} must be {#syntax#}>= @sizeOf(T).{#endsyntax#}</p>
{#see_also|Compile Variables|cmpxchgStrong#}
{#header_close#}
{#header_open|@compileError#}
<pre>{#syntax#}@compileError(comptime msg: []u8){#endsyntax#}</pre>
<p>
@ -5457,6 +5475,7 @@ fn cmpxchgWeakButNotAtomic(comptime T: type, ptr: *T, expected_value: T, new_val
and {#syntax#}comptime{#endsyntax#} functions.
</p>
{#header_close#}
{#header_open|@compileLog#}
<pre>{#syntax#}@compileLog(args: ...){#endsyntax#}</pre>
<p>
@ -5511,6 +5530,7 @@ test "main" {
}
{#code_end#}
{#header_close#}
{#header_open|@ctz#}
<pre>{#syntax#}@ctz(x: T) U{#endsyntax#}</pre>
<p>
@ -5526,6 +5546,19 @@ test "main" {
</p>
{#see_also|@clz|@popCount#}
{#header_close#}
{#header_open|@cUndef#}
<pre>{#syntax#}@cUndef(comptime name: []u8){#endsyntax#}</pre>
<p>
This function can only occur inside {#syntax#}@cImport{#endsyntax#}.
</p>
<p>
This appends <code>#undef $name</code> to the {#syntax#}@cImport{#endsyntax#}
temporary buffer.
</p>
{#see_also|Import from C Header File|@cImport|@cDefine|@cInclude#}
{#header_close#}
{#header_open|@divExact#}
<pre>{#syntax#}@divExact(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
@ -5592,27 +5625,15 @@ test "main" {
{#see_also|@intToEnum#}
{#header_close#}
{#header_open|@errSetCast#}
<pre>{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}</pre>
<p>
Converts an error value from one error set to another error set. Attempting to convert an error
which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
</p>
{#header_close#}
{#header_open|@errorName#}
<pre>{#syntax#}@errorName(err: error) []u8{#endsyntax#}</pre>
<pre>{#syntax#}@errorName(err: anyerror) []const u8{#endsyntax#}</pre>
<p>
This function returns the string representation of an error. If an error
declaration is:
</p>
<pre>{#syntax#}error OutOfMem{#endsyntax#}</pre>
<p>
Then the string representation is {#syntax#}"OutOfMem"{#endsyntax#}.
This function returns the string representation of an error. The string representation
of {#syntax#}error.OutOfMem{#endsyntax#} is {#syntax#}"OutOfMem"{#endsyntax#}.
</p>
<p>
If there are no calls to {#syntax#}@errorName{#endsyntax#} in an entire application,
or all calls have a compile-time known value for {#syntax#}err{#endsyntax#}, then no
or all calls have a compile-time known value for {#syntax#}err{#endsyntax#}, then no
error name table will be generated.
</p>
{#header_close#}
@ -5627,13 +5648,14 @@ test "main" {
{#header_close#}
{#header_open|@errorToInt#}
<pre>{#syntax#}@errorToInt(err: var) @IntType(false, @sizeOf(error) * 8){#endsyntax#}</pre>
<pre>{#syntax#}@errorToInt(err: var) @IntType(false, @sizeOf(anyerror) * 8){#endsyntax#}</pre>
<p>
Supports the following types:
</p>
<ul>
<li>error unions</li>
<li>{#syntax#}E!void{#endsyntax#}</li>
<li>{#link|The Global Error Set#}</li>
<li>{#link|Error Set Type#}</li>
<li>{#link|Error Union Type#}</li>
</ul>
<p>
Converts an error to the integer representation of an error.
@ -5645,6 +5667,14 @@ test "main" {
{#see_also|@intToError#}
{#header_close#}
{#header_open|@errSetCast#}
<pre>{#syntax#}@errSetCast(comptime T: DestType, value: var) DestType{#endsyntax#}</pre>
<p>
Converts an error value from one error set to another error set. Attempting to convert an error
which is not in the destination error set results in safety-protected {#link|Undefined Behavior#}.
</p>
{#header_close#}
{#header_open|@export#}
<pre>{#syntax#}@export(comptime name: []const u8, target: var, linkage: builtin.GlobalLinkage) []const u8{#endsyntax#}</pre>
<p>
@ -5713,6 +5743,7 @@ test "main" {
This function is only valid within function scope.
</p>
{#header_close#}
{#header_open|@handle#}
<pre>{#syntax#}@handle(){#endsyntax#}</pre>
<p>
@ -5723,6 +5754,7 @@ test "main" {
This function is only valid within an async function scope.
</p>
{#header_close#}
{#header_open|@import#}
<pre>{#syntax#}@import(comptime path: []u8) (namespace){#endsyntax#}</pre>
<p>
@ -5743,6 +5775,7 @@ test "main" {
</ul>
{#see_also|Compile Variables|@embedFile#}
{#header_close#}
{#header_open|@inlineCall#}
<pre>{#syntax#}@inlineCall(function: X, args: ...) Y{#endsyntax#}</pre>
<p>
@ -5788,7 +5821,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
{#header_open|@intToError#}
<pre>{#syntax#}@intToError(value: @IntType(false, @sizeOf(anyerror) * 8)) anyerror{#endsyntax#}</pre>
<p>
Converts from the integer representation of an error into the global error set type.
Converts from the integer representation of an error into {#link|The Global Error Set#} type.
</p>
<p>
It is generally recommended to avoid this
@ -5822,6 +5855,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
bit count for an integer type is {#syntax#}65535{#endsyntax#}.
</p>
{#header_close#}
{#header_open|@memberCount#}
<pre>{#syntax#}@memberCount(comptime T: type) comptime_int{#endsyntax#}</pre>
<p>
@ -5848,6 +5882,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
<pre>{#syntax#}@memberType(comptime T: type, comptime index: usize) type{#endsyntax#}</pre>
<p>Returns the field type of a struct or union.</p>
{#header_close#}
{#header_open|@memcpy#}
<pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize){#endsyntax#}</pre>
<p>
@ -5866,6 +5901,7 @@ fn add(a: i32, b: i32) i32 { return a + b; }
<pre>{#syntax#}const mem = @import("std").mem;
mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
{#header_close#}
{#header_open|@memset#}
<pre>{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize){#endsyntax#}</pre>
<p>
@ -5883,6 +5919,7 @@ mem.copy(u8, dest[0...byte_count], source[0...byte_count]);{#endsyntax#}</pre>
<pre>{#syntax#}const mem = @import("std").mem;
mem.set(u8, dest, c);{#endsyntax#}</pre>
{#header_close#}
{#header_open|@mod#}
<pre>{#syntax#}@mod(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
@ -5896,6 +5933,7 @@ mem.set(u8, dest, c);{#endsyntax#}</pre>
<p>For a function that returns an error code, see {#syntax#}@import("std").math.mod{#endsyntax#}.</p>
{#see_also|@rem#}
{#header_close#}
{#header_open|@mulWithOverflow#}
<pre>{#syntax#}@mulWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
<p>
@ -5904,6 +5942,7 @@ mem.set(u8, dest, c);{#endsyntax#}</pre>
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
</p>
{#header_close#}
{#header_open|@newStackCall#}
<pre>{#syntax#}@newStackCall(new_stack: []u8, function: var, args: ...) var{#endsyntax#}</pre>
<p>
@ -5940,6 +5979,7 @@ fn targetFunction(x: i32) usize {
}
{#code_end#}
{#header_close#}
{#header_open|@noInlineCall#}
<pre>{#syntax#}@noInlineCall(function: var, args: ...) var{#endsyntax#}</pre>
<p>
@ -5962,6 +6002,7 @@ fn add(a: i32, b: i32) i32 {
</p>
{#see_also|@inlineCall#}
{#header_close#}
{#header_open|@OpaqueType#}
<pre>{#syntax#}@OpaqueType() type{#endsyntax#}</pre>
<p>
@ -5985,6 +6026,7 @@ test "call foo" {
}
{#code_end#}
{#header_close#}
{#header_open|@panic#}
<pre>{#syntax#}@panic(message: []const u8) noreturn{#endsyntax#}</pre>
<p>
@ -6001,6 +6043,7 @@ test "call foo" {
</ul>
{#see_also|Root Source File#}
{#header_close#}
{#header_open|@popCount#}
<pre>{#syntax#}@popCount(integer: var) var{#endsyntax#}</pre>
<p>Counts the number of bits set in an integer.</p>
@ -6011,12 +6054,14 @@ test "call foo" {
</p>
{#see_also|@ctz|@clz#}
{#header_close#}
{#header_open|@ptrCast#}
<pre>{#syntax#}@ptrCast(comptime DestType: type, value: var) DestType{#endsyntax#}</pre>
<p>
Converts a pointer of one type to a pointer of another type.
</p>
{#header_close#}
{#header_open|@ptrToInt#}
<pre>{#syntax#}@ptrToInt(value: var) usize{#endsyntax#}</pre>
<p>
@ -6031,6 +6076,7 @@ test "call foo" {
<p>To convert the other way, use {#link|@intToPtr#}</p>
{#header_close#}
{#header_open|@rem#}
<pre>{#syntax#}@rem(numerator: T, denominator: T) T{#endsyntax#}</pre>
<p>
@ -6044,6 +6090,7 @@ test "call foo" {
<p>For a function that returns an error code, see {#syntax#}@import("std").math.rem{#endsyntax#}.</p>
{#see_also|@mod#}
{#header_close#}
{#header_open|@returnAddress#}
<pre>{#syntax#}@returnAddress(){#endsyntax#}</pre>
<p>
@ -6064,19 +6111,14 @@ test "call foo" {
Ensures that a function will have a stack alignment of at least {#syntax#}alignment{#endsyntax#} bytes.
</p>
{#header_close#}
{#header_open|@setCold#}
<pre>{#syntax#}@setCold(is_cold: bool){#endsyntax#}</pre>
<p>
Tells the optimizer that a function is rarely called.
</p>
{#header_close#}
{#header_open|@setRuntimeSafety#}
<pre>{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}</pre>
<p>
Sets whether runtime safety checks are on for the scope that contains the function call.
</p>
{#header_close#}
{#header_open|@setEvalBranchQuota#}
<pre>{#syntax#}@setEvalBranchQuota(new_quota: usize){#endsyntax#}</pre>
<p>
@ -6111,6 +6153,7 @@ test "foo" {
{#see_also|comptime#}
{#header_close#}
{#header_open|@setFloatMode#}
<pre>{#syntax#}@setFloatMode(mode: @import("builtin").FloatMode){#endsyntax#}</pre>
<p>
@ -6145,6 +6188,7 @@ pub const FloatMode = enum {
</p>
{#see_also|Floating Point Operations#}
{#header_close#}
{#header_open|@setGlobalLinkage#}
<pre>{#syntax#}@setGlobalLinkage(global_variable_name, comptime linkage: GlobalLinkage){#endsyntax#}</pre>
<p>
@ -6152,6 +6196,15 @@ pub const FloatMode = enum {
</p>
{#see_also|Compile Variables#}
{#header_close#}
{#header_open|@setRuntimeSafety#}
<pre>{#syntax#}@setRuntimeSafety(safety_on: bool){#endsyntax#}</pre>
<p>
Sets whether runtime safety checks are on for the scope that contains the function call.
</p>
{#header_close#}
{#header_open|@shlExact#}
<pre>{#syntax#}@shlExact(value: T, shift_amt: Log2T) T{#endsyntax#}</pre>
<p>
@ -6164,6 +6217,7 @@ pub const FloatMode = enum {
</p>
{#see_also|@shrExact|@shlWithOverflow#}
{#header_close#}
{#header_open|@shlWithOverflow#}
<pre>{#syntax#}@shlWithOverflow(comptime T: type, a: T, shift_amt: Log2T, result: *T) bool{#endsyntax#}</pre>
<p>
@ -6177,6 +6231,7 @@ pub const FloatMode = enum {
</p>
{#see_also|@shlExact|@shrExact#}
{#header_close#}
{#header_open|@shrExact#}
<pre>{#syntax#}@shrExact(value: T, shift_amt: Log2T) T{#endsyntax#}</pre>
<p>
@ -6218,6 +6273,7 @@ pub const FloatMode = enum {
This is a low-level intrinsic. Most code can use {#syntax#}std.math.sqrt{#endsyntax#} instead.
</p>
{#header_close#}
{#header_open|@subWithOverflow#}
<pre>{#syntax#}@subWithOverflow(comptime T: type, a: T, b: T, result: *T) bool{#endsyntax#}</pre>
<p>
@ -6226,12 +6282,14 @@ pub const FloatMode = enum {
If no overflow or underflow occurs, returns {#syntax#}false{#endsyntax#}.
</p>
{#header_close#}
{#header_open|@tagName#}
<pre>{#syntax#}@tagName(value: var) []const u8{#endsyntax#}</pre>
<p>
Converts an enum value or union value to a slice of bytes representing the name.
</p>
{#header_close#}
{#header_open|@TagType#}
<pre>{#syntax#}@TagType(T: type) type{#endsyntax#}</pre>
<p>
@ -6241,6 +6299,7 @@ pub const FloatMode = enum {
For a union, returns the enum type that is used to store the tag value.
</p>
{#header_close#}
{#header_open|@This#}
<pre>{#syntax#}@This() type{#endsyntax#}</pre>
<p>
@ -6276,6 +6335,7 @@ fn List(comptime T: type) type {
<a href="https://github.com/ziglang/zig/issues/1047">#1047</a> for details.
</p>
{#header_close#}
{#header_open|@truncate#}
<pre>{#syntax#}@truncate(comptime T: type, integer) T{#endsyntax#}</pre>
<p>
@ -6300,6 +6360,7 @@ const b: u8 = @truncate(u8, a);
</p>
{#header_close#}
{#header_open|@typeId#}
<pre>{#syntax#}@typeId(comptime T: type) @import("builtin").TypeId{#endsyntax#}</pre>
<p>
@ -6334,6 +6395,7 @@ pub const TypeId = enum {
};
{#code_end#}
{#header_close#}
{#header_open|@typeInfo#}
<pre>{#syntax#}@typeInfo(comptime T: type) @import("builtin").TypeInfo{#endsyntax#}</pre>
<p>
@ -6516,6 +6578,7 @@ pub const TypeInfo = union(TypeId) {
};
{#code_end#}
{#header_close#}
{#header_open|@typeName#}
<pre>{#syntax#}@typeName(T: type) []u8{#endsyntax#}</pre>
<p>
@ -6523,6 +6586,7 @@ pub const TypeInfo = union(TypeId) {
</p>
{#header_close#}
{#header_open|@typeOf#}
<pre>{#syntax#}@typeOf(expression) type{#endsyntax#}</pre>
<p>
@ -6532,6 +6596,7 @@ pub const TypeInfo = union(TypeId) {
{#header_close#}
{#header_close#}
{#header_open|Build Mode#}
<p>
Zig has four build modes:
@ -6659,7 +6724,7 @@ fn foo(x: []const u8) u8 {
{#header_close#}
{#header_open|Cast Negative Number to Unsigned Integer#}
<p>At compile-time:</p>
{#code_begin|test_err|attempt to cast negative value to unsigned integer#}
{#code_begin|test_err|cannot cast negative value -1 to unsigned integer type 'u32'#}
comptime {
const value: i32 = -1;
const unsigned = @intCast(u32, value);
@ -6681,7 +6746,7 @@ pub fn main() void {
{#header_close#}
{#header_open|Cast Truncates Data#}
<p>At compile-time:</p>
{#code_begin|test_err|cast from 'u16' to 'u8' truncates bits#}
{#code_begin|test_err|integer value 300 cannot be implicitly casted to type 'u8'#}
comptime {
const spartan_count: u16 = 300;
const byte = @intCast(u8, spartan_count);
@ -7830,11 +7895,11 @@ TypeExpr &lt;- PrefixTypeOp* ErrorUnionExpr
ErrorUnionExpr &lt;- SuffixExpr (EXCLAMATIONMARK TypeExpr)?
SuffixExpr
&lt;- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArgumnets
/ PrimaryTypeExpr (SuffixOp / FnCallArgumnets)*
&lt;- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments
/ PrimaryTypeExpr (SuffixOp / FnCallArguments)*
PrimaryTypeExpr
&lt;- BUILTININDENTIFIER FnCallArgumnets
&lt;- BUILTINIDENTIFIER FnCallArguments
/ CHAR_LITERAL
/ ContainerDecl
/ ErrorSetDecl
@ -7884,11 +7949,11 @@ AsmOutput &lt;- COLON AsmOutputList AsmInput?
AsmOutputItem &lt;- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN (MINUSRARROW TypeExpr / IDENTIFIER) RPAREN
AsmInput &lt;- COLON AsmInputList AsmCloppers?
AsmInput &lt;- COLON AsmInputList AsmClobbers?
AsmInputItem &lt;- LBRACKET IDENTIFIER RBRACKET STRINGLITERAL LPAREN Expr RPAREN
AsmCloppers &lt;- COLON StringList
AsmClobbers &lt;- COLON StringList
# *** Helper grammar ***
BreakLabel &lt;- COLON IDENTIFIER
@ -8013,7 +8078,7 @@ SuffixOp
AsyncPrefix &lt;- KEYWORD_async (LARROW PrefixExpr RARROW)?
FnCallArgumnets &lt;- LPAREN ExprList RPAREN
FnCallArguments &lt;- LPAREN ExprList RPAREN
# Ptr specific
ArrayTypeStart &lt;- LBRACKET Expr? RBRACKET
@ -8090,7 +8155,7 @@ STRINGLITERAL
IDENTIFIER
&lt;- !keyword ("c" !["\\] / [A-Zabd-z_]) [A-Za-z0-9_]* skip
/ "@\"" string_char* "\"" skip
BUILTININDENTIFIER &lt;- "@"[A-Za-z_][A-Za-z0-9_]* skip
BUILTINIDENTIFIER &lt;- "@"[A-Za-z_][A-Za-z0-9_]* skip
AMPERSAND &lt;- '&' ![=] skip
@ -8109,9 +8174,9 @@ DOT2 &lt;- '..' ![.] skip
DOT3 &lt;- '...' skip
DOTASTERISK &lt;- '.*' skip
DOTQUESTIONMARK &lt;- '.?' skip
EQUAL &lt;- '=' ![>=] skip
EQUAL &lt;- '=' ![&gt;=] skip
EQUALEQUAL &lt;- '==' skip
EQUALRARROW &lt;- '=>' skip
EQUALRARROW &lt;- '=&gt;' skip
EXCLAMATIONMARK &lt;- '!' ![=] skip
EXCLAMATIONMARKEQUAL &lt;- '!=' skip
LARROW &lt;- '&lt;' ![&lt;=] skip
@ -8121,11 +8186,11 @@ LARROWEQUAL &lt;- '&lt;=' skip
LBRACE &lt;- '{' skip
LBRACKET &lt;- '[' skip
LPAREN &lt;- '(' skip
MINUS &lt;- '-' ![%=>] skip
MINUS &lt;- '-' ![%=&gt;] skip
MINUSEQUAL &lt;- '-=' skip
MINUSPERCENT &lt;- '-%' ![=] skip
MINUSPERCENTEQUAL &lt;- '-%=' skip
MINUSRARROW &lt;- '->' skip
MINUSRARROW &lt;- '-&gt;' skip
PERCENT &lt;- '%' ![=] skip
PERCENTEQUAL &lt;- '%=' skip
PIPE &lt;- '|' ![|=] skip
@ -8137,10 +8202,10 @@ PLUSEQUAL &lt;- '+=' skip
PLUSPERCENT &lt;- '+%' ![=] skip
PLUSPERCENTEQUAL &lt;- '+%=' skip
QUESTIONMARK &lt;- '?' skip
RARROW &lt;- '>' ![>=] skip
RARROW2 &lt;- '>>' ![=] skip
RARROW2EQUAL &lt;- '>>=' skip
RARROWEQUAL &lt;- '>=' skip
RARROW &lt;- '&gt;' ![&gt;=] skip
RARROW2 &lt;- '&gt;&gt;' ![=] skip
RARROW2EQUAL &lt;- '&gt;&gt;=' skip
RARROWEQUAL &lt;- '&gt;=' skip
RBRACE &lt;- '}' skip
RBRACKET &lt;- ']' skip
RPAREN &lt;- ')' skip

View File

@ -15,7 +15,7 @@ pub fn main() !void {
std.debug.warn("unable to seed random number generator: {}", err);
return err;
};
const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
const seed = std.mem.readIntNative(u64, &seed_bytes);
var prng = std.rand.DefaultPrng.init(seed);
const answer = prng.random.range(u8, 0, 100) + 1;
@ -24,15 +24,15 @@ pub fn main() !void {
try stdout.print("\nGuess a number between 1 and 100: ");
var line_buf: [20]u8 = undefined;
const line_len = io.readLine(line_buf[0..]) catch |err| switch (err) {
error.InputTooLong => {
const line = io.readLineSlice(line_buf[0..]) catch |err| switch (err) {
error.OutOfMemory => {
try stdout.print("Input too long.\n");
continue;
},
error.EndOfFile, error.StdInUnavailable => return err,
else => return err,
};
const guess = fmt.parseUnsigned(u8, line_buf[0..line_len], 10) catch {
const guess = fmt.parseUnsigned(u8, line, 10) catch {
try stdout.print("Invalid number.\n");
continue;
};

View File

@ -2,7 +2,7 @@ const std = @import("std");
pub fn main() !void {
// If this program is run without stdout attached, exit with an error.
var stdout_file = try std.io.getStdOut();
const stdout_file = try std.io.getStdOut();
// If this program encounters pipe failure when printing to stdout, exit
// with an error.
try stdout_file.write("Hello, world!\n");

View File

@ -55,7 +55,7 @@ pub const ZigCompiler = struct {
var seed_bytes: [@sizeOf(u64)]u8 = undefined;
try std.os.getRandomBytes(seed_bytes[0..]);
const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
const seed = mem.readIntNative(u64, &seed_bytes);
return ZigCompiler{
.loop = loop,
@ -300,6 +300,7 @@ pub const Compilation = struct {
UserResourceLimitReached,
InvalidUtf8,
BadPathName,
DeviceBusy,
};
pub const Event = union(enum) {

View File

@ -172,7 +172,7 @@ pub const LibCInstallation = struct {
try group.call(findNativeStaticLibDir, self, loop);
try group.call(findNativeDynamicLinker, self, loop);
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
},
else => @compileError("unimplemented: find libc for this OS"),

View File

@ -311,160 +311,164 @@ pub const Target = union(enum) {
pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
const env = self.getEnviron();
const arch = self.getArch();
switch (env) {
builtin.Environ.android => {
if (self.is64bit()) {
return "/system/bin/linker64";
} else {
return "/system/bin/linker";
const os = self.getOs();
switch (os) {
builtin.Os.freebsd => {
return "/libexec/ld-elf.so.1";
},
builtin.Os.linux => {
switch (env) {
builtin.Environ.android => {
if (self.is64bit()) {
return "/system/bin/linker64";
} else {
return "/system/bin/linker";
}
},
builtin.Environ.gnux32 => {
if (arch == builtin.Arch.x86_64) {
return "/libx32/ld-linux-x32.so.2";
}
},
builtin.Environ.musl,
builtin.Environ.musleabi,
builtin.Environ.musleabihf,
=> {
if (arch == builtin.Arch.x86_64) {
return "/lib/ld-musl-x86_64.so.1";
}
},
else => {},
}
switch (arch) {
builtin.Arch.i386,
builtin.Arch.sparc,
builtin.Arch.sparcel,
=> return "/lib/ld-linux.so.2",
builtin.Arch.aarch64v8_5a,
builtin.Arch.aarch64v8_4a,
builtin.Arch.aarch64v8_3a,
builtin.Arch.aarch64v8_2a,
builtin.Arch.aarch64v8_1a,
builtin.Arch.aarch64v8,
builtin.Arch.aarch64v8r,
builtin.Arch.aarch64v8m_baseline,
builtin.Arch.aarch64v8m_mainline,
=> return "/lib/ld-linux-aarch64.so.1",
builtin.Arch.aarch64_bev8_5a,
builtin.Arch.aarch64_bev8_4a,
builtin.Arch.aarch64_bev8_3a,
builtin.Arch.aarch64_bev8_2a,
builtin.Arch.aarch64_bev8_1a,
builtin.Arch.aarch64_bev8,
builtin.Arch.aarch64_bev8r,
builtin.Arch.aarch64_bev8m_baseline,
builtin.Arch.aarch64_bev8m_mainline,
=> return "/lib/ld-linux-aarch64_be.so.1",
builtin.Arch.armv8_5a,
builtin.Arch.armv8_4a,
builtin.Arch.armv8_3a,
builtin.Arch.armv8_2a,
builtin.Arch.armv8_1a,
builtin.Arch.armv8,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
builtin.Arch.thumb,
builtin.Arch.armebv8_5a,
builtin.Arch.armebv8_4a,
builtin.Arch.armebv8_3a,
builtin.Arch.armebv8_2a,
builtin.Arch.armebv8_1a,
builtin.Arch.armebv8,
builtin.Arch.armebv8r,
builtin.Arch.armebv8m_baseline,
builtin.Arch.armebv8m_mainline,
builtin.Arch.armebv7,
builtin.Arch.armebv7em,
builtin.Arch.armebv7m,
builtin.Arch.armebv7s,
builtin.Arch.armebv7k,
builtin.Arch.armebv7ve,
builtin.Arch.armebv6,
builtin.Arch.armebv6m,
builtin.Arch.armebv6k,
builtin.Arch.armebv6t2,
builtin.Arch.armebv5,
builtin.Arch.armebv5te,
builtin.Arch.armebv4t,
builtin.Arch.thumbeb,
=> return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
builtin.Arch.mipsr6,
builtin.Arch.mipselr6,
builtin.Arch.mips64r6,
builtin.Arch.mips64elr6,
=> return null,
builtin.Arch.powerpc => return "/lib/ld.so.1",
builtin.Arch.powerpc64 => return "/lib64/ld64.so.2",
builtin.Arch.powerpc64le => return "/lib64/ld64.so.2",
builtin.Arch.s390x => return "/lib64/ld64.so.1",
builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2",
builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2",
builtin.Arch.arc,
builtin.Arch.avr,
builtin.Arch.bpfel,
builtin.Arch.bpfeb,
builtin.Arch.hexagon,
builtin.Arch.msp430,
builtin.Arch.nios2,
builtin.Arch.r600,
builtin.Arch.amdgcn,
builtin.Arch.riscv32,
builtin.Arch.riscv64,
builtin.Arch.tce,
builtin.Arch.tcele,
builtin.Arch.xcore,
builtin.Arch.nvptx,
builtin.Arch.nvptx64,
builtin.Arch.le32,
builtin.Arch.le64,
builtin.Arch.amdil,
builtin.Arch.amdil64,
builtin.Arch.hsail,
builtin.Arch.hsail64,
builtin.Arch.spir,
builtin.Arch.spir64,
builtin.Arch.kalimbav3,
builtin.Arch.kalimbav4,
builtin.Arch.kalimbav5,
builtin.Arch.shave,
builtin.Arch.lanai,
builtin.Arch.wasm32,
builtin.Arch.wasm64,
builtin.Arch.renderscript32,
builtin.Arch.renderscript64,
=> return null,
}
},
builtin.Environ.gnux32 => {
if (arch == builtin.Arch.x86_64) {
return "/libx32/ld-linux-x32.so.2";
}
},
builtin.Environ.musl,
builtin.Environ.musleabi,
builtin.Environ.musleabihf,
=> {
if (arch == builtin.Arch.x86_64) {
return "/lib/ld-musl-x86_64.so.1";
}
},
else => {},
}
switch (arch) {
builtin.Arch.i386,
builtin.Arch.sparc,
builtin.Arch.sparcel,
=> return "/lib/ld-linux.so.2",
builtin.Arch.aarch64v8_5a,
builtin.Arch.aarch64v8_4a,
builtin.Arch.aarch64v8_3a,
builtin.Arch.aarch64v8_2a,
builtin.Arch.aarch64v8_1a,
builtin.Arch.aarch64v8,
builtin.Arch.aarch64v8r,
builtin.Arch.aarch64v8m_baseline,
builtin.Arch.aarch64v8m_mainline,
=> return "/lib/ld-linux-aarch64.so.1",
builtin.Arch.aarch64_bev8_5a,
builtin.Arch.aarch64_bev8_4a,
builtin.Arch.aarch64_bev8_3a,
builtin.Arch.aarch64_bev8_2a,
builtin.Arch.aarch64_bev8_1a,
builtin.Arch.aarch64_bev8,
builtin.Arch.aarch64_bev8r,
builtin.Arch.aarch64_bev8m_baseline,
builtin.Arch.aarch64_bev8m_mainline,
=> return "/lib/ld-linux-aarch64_be.so.1",
builtin.Arch.armv8_5a,
builtin.Arch.armv8_4a,
builtin.Arch.armv8_3a,
builtin.Arch.armv8_2a,
builtin.Arch.armv8_1a,
builtin.Arch.armv8,
builtin.Arch.armv8r,
builtin.Arch.armv8m_baseline,
builtin.Arch.armv8m_mainline,
builtin.Arch.armv7,
builtin.Arch.armv7em,
builtin.Arch.armv7m,
builtin.Arch.armv7s,
builtin.Arch.armv7k,
builtin.Arch.armv7ve,
builtin.Arch.armv6,
builtin.Arch.armv6m,
builtin.Arch.armv6k,
builtin.Arch.armv6t2,
builtin.Arch.armv5,
builtin.Arch.armv5te,
builtin.Arch.armv4t,
builtin.Arch.thumb,
=> return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
builtin.Arch.armebv8_5a,
builtin.Arch.armebv8_4a,
builtin.Arch.armebv8_3a,
builtin.Arch.armebv8_2a,
builtin.Arch.armebv8_1a,
builtin.Arch.armebv8,
builtin.Arch.armebv8r,
builtin.Arch.armebv8m_baseline,
builtin.Arch.armebv8m_mainline,
builtin.Arch.armebv7,
builtin.Arch.armebv7em,
builtin.Arch.armebv7m,
builtin.Arch.armebv7s,
builtin.Arch.armebv7k,
builtin.Arch.armebv7ve,
builtin.Arch.armebv6,
builtin.Arch.armebv6m,
builtin.Arch.armebv6k,
builtin.Arch.armebv6t2,
builtin.Arch.armebv5,
builtin.Arch.armebv5te,
builtin.Arch.armebv4t,
builtin.Arch.thumbeb,
=> return switch (self.getFloatAbi()) {
FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
else => return "/lib/ld-linux.so.3",
},
builtin.Arch.mipsr6,
builtin.Arch.mipselr6,
builtin.Arch.mips64r6,
builtin.Arch.mips64elr6,
=> return null,
builtin.Arch.powerpc => return "/lib/ld.so.1",
builtin.Arch.powerpc64 => return "/lib64/ld64.so.2",
builtin.Arch.powerpc64le => return "/lib64/ld64.so.2",
builtin.Arch.s390x => return "/lib64/ld64.so.1",
builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2",
builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2",
builtin.Arch.arc,
builtin.Arch.avr,
builtin.Arch.bpfel,
builtin.Arch.bpfeb,
builtin.Arch.hexagon,
builtin.Arch.msp430,
builtin.Arch.nios2,
builtin.Arch.r600,
builtin.Arch.amdgcn,
builtin.Arch.riscv32,
builtin.Arch.riscv64,
builtin.Arch.tce,
builtin.Arch.tcele,
builtin.Arch.xcore,
builtin.Arch.nvptx,
builtin.Arch.nvptx64,
builtin.Arch.le32,
builtin.Arch.le64,
builtin.Arch.amdil,
builtin.Arch.amdil64,
builtin.Arch.hsail,
builtin.Arch.hsail64,
builtin.Arch.spir,
builtin.Arch.spir64,
builtin.Arch.kalimbav3,
builtin.Arch.kalimbav4,
builtin.Arch.kalimbav5,
builtin.Arch.shave,
builtin.Arch.lanai,
builtin.Arch.wasm32,
builtin.Arch.wasm64,
builtin.Arch.renderscript32,
builtin.Arch.renderscript64,
=> return null,
else => return null,
}
}
@ -513,6 +517,7 @@ pub const Target = union(enum) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
builtin.Os.openbsd,
builtin.Os.zen,
=> switch (id) {
@ -547,7 +552,6 @@ pub const Target = union(enum) {
builtin.Os.ananas,
builtin.Os.cloudabi,
builtin.Os.dragonfly,
builtin.Os.freebsd,
builtin.Os.fuchsia,
builtin.Os.ios,
builtin.Os.kfreebsd,

View File

@ -605,7 +605,6 @@ enum CastOp {
CastOpFloatToInt,
CastOpBoolToInt,
CastOpResizeSlice,
CastOpBytesToSlice,
CastOpNumLitToConcrete,
CastOpErrSet,
CastOpBitCast,
@ -1415,6 +1414,7 @@ enum BuiltinFnId {
BuiltinFnIdErrorReturnTrace,
BuiltinFnIdAtomicRmw,
BuiltinFnIdAtomicLoad,
BuiltinFnIdBswap,
};
struct BuiltinFnEntry {
@ -1487,6 +1487,7 @@ enum ZigLLVMFnId {
ZigLLVMFnIdFloor,
ZigLLVMFnIdCeil,
ZigLLVMFnIdSqrt,
ZigLLVMFnIdBswap,
};
enum AddSubMul {
@ -1516,6 +1517,9 @@ struct ZigLLVMFnKey {
uint32_t bit_count;
bool is_signed;
} overflow_arithmetic;
struct {
uint32_t bit_count;
} bswap;
} data;
};
@ -2158,6 +2162,7 @@ enum IrInstructionId {
IrInstructionIdMergeErrRetTraces,
IrInstructionIdMarkErrRetTracePtr,
IrInstructionIdSqrt,
IrInstructionIdBswap,
IrInstructionIdErrSetCast,
IrInstructionIdToBytes,
IrInstructionIdFromBytes,
@ -3251,6 +3256,13 @@ struct IrInstructionCheckRuntimeScope {
IrInstruction *is_comptime;
};
struct IrInstructionBswap {
IrInstruction base;
IrInstruction *type;
IrInstruction *op;
};
static const size_t slice_ptr_index = 0;
static const size_t slice_len_index = 1;

View File

@ -401,7 +401,8 @@ ZigType *get_promise_type(CodeGen *g, ZigType *result_type) {
}
ZigType *get_pointer_to_type_extra(CodeGen *g, ZigType *child_type, bool is_const,
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment, uint32_t bit_offset_in_host, uint32_t host_int_bytes)
bool is_volatile, PtrLen ptr_len, uint32_t byte_alignment,
uint32_t bit_offset_in_host, uint32_t host_int_bytes)
{
assert(!type_is_invalid(child_type));
assert(ptr_len == PtrLenSingle || child_type->id != ZigTypeIdOpaque);
@ -1059,7 +1060,7 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id) {
}
zig_panic("TODO implement C ABI for x86_64 return types. type '%s'\nSee https://github.com/ziglang/zig/issues/1481",
buf_ptr(&fn_type_id->return_type->name));
} else if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb) {
} else if (target_is_arm(&g->zig_target)) {
return type_size(g, fn_type_id->return_type) > 16;
}
zig_panic("TODO implement C ABI for this architecture. See https://github.com/ziglang/zig/issues/1481");
@ -1619,13 +1620,16 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (type_requires_comptime(type_entry)) {
add_node_error(g, param_node->data.param_decl.type,
buf_sprintf("parameter of type '%s' must be declared comptime",
buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
switch (type_requires_comptime(g, type_entry)) {
case ReqCompTimeNo:
break;
case ReqCompTimeYes:
add_node_error(g, param_node->data.param_decl.type,
buf_sprintf("parameter of type '%s' must be declared comptime",
buf_ptr(&type_entry->name)));
return g->builtin_types.entry_invalid;
case ReqCompTimeInvalid:
return g->builtin_types.entry_invalid;
}
break;
}
@ -1711,10 +1715,13 @@ static ZigType *analyze_fn_type(CodeGen *g, AstNode *proto_node, Scope *child_sc
case ZigTypeIdUnion:
case ZigTypeIdFn:
case ZigTypeIdPromise:
if ((err = type_resolve(g, fn_type_id.return_type, ResolveStatusZeroBitsKnown)))
return g->builtin_types.entry_invalid;
if (type_requires_comptime(fn_type_id.return_type)) {
return get_generic_fn_type(g, &fn_type_id);
switch (type_requires_comptime(g, fn_type_id.return_type)) {
case ReqCompTimeInvalid:
return g->builtin_types.entry_invalid;
case ReqCompTimeYes:
return get_generic_fn_type(g, &fn_type_id);
case ReqCompTimeNo:
break;
}
break;
}
@ -2560,8 +2567,6 @@ static Error resolve_enum_zero_bits(CodeGen *g, ZigType *enum_type) {
static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
assert(struct_type->id == ZigTypeIdStruct);
Error err;
if (struct_type->data.structure.resolve_status == ResolveStatusInvalid)
return ErrorSemanticAnalyzeFail;
if (struct_type->data.structure.resolve_status >= ResolveStatusZeroBitsKnown)
@ -2619,13 +2624,15 @@ static Error resolve_struct_zero_bits(CodeGen *g, ZigType *struct_type) {
buf_sprintf("enums, not structs, support field assignment"));
}
if ((err = type_resolve(g, field_type, ResolveStatusZeroBitsKnown))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
}
if (type_requires_comptime(field_type)) {
struct_type->data.structure.requires_comptime = true;
switch (type_requires_comptime(g, field_type)) {
case ReqCompTimeYes:
struct_type->data.structure.requires_comptime = true;
break;
case ReqCompTimeInvalid:
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
continue;
case ReqCompTimeNo:
break;
}
if (!type_has_bits(field_type))
@ -2674,39 +2681,50 @@ static Error resolve_struct_alignment(CodeGen *g, ZigType *struct_type) {
assert(decl_node->type == NodeTypeContainerDecl);
assert(struct_type->di_type);
size_t field_count = struct_type->data.structure.src_field_count;
if (struct_type->data.structure.layout == ContainerLayoutPacked) {
struct_type->data.structure.abi_alignment = 1;
}
size_t field_count = struct_type->data.structure.src_field_count;
for (size_t i = 0; i < field_count; i += 1) {
TypeStructField *field = &struct_type->data.structure.fields[i];
// If this assertion trips, look up the call stack. Probably something is
// calling type_resolve with ResolveStatusAlignmentKnown when it should only
// be resolving ResolveStatusZeroBitsKnown
assert(field->type_entry != nullptr);
if (type_is_invalid(field->type_entry)) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
for (size_t i = 0; i < field_count; i += 1) {
TypeStructField *field = &struct_type->data.structure.fields[i];
if (field->type_entry != nullptr && type_is_invalid(field->type_entry)) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
}
} else for (size_t i = 0; i < field_count; i += 1) {
TypeStructField *field = &struct_type->data.structure.fields[i];
uint32_t this_field_align;
if (!type_has_bits(field->type_entry))
continue;
// TODO If we have no type_entry for the field, we've already failed to
// compile the program correctly. This stage1 compiler needs a deeper
// reworking to make this correct, or we can ignore the problem
// and make sure it is fixed in stage2. This workaround is for when
// there is a false positive of a dependency loop, of alignment depending
// on itself. When this false positive happens we assume a pointer-aligned
// field, which is usually fine but could be incorrectly over-aligned or
// even under-aligned. See https://github.com/ziglang/zig/issues/1512
if (field->type_entry == nullptr) {
this_field_align = LLVMABIAlignmentOfType(g->target_data_ref, LLVMPointerType(LLVMInt8Type(), 0));
} else {
if (type_is_invalid(field->type_entry)) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
if (!type_has_bits(field->type_entry))
continue;
// alignment of structs is the alignment of the most-aligned field
if (struct_type->data.structure.layout != ContainerLayoutPacked) {
if ((err = type_resolve(g, field->type_entry, ResolveStatusAlignmentKnown))) {
struct_type->data.structure.resolve_status = ResolveStatusInvalid;
break;
}
uint32_t this_field_align = get_abi_alignment(g, field->type_entry);
this_field_align = get_abi_alignment(g, field->type_entry);
assert(this_field_align != 0);
if (this_field_align > struct_type->data.structure.abi_alignment) {
struct_type->data.structure.abi_alignment = this_field_align;
}
}
// alignment of structs is the alignment of the most-aligned field
if (this_field_align > struct_type->data.structure.abi_alignment) {
struct_type->data.structure.abi_alignment = this_field_align;
}
}
@ -2890,11 +2908,17 @@ static Error resolve_union_zero_bits(CodeGen *g, ZigType *union_type) {
}
union_field->type_entry = field_type;
if (type_requires_comptime(field_type)) {
union_type->data.unionation.requires_comptime = true;
switch (type_requires_comptime(g, field_type)) {
case ReqCompTimeInvalid:
union_type->data.unionation.is_invalid = true;
continue;
case ReqCompTimeYes:
union_type->data.unionation.requires_comptime = true;
break;
case ReqCompTimeNo:
break;
}
if (field_node->data.struct_field.value != nullptr && !decl_node->data.container_decl.auto_enum) {
ErrorMsg *msg = add_node_error(g, field_node->data.struct_field.value,
buf_sprintf("non-enum union field assignment"));
@ -4579,7 +4603,10 @@ void find_libc_include_path(CodeGen *g) {
fprintf(stderr, "Unable to determine libc include path. --libc-include-dir");
exit(1);
}
} else if (g->zig_target.os == OsLinux || g->zig_target.os == OsMacOSX) {
} else if (g->zig_target.os == OsLinux ||
g->zig_target.os == OsMacOSX ||
g->zig_target.os == OsFreeBSD)
{
g->libc_include_dir = get_posix_libc_include_path();
} else {
fprintf(stderr, "Unable to determine libc include path.\n"
@ -4627,6 +4654,8 @@ void find_libc_lib_path(CodeGen *g) {
} else if (g->zig_target.os == OsLinux) {
g->libc_lib_dir = get_linux_libc_lib_path("crt1.o");
} else if (g->zig_target.os == OsFreeBSD) {
g->libc_lib_dir = buf_create_from_str("/usr/lib");
} else {
zig_panic("Unable to determine libc lib path.");
}
@ -4639,6 +4668,8 @@ void find_libc_lib_path(CodeGen *g) {
return;
} else if (g->zig_target.os == OsLinux) {
g->libc_static_lib_dir = get_linux_libc_lib_path("crtbegin.o");
} else if (g->zig_target.os == OsFreeBSD) {
g->libc_static_lib_dir = buf_create_from_str("/usr/lib");
} else {
zig_panic("Unable to determine libc static lib path.");
}
@ -5089,7 +5120,10 @@ bool type_has_bits(ZigType *type_entry) {
return !type_entry->zero_bits;
}
bool type_requires_comptime(ZigType *type_entry) {
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry) {
Error err;
if ((err = type_resolve(g, type_entry, ResolveStatusZeroBitsKnown)))
return ReqCompTimeInvalid;
switch (type_entry->id) {
case ZigTypeIdInvalid:
case ZigTypeIdOpaque:
@ -5102,27 +5136,25 @@ bool type_requires_comptime(ZigType *type_entry) {
case ZigTypeIdNamespace:
case ZigTypeIdBoundFn:
case ZigTypeIdArgTuple:
return true;
return ReqCompTimeYes;
case ZigTypeIdArray:
return type_requires_comptime(type_entry->data.array.child_type);
return type_requires_comptime(g, type_entry->data.array.child_type);
case ZigTypeIdStruct:
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return type_entry->data.structure.requires_comptime;
return type_entry->data.structure.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo;
case ZigTypeIdUnion:
assert(type_is_resolved(type_entry, ResolveStatusZeroBitsKnown));
return type_entry->data.unionation.requires_comptime;
return type_entry->data.unionation.requires_comptime ? ReqCompTimeYes : ReqCompTimeNo;
case ZigTypeIdOptional:
return type_requires_comptime(type_entry->data.maybe.child_type);
return type_requires_comptime(g, type_entry->data.maybe.child_type);
case ZigTypeIdErrorUnion:
return type_requires_comptime(type_entry->data.error_union.payload_type);
return type_requires_comptime(g, type_entry->data.error_union.payload_type);
case ZigTypeIdPointer:
if (type_entry->data.pointer.child_type->id == ZigTypeIdOpaque) {
return false;
return ReqCompTimeNo;
} else {
return type_requires_comptime(type_entry->data.pointer.child_type);
return type_requires_comptime(g, type_entry->data.pointer.child_type);
}
case ZigTypeIdFn:
return type_entry->data.fn.is_generic;
return type_entry->data.fn.is_generic ? ReqCompTimeYes : ReqCompTimeNo;
case ZigTypeIdEnum:
case ZigTypeIdErrorSet:
case ZigTypeIdBool:
@ -5131,7 +5163,7 @@ bool type_requires_comptime(ZigType *type_entry) {
case ZigTypeIdVoid:
case ZigTypeIdUnreachable:
case ZigTypeIdPromise:
return false;
return ReqCompTimeNo;
}
zig_unreachable();
}
@ -6090,6 +6122,8 @@ uint32_t zig_llvm_fn_key_hash(ZigLLVMFnKey x) {
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)1953839089;
case ZigLLVMFnIdSqrt:
return (uint32_t)(x.data.floating.bit_count) * (uint32_t)2225366385;
case ZigLLVMFnIdBswap:
return (uint32_t)(x.data.bswap.bit_count) * (uint32_t)3661994335;
case ZigLLVMFnIdOverflowArithmetic:
return ((uint32_t)(x.data.overflow_arithmetic.bit_count) * 87135777) +
((uint32_t)(x.data.overflow_arithmetic.add_sub_mul) * 31640542) +
@ -6108,6 +6142,8 @@ bool zig_llvm_fn_key_eql(ZigLLVMFnKey a, ZigLLVMFnKey b) {
return a.data.clz.bit_count == b.data.clz.bit_count;
case ZigLLVMFnIdPopCount:
return a.data.pop_count.bit_count == b.data.pop_count.bit_count;
case ZigLLVMFnIdBswap:
return a.data.bswap.bit_count == b.data.bswap.bit_count;
case ZigLLVMFnIdFloor:
case ZigLLVMFnIdCeil:
case ZigLLVMFnIdSqrt:

View File

@ -87,7 +87,6 @@ ZigFn *create_fn(CodeGen *g, AstNode *proto_node);
ZigFn *create_fn_raw(CodeGen *g, FnInline inline_value);
void init_fn_type_id(FnTypeId *fn_type_id, AstNode *proto_node, size_t param_count_alloc);
AstNode *get_param_decl_node(ZigFn *fn_entry, size_t index);
bool type_requires_comptime(ZigType *type_entry);
Error ATTRIBUTE_MUST_USE ensure_complete_type(CodeGen *g, ZigType *type_entry);
Error ATTRIBUTE_MUST_USE type_resolve(CodeGen *g, ZigType *type_entry, ResolveStatus status);
void complete_enum(CodeGen *g, ZigType *enum_type);
@ -216,4 +215,11 @@ bool want_first_arg_sret(CodeGen *g, FnTypeId *fn_type_id);
uint32_t get_host_int_bytes(CodeGen *g, ZigType *struct_type, TypeStructField *field);
enum ReqCompTime {
ReqCompTimeInvalid,
ReqCompTimeNo,
ReqCompTimeYes,
};
ReqCompTime type_requires_comptime(CodeGen *g, ZigType *type_entry);
#endif

View File

@ -181,5 +181,15 @@ static inline Slice<uint8_t> buf_to_slice(Buf *buf) {
return Slice<uint8_t>{reinterpret_cast<uint8_t*>(buf_ptr(buf)), buf_len(buf)};
}
static inline void buf_replace(Buf* buf, char from, char to) {
const size_t count = buf_len(buf);
char* ptr = buf_ptr(buf);
for (size_t i = 0; i < count; ++i) {
char& l = ptr[i];
if (l == from)
l = to;
}
}
#endif

View File

@ -352,8 +352,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
// if the mtime matches we can trust the digest
OsFile this_file;
if ((err = os_file_open_r(chf->path, &this_file))) {
fprintf(stderr, "Unable to open %s\n: %s", buf_ptr(chf->path), err_str(err));
os_file_close(ch->manifest_file);
return err;
return ErrorCacheUnavailable;
}
OsTimeStamp actual_mtime;
if ((err = os_file_mtime(this_file, &actual_mtime))) {
@ -392,8 +393,9 @@ Error cache_hit(CacheHash *ch, Buf *out_digest) {
for (; file_i < input_file_count; file_i += 1) {
CacheHashFile *chf = &ch->files.at(file_i);
if ((err = populate_file_hash(ch, chf, nullptr))) {
fprintf(stderr, "Unable to hash %s: %s\n", buf_ptr(chf->path), err_str(err));
os_file_close(ch->manifest_file);
return err;
return ErrorCacheUnavailable;
}
}
return ErrorNone;

View File

@ -129,6 +129,11 @@ CodeGen *codegen_create(Buf *root_src_path, const ZigTarget *target, OutType out
Buf *src_dir = buf_alloc();
os_path_split(root_src_path, src_dir, src_basename);
if (buf_len(src_basename) == 0) {
fprintf(stderr, "Invalid root source path: %s\n", buf_ptr(root_src_path));
exit(1);
}
g->root_package = new_package(buf_ptr(src_dir), buf_ptr(src_basename));
g->std_package = new_package(buf_ptr(g->zig_std_dir), "index.zig");
g->root_package->package_table.put(buf_create_from_str("std"), g->std_package);
@ -1645,7 +1650,7 @@ static LLVMValueRef gen_widen_or_shorten(CodeGen *g, bool want_runtime_safety, Z
zig_unreachable();
}
if (actual_bits >= wanted_bits && actual_type->id == ZigTypeIdInt &&
if (actual_type->id == ZigTypeIdInt &&
!wanted_type->data.integral.is_signed && actual_type->data.integral.is_signed &&
want_runtime_safety)
{
@ -2877,32 +2882,6 @@ static LLVMValueRef ir_render_cast(CodeGen *g, IrExecutable *executable,
gen_store_untyped(g, new_len, dest_len_ptr, 0, false);
return cast_instruction->tmp_ptr;
}
case CastOpBytesToSlice:
{
assert(cast_instruction->tmp_ptr);
assert(wanted_type->id == ZigTypeIdStruct);
assert(wanted_type->data.structure.is_slice);
assert(actual_type->id == ZigTypeIdArray);
ZigType *wanted_pointer_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
ZigType *wanted_child_type = wanted_pointer_type->data.pointer.child_type;
size_t wanted_ptr_index = wanted_type->data.structure.fields[0].gen_index;
LLVMValueRef dest_ptr_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
(unsigned)wanted_ptr_index, "");
LLVMValueRef src_ptr_casted = LLVMBuildBitCast(g->builder, expr_val, wanted_pointer_type->type_ref, "");
gen_store_untyped(g, src_ptr_casted, dest_ptr_ptr, 0, false);
size_t wanted_len_index = wanted_type->data.structure.fields[1].gen_index;
LLVMValueRef len_ptr = LLVMBuildStructGEP(g->builder, cast_instruction->tmp_ptr,
(unsigned)wanted_len_index, "");
LLVMValueRef len_val = LLVMConstInt(g->builtin_types.entry_usize->type_ref,
actual_type->data.array.len / type_size(g, wanted_child_type), false);
gen_store_untyped(g, len_val, len_ptr, 0, false);
return cast_instruction->tmp_ptr;
}
case CastOpIntToFloat:
@ -3660,6 +3639,13 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
AsmOutput *asm_output = asm_expr->output_list.at(i);
bool is_return = (asm_output->return_type != nullptr);
assert(*buf_ptr(asm_output->constraint) == '=');
// LLVM uses commas internally to separate different constraints,
// alternative constraints are achieved with pipes.
// We still allow the user to use commas in a way that is similar
// to GCC's inline assembly.
// http://llvm.org/docs/LangRef.html#constraint-codes
buf_replace(asm_output->constraint, ',', '|');
if (is_return) {
buf_appendf(&constraint_buf, "=%s", buf_ptr(asm_output->constraint) + 1);
} else {
@ -3679,14 +3665,30 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
}
for (size_t i = 0; i < asm_expr->input_list.length; i += 1, total_index += 1, param_index += 1) {
AsmInput *asm_input = asm_expr->input_list.at(i);
buf_replace(asm_input->constraint, ',', '|');
IrInstruction *ir_input = instruction->input_list[i];
buf_append_buf(&constraint_buf, asm_input->constraint);
if (total_index + 1 < total_constraint_count) {
buf_append_char(&constraint_buf, ',');
}
param_types[param_index] = ir_input->value.type->type_ref;
param_values[param_index] = ir_llvm_value(g, ir_input);
ZigType *const type = ir_input->value.type;
LLVMTypeRef type_ref = type->type_ref;
LLVMValueRef value_ref = ir_llvm_value(g, ir_input);
// Handle integers of non pot bitsize by widening them.
if (type->id == ZigTypeIdInt) {
const size_t bitsize = type->data.integral.bit_count;
if (bitsize < 8 || !is_power_of_2(bitsize)) {
const bool is_signed = type->data.integral.is_signed;
const size_t wider_bitsize = bitsize < 8 ? 8 : round_to_next_power_of_2(bitsize);
ZigType *const wider_type = get_int_type(g, is_signed, wider_bitsize);
type_ref = wider_type->type_ref;
value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref);
}
}
param_types[param_index] = type_ref;
param_values[param_index] = value_ref;
}
for (size_t i = 0; i < asm_expr->clobber_list.length; i += 1, total_index += 1) {
Buf *clobber_buf = asm_expr->clobber_list.at(i);
@ -3705,8 +3707,8 @@ static LLVMValueRef ir_render_asm(CodeGen *g, IrExecutable *executable, IrInstru
LLVMTypeRef function_type = LLVMFunctionType(ret_type, param_types, (unsigned)input_and_output_count, false);
bool is_volatile = asm_expr->is_volatile || (asm_expr->output_list.length == 0);
LLVMValueRef asm_fn = LLVMConstInlineAsm(function_type, buf_ptr(&llvm_template),
buf_ptr(&constraint_buf), is_volatile, false);
LLVMValueRef asm_fn = LLVMGetInlineAsm(function_type, buf_ptr(&llvm_template), buf_len(&llvm_template),
buf_ptr(&constraint_buf), buf_len(&constraint_buf), is_volatile, false, LLVMInlineAsmDialectATT);
return LLVMBuildCall(g->builder, asm_fn, param_values, (unsigned)input_and_output_count, "");
}
@ -3786,6 +3788,11 @@ static LLVMValueRef get_int_builtin_fn(CodeGen *g, ZigType *int_type, BuiltinFnI
n_args = 1;
key.id = ZigLLVMFnIdPopCount;
key.data.pop_count.bit_count = (uint32_t)int_type->data.integral.bit_count;
} else if (fn_id == BuiltinFnIdBswap) {
fn_name = "bswap";
n_args = 1;
key.id = ZigLLVMFnIdBswap;
key.data.bswap.bit_count = (uint32_t)int_type->data.integral.bit_count;
} else {
zig_unreachable();
}
@ -5070,6 +5077,29 @@ static LLVMValueRef ir_render_sqrt(CodeGen *g, IrExecutable *executable, IrInstr
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
static LLVMValueRef ir_render_bswap(CodeGen *g, IrExecutable *executable, IrInstructionBswap *instruction) {
LLVMValueRef op = ir_llvm_value(g, instruction->op);
ZigType *int_type = instruction->base.value.type;
assert(int_type->id == ZigTypeIdInt);
if (int_type->data.integral.bit_count % 16 == 0) {
LLVMValueRef fn_val = get_int_builtin_fn(g, instruction->base.value.type, BuiltinFnIdBswap);
return LLVMBuildCall(g->builder, fn_val, &op, 1, "");
}
// Not an even number of bytes, so we zext 1 byte, then bswap, shift right 1 byte, truncate
ZigType *extended_type = get_int_type(g, int_type->data.integral.is_signed,
int_type->data.integral.bit_count + 8);
// aabbcc
LLVMValueRef extended = LLVMBuildZExt(g->builder, op, extended_type->type_ref, "");
// 00aabbcc
LLVMValueRef fn_val = get_int_builtin_fn(g, extended_type, BuiltinFnIdBswap);
LLVMValueRef swapped = LLVMBuildCall(g->builder, fn_val, &extended, 1, "");
// ccbbaa00
LLVMValueRef shifted = ZigLLVMBuildLShrExact(g->builder, swapped,
LLVMConstInt(extended_type->type_ref, 8, false), "");
// 00ccbbaa
return LLVMBuildTrunc(g->builder, shifted, int_type->type_ref, "");
}
static void set_debug_location(CodeGen *g, IrInstruction *instruction) {
AstNode *source_node = instruction->source_node;
Scope *scope = instruction->scope;
@ -5307,6 +5337,8 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
return ir_render_mark_err_ret_trace_ptr(g, executable, (IrInstructionMarkErrRetTracePtr *)instruction);
case IrInstructionIdSqrt:
return ir_render_sqrt(g, executable, (IrInstructionSqrt *)instruction);
case IrInstructionIdBswap:
return ir_render_bswap(g, executable, (IrInstructionBswap *)instruction);
}
zig_unreachable();
}
@ -6258,8 +6290,14 @@ static void do_code_gen(CodeGen *g) {
}
if (ir_get_var_is_comptime(var))
continue;
if (type_requires_comptime(var->value->type))
continue;
switch (type_requires_comptime(g, var->value->type)) {
case ReqCompTimeInvalid:
zig_unreachable();
case ReqCompTimeYes:
continue;
case ReqCompTimeNo:
break;
}
if (var->src_arg_index == SIZE_MAX) {
var->value_ref = build_alloca(g, var->value->type, buf_ptr(&var->name), var->align_bytes);
@ -6723,6 +6761,7 @@ static void define_builtin_fns(CodeGen *g) {
create_builtin_fn(g, BuiltinFnIdToBytes, "sliceToBytes", 1);
create_builtin_fn(g, BuiltinFnIdFromBytes, "bytesToSlice", 2);
create_builtin_fn(g, BuiltinFnIdThis, "This", 0);
create_builtin_fn(g, BuiltinFnIdBswap, "bswap", 2);
}
static const char *bool_to_str(bool b) {
@ -8149,7 +8188,11 @@ void codegen_build_and_link(CodeGen *g) {
os_path_join(stage1_dir, buf_create_from_str("build"), manifest_dir);
if ((err = check_cache(g, manifest_dir, &digest))) {
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
if (err == ErrorCacheUnavailable) {
// message already printed
} else {
fprintf(stderr, "Unable to check cache: %s\n", err_str(err));
}
exit(1);
}

View File

@ -33,6 +33,7 @@ const char *err_str(Error err) {
case ErrorSharingViolation: return "sharing violation";
case ErrorPipeBusy: return "pipe busy";
case ErrorPrimitiveTypeNotFound: return "primitive type not found";
case ErrorCacheUnavailable: return "cache unavailable";
}
return "(invalid error)";
}

View File

@ -35,6 +35,7 @@ enum Error {
ErrorSharingViolation,
ErrorPipeBusy,
ErrorPrimitiveTypeNotFound,
ErrorCacheUnavailable,
};
const char *err_str(Error err);

File diff suppressed because it is too large Load Diff

View File

@ -1323,6 +1323,18 @@ static void ir_print_sqrt(IrPrint *irp, IrInstructionSqrt *instruction) {
fprintf(irp->f, ")");
}
static void ir_print_bswap(IrPrint *irp, IrInstructionBswap *instruction) {
fprintf(irp->f, "@bswap(");
if (instruction->type != nullptr) {
ir_print_other_instruction(irp, instruction->type);
} else {
fprintf(irp->f, "null");
}
fprintf(irp->f, ",");
ir_print_other_instruction(irp, instruction->op);
fprintf(irp->f, ")");
}
static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
ir_print_prefix(irp, instruction);
switch (instruction->id) {
@ -1736,6 +1748,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
case IrInstructionIdSqrt:
ir_print_sqrt(irp, (IrInstructionSqrt *)instruction);
break;
case IrInstructionIdBswap:
ir_print_bswap(irp, (IrInstructionBswap *)instruction);
break;
case IrInstructionIdAtomicLoad:
ir_print_atomic_load(irp, (IrInstructionAtomicLoad *)instruction);
break;

View File

@ -150,6 +150,10 @@ static const char *getLDMOption(const ZigTarget *t) {
if (t->env_type == ZigLLVM_GNUX32) {
return "elf32_x86_64";
}
// Any target elf will use the freebsd osabi if suffixed with "_fbsd".
if (t->os == OsFreeBSD) {
return "elf_x86_64_fbsd";
}
return "elf_x86_64";
default:
zig_unreachable();
@ -191,6 +195,9 @@ static Buf *try_dynamic_linker_path(const char *ld_name) {
}
static Buf *get_dynamic_linker_path(CodeGen *g) {
if (g->zig_target.os == OsFreeBSD) {
return buf_create_from_str("/libexec/ld-elf.so.1");
}
if (g->is_native_target && g->zig_target.arch.arch == ZigLLVM_x86_64) {
static const char *ld_names[] = {
"ld-linux-x86-64.so.2",

View File

@ -466,16 +466,9 @@ int main(int argc, char **argv) {
"\n"
"General Options:\n"
" --help Print this help and exit\n"
" --build-file [file] Override path to build.zig\n"
" --cache-dir [path] Override path to cache directory\n"
" --verbose Print commands before executing them\n"
" --verbose-tokenize Enable compiler debug output for tokenization\n"
" --verbose-ast Enable compiler debug output for parsing into an AST\n"
" --verbose-link Enable compiler debug output for linking\n"
" --verbose-ir Enable compiler debug output for Zig IR\n"
" --verbose-llvm-ir Enable compiler debug output for LLVM IR\n"
" --verbose-cimport Enable compiler debug output for C imports\n"
" --prefix [path] Override default install prefix\n"
" --search-prefix [path] Add a path to look for binaries, libraries, headers\n"
"\n"
"Project-specific options become available when the build file is found.\n"
"\n"

View File

@ -50,10 +50,13 @@ typedef SSIZE_T ssize_t;
#endif
#if defined(ZIG_OS_LINUX)
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
#include <link.h>
#endif
#if defined(ZIG_OS_FREEBSD)
#include <sys/sysctl.h>
#endif
#if defined(__MACH__)
#include <mach/clock.h>
@ -75,7 +78,9 @@ static clock_serv_t cclock;
#if defined(__APPLE__) && !defined(environ)
#include <crt_externs.h>
#define environ (*_NSGetEnviron())
#endif
#elif defined(ZIG_OS_FREEBSD)
extern char **environ;
#endif
#if defined(ZIG_OS_POSIX)
static void populate_termination(Termination *term, int status) {
@ -188,14 +193,20 @@ void os_path_split(Buf *full_path, Buf *out_dirname, Buf *out_basename) {
size_t len = buf_len(full_path);
if (len != 0) {
size_t last_index = len - 1;
if (os_is_sep(buf_ptr(full_path)[last_index])) {
char last_char = buf_ptr(full_path)[last_index];
if (os_is_sep(last_char)) {
if (last_index == 0) {
if (out_dirname) buf_init_from_mem(out_dirname, &last_char, 1);
if (out_basename) buf_init_from_str(out_basename, "");
return;
}
last_index -= 1;
}
for (size_t i = last_index;;) {
uint8_t c = buf_ptr(full_path)[i];
if (os_is_sep(c)) {
if (out_dirname) {
buf_init_from_mem(out_dirname, buf_ptr(full_path), i);
buf_init_from_mem(out_dirname, buf_ptr(full_path), (i == 0) ? 1 : i);
}
if (out_basename) {
buf_init_from_mem(out_basename, buf_ptr(full_path) + i + 1, buf_len(full_path) - (i + 1));
@ -1438,6 +1449,15 @@ Error os_self_exe_path(Buf *out_path) {
}
buf_resize(out_path, amt);
return ErrorNone;
#elif defined(ZIG_OS_FREEBSD)
buf_resize(out_path, PATH_MAX);
int mib[4] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
size_t cb = PATH_MAX;
if (sysctl(mib, 4, buf_ptr(out_path), &cb, nullptr, 0) != 0) {
return ErrorUnexpected;
}
buf_resize(out_path, cb - 1);
return ErrorNone;
#endif
return ErrorFileNotFound;
}
@ -1743,7 +1763,7 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) {
buf_resize(out_path, 0);
buf_appendf(out_path, "%s/Library/Application Support/%s", home_dir, appname);
return ErrorNone;
#elif defined(ZIG_OS_LINUX)
#elif defined(ZIG_OS_POSIX)
const char *home_dir = getenv("HOME");
if (home_dir == nullptr) {
// TODO use /etc/passwd
@ -1756,7 +1776,7 @@ Error os_get_app_data_dir(Buf *out_path, const char *appname) {
}
#if defined(ZIG_OS_LINUX)
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size, void *data) {
ZigList<Buf *> *libs = reinterpret_cast< ZigList<Buf *> *>(data);
if (info->dlpi_name[0] == '/') {
@ -1767,7 +1787,7 @@ static int self_exe_shared_libs_callback(struct dl_phdr_info *info, size_t size,
#endif
Error os_self_exe_shared_libs(ZigList<Buf *> &paths) {
#if defined(ZIG_OS_LINUX)
#if defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
paths.resize(0);
dl_iterate_phdr(self_exe_shared_libs_callback, &paths);
return ErrorNone;
@ -1936,7 +1956,7 @@ Error os_file_mtime(OsFile file, OsTimeStamp *mtime) {
mtime->sec = (((ULONGLONG) last_write_time.dwHighDateTime) << 32) + last_write_time.dwLowDateTime;
mtime->nsec = 0;
return ErrorNone;
#elif defined(ZIG_OS_LINUX)
#elif defined(ZIG_OS_LINUX) || defined(ZIG_OS_FREEBSD)
struct stat statbuf;
if (fstat(file, &statbuf) == -1)
return ErrorFileSystem;
@ -1976,7 +1996,7 @@ Error os_file_read(OsFile file, void *ptr, size_t *len) {
case EFAULT:
zig_unreachable();
case EISDIR:
zig_unreachable();
return ErrorIsDir;
default:
return ErrorFileSystem;
}

View File

@ -23,6 +23,8 @@
#define ZIG_OS_WINDOWS
#elif defined(__linux__)
#define ZIG_OS_LINUX
#elif defined(__FreeBSD__)
#define ZIG_OS_FREEBSD
#else
#define ZIG_OS_UNKNOWN
#endif

View File

@ -91,7 +91,7 @@ static Token *ast_parse_break_label(ParseContext *pc);
static Token *ast_parse_block_label(ParseContext *pc);
static AstNode *ast_parse_field_init(ParseContext *pc);
static AstNode *ast_parse_while_continue_expr(ParseContext *pc);
static AstNode *ast_parse_section(ParseContext *pc);
static AstNode *ast_parse_link_section(ParseContext *pc);
static Optional<AstNodeFnProto> ast_parse_fn_cc(ParseContext *pc);
static AstNode *ast_parse_param_decl(ParseContext *pc);
static AstNode *ast_parse_param_type(ParseContext *pc);
@ -775,7 +775,7 @@ static AstNode *ast_parse_top_level_decl(ParseContext *pc, VisibMod visib_mod) {
return nullptr;
}
// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? Section? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
// FnProto <- FnCC? KEYWORD_fn IDENTIFIER? LPAREN ParamDeclList RPAREN ByteAlign? LinkSection? EXCLAMATIONMARK? (KEYWORD_var / TypeExpr)
static AstNode *ast_parse_fn_proto(ParseContext *pc) {
Token *first = peek_token(pc);
AstNodeFnProto fn_cc;
@ -806,7 +806,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
expect_token(pc, TokenIdRParen);
AstNode *align_expr = ast_parse_byte_align(pc);
AstNode *section_expr = ast_parse_section(pc);
AstNode *section_expr = ast_parse_link_section(pc);
Token *var = eat_token_if(pc, TokenIdKeywordVar);
Token *exmark = nullptr;
AstNode *return_type = nullptr;
@ -842,7 +842,7 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) {
return res;
}
// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? Section? (EQUAL Expr)? SEMICOLON
// VarDecl <- (KEYWORD_const / KEYWORD_var) IDENTIFIER (COLON TypeExpr)? ByteAlign? LinkSection? (EQUAL Expr)? SEMICOLON
static AstNode *ast_parse_var_decl(ParseContext *pc) {
Token *first = eat_token_if(pc, TokenIdKeywordConst);
if (first == nullptr)
@ -856,7 +856,7 @@ static AstNode *ast_parse_var_decl(ParseContext *pc) {
type_expr = ast_expect(pc, ast_parse_type_expr);
AstNode *align_expr = ast_parse_byte_align(pc);
AstNode *section_expr = ast_parse_section(pc);
AstNode *section_expr = ast_parse_link_section(pc);
AstNode *expr = nullptr;
if (eat_token_if(pc, TokenIdEq) != nullptr)
expr = ast_expect(pc, ast_parse_expr);
@ -1490,8 +1490,8 @@ static AstNode *ast_parse_error_union_expr(ParseContext *pc) {
}
// SuffixExpr
// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArgumnets
// / PrimaryTypeExpr (SuffixOp / FnCallArgumnets)*
// <- AsyncPrefix PrimaryTypeExpr SuffixOp* FnCallArguments
// / PrimaryTypeExpr (SuffixOp / FnCallArguments)*
static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
AstNode *async_call = ast_parse_async_prefix(pc);
if (async_call != nullptr) {
@ -1599,7 +1599,7 @@ static AstNode *ast_parse_suffix_expr(ParseContext *pc) {
}
// PrimaryTypeExpr
// <- BUILTININDENTIFIER FnCallArgumnets
// <- BUILTINIDENTIFIER FnCallArguments
// / CHAR_LITERAL
// / ContainerDecl
// / ErrorSetDecl
@ -1978,7 +1978,7 @@ static AsmOutput *ast_parse_asm_output_item(ParseContext *pc) {
return res;
}
// AsmInput <- COLON AsmInputList AsmCloppers?
// AsmInput <- COLON AsmInputList AsmClobbers?
static AstNode *ast_parse_asm_input(ParseContext *pc) {
if (eat_token_if(pc, TokenIdColon) == nullptr)
return nullptr;
@ -2011,7 +2011,7 @@ static AsmInput *ast_parse_asm_input_item(ParseContext *pc) {
return res;
}
// AsmCloppers <- COLON StringList
// AsmClobbers <- COLON StringList
static AstNode *ast_parse_asm_cloppers(ParseContext *pc) {
if (eat_token_if(pc, TokenIdColon) == nullptr)
return nullptr;
@ -2080,8 +2080,8 @@ static AstNode *ast_parse_while_continue_expr(ParseContext *pc) {
return expr;
}
// Section <- KEYWORD_section LPAREN Expr RPAREN
static AstNode *ast_parse_section(ParseContext *pc) {
// LinkSection <- KEYWORD_linksection LPAREN Expr RPAREN
static AstNode *ast_parse_link_section(ParseContext *pc) {
Token *first = eat_token_if(pc, TokenIdKeywordLinkSection);
if (first == nullptr)
return nullptr;
@ -2742,7 +2742,7 @@ static AstNode *ast_parse_async_prefix(ParseContext *pc) {
return res;
}
// FnCallArgumnets <- LPAREN ExprList RPAREN
// FnCallArguments <- LPAREN ExprList RPAREN
static AstNode *ast_parse_fn_call_argumnets(ParseContext *pc) {
Token *paren = eat_token_if(pc, TokenIdLParen);
if (paren == nullptr)

View File

@ -754,6 +754,7 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case OsLinux:
case OsMacOSX:
case OsZen:
case OsFreeBSD:
case OsOpenBSD:
switch (id) {
case CIntTypeShort:
@ -790,7 +791,6 @@ uint32_t target_c_type_size_in_bits(const ZigTarget *target, CIntType id) {
case OsAnanas:
case OsCloudABI:
case OsDragonFly:
case OsFreeBSD:
case OsIOS:
case OsKFreeBSD:
case OsLv2:
@ -1028,3 +1028,64 @@ const char *arch_stack_pointer_register_name(const ArchType *arch) {
}
zig_unreachable();
}
bool target_is_arm(const ZigTarget *target) {
switch (target->arch.arch) {
case ZigLLVM_UnknownArch:
zig_unreachable();
case ZigLLVM_aarch64:
case ZigLLVM_arm:
case ZigLLVM_thumb:
case ZigLLVM_aarch64_be:
case ZigLLVM_armeb:
case ZigLLVM_thumbeb:
return true;
case ZigLLVM_x86:
case ZigLLVM_x86_64:
case ZigLLVM_amdgcn:
case ZigLLVM_amdil:
case ZigLLVM_amdil64:
case ZigLLVM_arc:
case ZigLLVM_avr:
case ZigLLVM_bpfeb:
case ZigLLVM_bpfel:
case ZigLLVM_hexagon:
case ZigLLVM_lanai:
case ZigLLVM_hsail:
case ZigLLVM_hsail64:
case ZigLLVM_kalimba:
case ZigLLVM_le32:
case ZigLLVM_le64:
case ZigLLVM_mips:
case ZigLLVM_mips64:
case ZigLLVM_mips64el:
case ZigLLVM_mipsel:
case ZigLLVM_msp430:
case ZigLLVM_nios2:
case ZigLLVM_nvptx:
case ZigLLVM_nvptx64:
case ZigLLVM_ppc64le:
case ZigLLVM_r600:
case ZigLLVM_renderscript32:
case ZigLLVM_renderscript64:
case ZigLLVM_riscv32:
case ZigLLVM_riscv64:
case ZigLLVM_shave:
case ZigLLVM_sparc:
case ZigLLVM_sparcel:
case ZigLLVM_sparcv9:
case ZigLLVM_spir:
case ZigLLVM_spir64:
case ZigLLVM_systemz:
case ZigLLVM_tce:
case ZigLLVM_tcele:
case ZigLLVM_wasm32:
case ZigLLVM_wasm64:
case ZigLLVM_xcore:
case ZigLLVM_ppc:
case ZigLLVM_ppc64:
return false;
}
zig_unreachable();
}

View File

@ -122,4 +122,6 @@ Buf *target_dynamic_linker(ZigTarget *target);
bool target_can_exec(const ZigTarget *host_target, const ZigTarget *guest_target);
ZigLLVM_OSType get_llvm_os_type(Os os_type);
bool target_is_arm(const ZigTarget *target);
#endif

View File

@ -4784,6 +4784,14 @@ Error parse_h_file(ImportTableEntry *import, ZigList<ErrorMsg *> *errors, const
clang_argv.append(target_file);
if (codegen->verbose_cimport) {
fprintf(stderr, "clang");
for (size_t i = 0; i < clang_argv.length; i += 1) {
fprintf(stderr, " %s", clang_argv.at(i));
}
fprintf(stderr, "\n");
}
// to make the [start...end] argument work
clang_argv.append(nullptr);

View File

@ -158,6 +158,17 @@ static inline bool is_power_of_2(uint64_t x) {
return x != 0 && ((x & (~x + 1)) == x);
}
static inline uint64_t round_to_next_power_of_2(uint64_t x) {
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
x |= x >> 32;
return x + 1;
}
uint32_t int_hash(int i);
bool int_eq(int a, int b);
uint32_t uint64_hash(uint64_t i);

View File

@ -680,20 +680,6 @@ void ZigLLVMParseCommandLineOptions(size_t argc, const char *const *argv) {
llvm::cl::ParseCommandLineOptions(argc, argv);
}
static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, "");
static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, "");
static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, "");
static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, "");
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
static_assert((Triple::SubArchType)ZigLLVM_MipsSubArch_r6 == Triple::MipsSubArch_r6, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, "");
const char *ZigLLVMGetArchTypeName(ZigLLVM_ArchType arch) {
return (const char*)Triple::getArchTypeName((Triple::ArchType)arch).bytes_begin();
}
@ -924,3 +910,164 @@ bool ZigLLDLink(ZigLLVM_ObjectFormatType oformat, const char **args, size_t arg_
assert(false); // unreachable
abort();
}
static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");
static_assert((Triple::ArchType)ZigLLVM_arm == Triple::arm, "");
static_assert((Triple::ArchType)ZigLLVM_armeb == Triple::armeb, "");
static_assert((Triple::ArchType)ZigLLVM_aarch64 == Triple::aarch64, "");
static_assert((Triple::ArchType)ZigLLVM_aarch64_be == Triple::aarch64_be, "");
static_assert((Triple::ArchType)ZigLLVM_arc == Triple::arc, "");
static_assert((Triple::ArchType)ZigLLVM_avr == Triple::avr, "");
static_assert((Triple::ArchType)ZigLLVM_bpfel == Triple::bpfel, "");
static_assert((Triple::ArchType)ZigLLVM_bpfeb == Triple::bpfeb, "");
static_assert((Triple::ArchType)ZigLLVM_hexagon == Triple::hexagon, "");
static_assert((Triple::ArchType)ZigLLVM_mips == Triple::mips, "");
static_assert((Triple::ArchType)ZigLLVM_mipsel == Triple::mipsel, "");
static_assert((Triple::ArchType)ZigLLVM_mips64 == Triple::mips64, "");
static_assert((Triple::ArchType)ZigLLVM_mips64el == Triple::mips64el, "");
static_assert((Triple::ArchType)ZigLLVM_msp430 == Triple::msp430, "");
static_assert((Triple::ArchType)ZigLLVM_nios2 == Triple::nios2, "");
static_assert((Triple::ArchType)ZigLLVM_ppc == Triple::ppc, "");
static_assert((Triple::ArchType)ZigLLVM_ppc64 == Triple::ppc64, "");
static_assert((Triple::ArchType)ZigLLVM_ppc64le == Triple::ppc64le, "");
static_assert((Triple::ArchType)ZigLLVM_r600 == Triple::r600, "");
static_assert((Triple::ArchType)ZigLLVM_amdgcn == Triple::amdgcn, "");
static_assert((Triple::ArchType)ZigLLVM_riscv32 == Triple::riscv32, "");
static_assert((Triple::ArchType)ZigLLVM_riscv64 == Triple::riscv64, "");
static_assert((Triple::ArchType)ZigLLVM_sparc == Triple::sparc, "");
static_assert((Triple::ArchType)ZigLLVM_sparcv9 == Triple::sparcv9, "");
static_assert((Triple::ArchType)ZigLLVM_sparcel == Triple::sparcel, "");
static_assert((Triple::ArchType)ZigLLVM_systemz == Triple::systemz, "");
static_assert((Triple::ArchType)ZigLLVM_tce == Triple::tce, "");
static_assert((Triple::ArchType)ZigLLVM_tcele == Triple::tcele, "");
static_assert((Triple::ArchType)ZigLLVM_thumb == Triple::thumb, "");
static_assert((Triple::ArchType)ZigLLVM_thumbeb == Triple::thumbeb, "");
static_assert((Triple::ArchType)ZigLLVM_x86 == Triple::x86, "");
static_assert((Triple::ArchType)ZigLLVM_x86_64 == Triple::x86_64, "");
static_assert((Triple::ArchType)ZigLLVM_xcore == Triple::xcore, "");
static_assert((Triple::ArchType)ZigLLVM_nvptx == Triple::nvptx, "");
static_assert((Triple::ArchType)ZigLLVM_nvptx64 == Triple::nvptx64, "");
static_assert((Triple::ArchType)ZigLLVM_le32 == Triple::le32, "");
static_assert((Triple::ArchType)ZigLLVM_le64 == Triple::le64, "");
static_assert((Triple::ArchType)ZigLLVM_amdil == Triple::amdil, "");
static_assert((Triple::ArchType)ZigLLVM_amdil64 == Triple::amdil64, "");
static_assert((Triple::ArchType)ZigLLVM_hsail == Triple::hsail, "");
static_assert((Triple::ArchType)ZigLLVM_hsail64 == Triple::hsail64, "");
static_assert((Triple::ArchType)ZigLLVM_spir == Triple::spir, "");
static_assert((Triple::ArchType)ZigLLVM_spir64 == Triple::spir64, "");
static_assert((Triple::ArchType)ZigLLVM_kalimba == Triple::kalimba, "");
static_assert((Triple::ArchType)ZigLLVM_shave == Triple::shave, "");
static_assert((Triple::ArchType)ZigLLVM_lanai == Triple::lanai, "");
static_assert((Triple::ArchType)ZigLLVM_wasm32 == Triple::wasm32, "");
static_assert((Triple::ArchType)ZigLLVM_wasm64 == Triple::wasm64, "");
static_assert((Triple::ArchType)ZigLLVM_renderscript32 == Triple::renderscript32, "");
static_assert((Triple::ArchType)ZigLLVM_renderscript64 == Triple::renderscript64, "");
static_assert((Triple::ArchType)ZigLLVM_LastArchType == Triple::LastArchType, "");
static_assert((Triple::SubArchType)ZigLLVM_NoSubArch == Triple::NoSubArch, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_4a == Triple::ARMSubArch_v8_4a, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_3a == Triple::ARMSubArch_v8_3a, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_2a == Triple::ARMSubArch_v8_2a, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8_1a == Triple::ARMSubArch_v8_1a, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8 == Triple::ARMSubArch_v8, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8r == Triple::ARMSubArch_v8r, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_baseline == Triple::ARMSubArch_v8m_baseline, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v8m_mainline == Triple::ARMSubArch_v8m_mainline, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7 == Triple::ARMSubArch_v7, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7em == Triple::ARMSubArch_v7em, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7m == Triple::ARMSubArch_v7m, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7s == Triple::ARMSubArch_v7s, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7k == Triple::ARMSubArch_v7k, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v7ve == Triple::ARMSubArch_v7ve, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6 == Triple::ARMSubArch_v6, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6m == Triple::ARMSubArch_v6m, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6k == Triple::ARMSubArch_v6k, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v6t2 == Triple::ARMSubArch_v6t2, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5 == Triple::ARMSubArch_v5, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v5te == Triple::ARMSubArch_v5te, "");
static_assert((Triple::SubArchType)ZigLLVM_ARMSubArch_v4t == Triple::ARMSubArch_v4t, "");
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v3 == Triple::KalimbaSubArch_v3, "");
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v4 == Triple::KalimbaSubArch_v4, "");
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
static_assert((Triple::SubArchType)ZigLLVM_KalimbaSubArch_v5 == Triple::KalimbaSubArch_v5, "");
static_assert((Triple::SubArchType)ZigLLVM_MipsSubArch_r6 == Triple::MipsSubArch_r6, "");
static_assert((Triple::VendorType)ZigLLVM_UnknownVendor == Triple::UnknownVendor, "");
static_assert((Triple::VendorType)ZigLLVM_Apple == Triple::Apple, "");
static_assert((Triple::VendorType)ZigLLVM_PC == Triple::PC, "");
static_assert((Triple::VendorType)ZigLLVM_SCEI == Triple::SCEI, "");
static_assert((Triple::VendorType)ZigLLVM_BGP == Triple::BGP, "");
static_assert((Triple::VendorType)ZigLLVM_BGQ == Triple::BGQ, "");
static_assert((Triple::VendorType)ZigLLVM_Freescale == Triple::Freescale, "");
static_assert((Triple::VendorType)ZigLLVM_IBM == Triple::IBM, "");
static_assert((Triple::VendorType)ZigLLVM_ImaginationTechnologies == Triple::ImaginationTechnologies, "");
static_assert((Triple::VendorType)ZigLLVM_MipsTechnologies == Triple::MipsTechnologies, "");
static_assert((Triple::VendorType)ZigLLVM_NVIDIA == Triple::NVIDIA, "");
static_assert((Triple::VendorType)ZigLLVM_CSR == Triple::CSR, "");
static_assert((Triple::VendorType)ZigLLVM_Myriad == Triple::Myriad, "");
static_assert((Triple::VendorType)ZigLLVM_AMD == Triple::AMD, "");
static_assert((Triple::VendorType)ZigLLVM_Mesa == Triple::Mesa, "");
static_assert((Triple::VendorType)ZigLLVM_SUSE == Triple::SUSE, "");
static_assert((Triple::VendorType)ZigLLVM_OpenEmbedded == Triple::OpenEmbedded, "");
static_assert((Triple::VendorType)ZigLLVM_LastVendorType == Triple::LastVendorType, "");
static_assert((Triple::OSType)ZigLLVM_UnknownOS == Triple::UnknownOS, "");
static_assert((Triple::OSType)ZigLLVM_Ananas == Triple::Ananas, "");
static_assert((Triple::OSType)ZigLLVM_CloudABI == Triple::CloudABI, "");
static_assert((Triple::OSType)ZigLLVM_Darwin == Triple::Darwin, "");
static_assert((Triple::OSType)ZigLLVM_DragonFly == Triple::DragonFly, "");
static_assert((Triple::OSType)ZigLLVM_FreeBSD == Triple::FreeBSD, "");
static_assert((Triple::OSType)ZigLLVM_Fuchsia == Triple::Fuchsia, "");
static_assert((Triple::OSType)ZigLLVM_IOS == Triple::IOS, "");
static_assert((Triple::OSType)ZigLLVM_KFreeBSD == Triple::KFreeBSD, "");
static_assert((Triple::OSType)ZigLLVM_Linux == Triple::Linux, "");
static_assert((Triple::OSType)ZigLLVM_Lv2 == Triple::Lv2, "");
static_assert((Triple::OSType)ZigLLVM_MacOSX == Triple::MacOSX, "");
static_assert((Triple::OSType)ZigLLVM_NetBSD == Triple::NetBSD, "");
static_assert((Triple::OSType)ZigLLVM_OpenBSD == Triple::OpenBSD, "");
static_assert((Triple::OSType)ZigLLVM_Solaris == Triple::Solaris, "");
static_assert((Triple::OSType)ZigLLVM_Win32 == Triple::Win32, "");
static_assert((Triple::OSType)ZigLLVM_Haiku == Triple::Haiku, "");
static_assert((Triple::OSType)ZigLLVM_Minix == Triple::Minix, "");
static_assert((Triple::OSType)ZigLLVM_RTEMS == Triple::RTEMS, "");
static_assert((Triple::OSType)ZigLLVM_NaCl == Triple::NaCl, "");
static_assert((Triple::OSType)ZigLLVM_CNK == Triple::CNK, "");
static_assert((Triple::OSType)ZigLLVM_AIX == Triple::AIX, "");
static_assert((Triple::OSType)ZigLLVM_CUDA == Triple::CUDA, "");
static_assert((Triple::OSType)ZigLLVM_NVCL == Triple::NVCL, "");
static_assert((Triple::OSType)ZigLLVM_AMDHSA == Triple::AMDHSA, "");
static_assert((Triple::OSType)ZigLLVM_PS4 == Triple::PS4, "");
static_assert((Triple::OSType)ZigLLVM_ELFIAMCU == Triple::ELFIAMCU, "");
static_assert((Triple::OSType)ZigLLVM_TvOS == Triple::TvOS, "");
static_assert((Triple::OSType)ZigLLVM_WatchOS == Triple::WatchOS, "");
static_assert((Triple::OSType)ZigLLVM_Mesa3D == Triple::Mesa3D, "");
static_assert((Triple::OSType)ZigLLVM_Contiki == Triple::Contiki, "");
static_assert((Triple::OSType)ZigLLVM_AMDPAL == Triple::AMDPAL, "");
static_assert((Triple::OSType)ZigLLVM_LastOSType == Triple::LastOSType, "");
static_assert((Triple::EnvironmentType)ZigLLVM_UnknownEnvironment == Triple::UnknownEnvironment, "");
static_assert((Triple::EnvironmentType)ZigLLVM_GNU == Triple::GNU, "");
static_assert((Triple::EnvironmentType)ZigLLVM_GNUABIN32 == Triple::GNUABIN32, "");
static_assert((Triple::EnvironmentType)ZigLLVM_GNUABI64 == Triple::GNUABI64, "");
static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABI == Triple::GNUEABI, "");
static_assert((Triple::EnvironmentType)ZigLLVM_GNUEABIHF == Triple::GNUEABIHF, "");
static_assert((Triple::EnvironmentType)ZigLLVM_GNUX32 == Triple::GNUX32, "");
static_assert((Triple::EnvironmentType)ZigLLVM_CODE16 == Triple::CODE16, "");
static_assert((Triple::EnvironmentType)ZigLLVM_EABI == Triple::EABI, "");
static_assert((Triple::EnvironmentType)ZigLLVM_EABIHF == Triple::EABIHF, "");
static_assert((Triple::EnvironmentType)ZigLLVM_Android == Triple::Android, "");
static_assert((Triple::EnvironmentType)ZigLLVM_Musl == Triple::Musl, "");
static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABI == Triple::MuslEABI, "");
static_assert((Triple::EnvironmentType)ZigLLVM_MuslEABIHF == Triple::MuslEABIHF, "");
static_assert((Triple::EnvironmentType)ZigLLVM_MSVC == Triple::MSVC, "");
static_assert((Triple::EnvironmentType)ZigLLVM_Itanium == Triple::Itanium, "");
static_assert((Triple::EnvironmentType)ZigLLVM_Cygnus == Triple::Cygnus, "");
static_assert((Triple::EnvironmentType)ZigLLVM_CoreCLR == Triple::CoreCLR, "");
static_assert((Triple::EnvironmentType)ZigLLVM_Simulator == Triple::Simulator, "");
static_assert((Triple::EnvironmentType)ZigLLVM_LastEnvironmentType == Triple::LastEnvironmentType, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_UnknownObjectFormat == Triple::UnknownObjectFormat, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_COFF == Triple::COFF, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_ELF == Triple::ELF, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_MachO == Triple::MachO, "");
static_assert((Triple::ObjectFormatType)ZigLLVM_Wasm == Triple::Wasm, "");

View File

@ -398,3 +398,14 @@ test "std.ArrayList.insertSlice" {
assert(list.len == 6);
assert(list.items[0] == 1);
}
const Item = struct {
integer: i32,
sub_items: ArrayList(Item),
};
test "std.ArrayList: ArrayList(T) of struct T" {
var root = Item{ .integer = 1, .sub_items = ArrayList(Item).init(debug.global_allocator) };
try root.sub_items.append( Item{ .integer = 42, .sub_items = ArrayList(Item).init(debug.global_allocator) } );
assert(root.sub_items.items[0].integer == 42);
}

View File

@ -26,6 +26,10 @@ pub fn Int(comptime T: type) type {
return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst);
}
pub fn set(self: *Self, new_value: T) void {
_ = self.xchg(new_value);
}
pub fn xchg(self: *Self, new_value: T) T {
return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst);
}

View File

@ -16,7 +16,7 @@ pub const BufMap = struct {
return self;
}
pub fn deinit(self: *const BufMap) void {
pub fn deinit(self: *BufMap) void {
var it = self.hash_map.iterator();
while (true) {
const entry = it.next() orelse break;
@ -27,16 +27,34 @@ pub const BufMap = struct {
self.hash_map.deinit();
}
pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void {
self.delete(key);
const key_copy = try self.copy(key);
errdefer self.free(key_copy);
const value_copy = try self.copy(value);
errdefer self.free(value_copy);
_ = try self.hash_map.put(key_copy, value_copy);
/// Same as `set` but the key and value become owned by the BufMap rather
/// than being copied.
/// If `setMove` fails, the ownership of key and value does not transfer.
pub fn setMove(self: *BufMap, key: []u8, value: []u8) !void {
const get_or_put = try self.hash_map.getOrPut(key);
if (get_or_put.found_existing) {
self.free(get_or_put.kv.key);
get_or_put.kv.key = key;
}
get_or_put.kv.value = value;
}
pub fn get(self: *const BufMap, key: []const u8) ?[]const u8 {
/// `key` and `value` are copied into the BufMap.
pub fn set(self: *BufMap, key: []const u8, value: []const u8) !void {
const value_copy = try self.copy(value);
errdefer self.free(value_copy);
// Avoid copying key if it already exists
const get_or_put = try self.hash_map.getOrPut(key);
if (!get_or_put.found_existing) {
get_or_put.kv.key = self.copy(key) catch |err| {
_ = self.hash_map.remove(key);
return err;
};
}
get_or_put.kv.value = value_copy;
}
pub fn get(self: BufMap, key: []const u8) ?[]const u8 {
const entry = self.hash_map.get(key) orelse return null;
return entry.value;
}
@ -47,7 +65,7 @@ pub const BufMap = struct {
self.free(entry.value);
}
pub fn count(self: *const BufMap) usize {
pub fn count(self: BufMap) usize {
return self.hash_map.count();
}
@ -55,11 +73,11 @@ pub const BufMap = struct {
return self.hash_map.iterator();
}
fn free(self: *const BufMap, value: []const u8) void {
fn free(self: BufMap, value: []const u8) void {
self.hash_map.allocator.free(value);
}
fn copy(self: *const BufMap, value: []const u8) ![]const u8 {
fn copy(self: BufMap, value: []const u8) ![]u8 {
return mem.dupe(self.hash_map.allocator, u8, value);
}
};

View File

@ -150,7 +150,11 @@ pub const Builder = struct {
}
pub fn addExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
return LibExeObjStep.createExecutable(self, name, root_src);
return LibExeObjStep.createExecutable(self, name, root_src, false);
}
pub fn addStaticExecutable(self: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
return LibExeObjStep.createExecutable(self, name, root_src, true);
}
pub fn addObject(self: *Builder, name: []const u8, root_src: []const u8) *LibExeObjStep {
@ -795,11 +799,23 @@ pub const Target = union(enum) {
};
}
pub fn isFreeBSD(self: *const Target) bool {
return switch (self.getOs()) {
builtin.Os.freebsd => true,
else => false,
};
}
pub fn wantSharedLibSymLinks(self: *const Target) bool {
return !self.isWindows();
}
};
const Pkg = struct {
name: []const u8,
path: []const u8,
};
pub const LibExeObjStep = struct {
step: Step,
builder: *Builder,
@ -842,11 +858,6 @@ pub const LibExeObjStep = struct {
source_files: ArrayList([]const u8),
object_src: []const u8,
const Pkg = struct {
name: []const u8,
path: []const u8,
};
const Kind = enum {
Exe,
Lib,
@ -884,8 +895,8 @@ pub const LibExeObjStep = struct {
return self;
}
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8) *LibExeObjStep {
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, false, builder.version(0, 0, 0))) catch unreachable;
pub fn createExecutable(builder: *Builder, name: []const u8, root_src: ?[]const u8, static: bool) *LibExeObjStep {
const self = builder.allocator.create(initExtraArgs(builder, name, root_src, Kind.Exe, static, builder.version(0, 0, 0))) catch unreachable;
return self;
}
@ -1263,6 +1274,9 @@ pub const LibExeObjStep = struct {
zig_args.append("--ver-patch") catch unreachable;
zig_args.append(builder.fmt("{}", self.version.patch)) catch unreachable;
}
if (self.kind == Kind.Exe and self.static) {
zig_args.append("--static") catch unreachable;
}
switch (self.target) {
Target.Native => {},
@ -1653,6 +1667,7 @@ pub const TestStep = struct {
exec_cmd_args: ?[]const ?[]const u8,
include_dirs: ArrayList([]const u8),
lib_paths: ArrayList([]const u8),
packages: ArrayList(Pkg),
object_files: ArrayList([]const u8),
no_rosegment: bool,
output_path: ?[]const u8,
@ -1673,6 +1688,7 @@ pub const TestStep = struct {
.exec_cmd_args = null,
.include_dirs = ArrayList([]const u8).init(builder.allocator),
.lib_paths = ArrayList([]const u8).init(builder.allocator),
.packages = ArrayList(Pkg).init(builder.allocator),
.object_files = ArrayList([]const u8).init(builder.allocator),
.no_rosegment = false,
.output_path = null,
@ -1688,6 +1704,13 @@ pub const TestStep = struct {
self.lib_paths.append(path) catch unreachable;
}
pub fn addPackagePath(self: *TestStep, name: []const u8, pkg_index_path: []const u8) void {
self.packages.append(Pkg{
.name = name,
.path = pkg_index_path,
}) catch unreachable;
}
pub fn setVerbose(self: *TestStep, value: bool) void {
self.verbose = value;
}
@ -1864,6 +1887,13 @@ pub const TestStep = struct {
try zig_args.append(lib_path);
}
for (self.packages.toSliceConst()) |pkg| {
zig_args.append("--pkg-begin") catch unreachable;
zig_args.append(pkg.name) catch unreachable;
zig_args.append(builder.pathFromRoot(pkg.path)) catch unreachable;
zig_args.append("--pkg-end") catch unreachable;
}
if (self.no_rosegment) {
try zig_args.append("--no-rosegment");
}

33
std/c/freebsd.zig Normal file
View File

@ -0,0 +1,33 @@
const timespec = @import("../os/freebsd/index.zig").timespec;
extern "c" fn __error() *c_int;
pub const _errno = __error;
pub extern "c" fn kqueue() c_int;
pub extern "c" fn kevent(
kq: c_int,
changelist: [*]const Kevent,
nchanges: c_int,
eventlist: [*]Kevent,
nevents: c_int,
timeout: ?*const timespec,
) c_int;
pub extern "c" fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) c_int;
pub extern "c" fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) c_int;
/// Renamed from `kevent` to `Kevent` to avoid conflict with function name.
pub const Kevent = extern struct {
ident: usize,
filter: i16,
flags: u16,
fflags: u32,
data: i64,
udata: usize,
// TODO ext
};
pub const pthread_attr_t = extern struct {
__size: [56]u8,
__align: c_long,
};

View File

@ -5,6 +5,7 @@ pub use switch (builtin.os) {
Os.linux => @import("linux.zig"),
Os.windows => @import("windows.zig"),
Os.macosx, Os.ios => @import("darwin.zig"),
Os.freebsd => @import("freebsd.zig"),
else => empty_import,
};
const empty_import = @import("../empty.zig");

View File

@ -51,7 +51,7 @@ pub const Coff = struct {
// Seek to PE File Header (coff header)
try self.in_file.seekTo(pe_pointer_offset);
const pe_magic_offset = try in.readIntLe(u32);
const pe_magic_offset = try in.readIntLittle(u32);
try self.in_file.seekTo(pe_magic_offset);
var pe_header_magic: [4]u8 = undefined;
@ -60,13 +60,13 @@ pub const Coff = struct {
return error.InvalidPEHeader;
self.coff_header = CoffHeader{
.machine = try in.readIntLe(u16),
.number_of_sections = try in.readIntLe(u16),
.timedate_stamp = try in.readIntLe(u32),
.pointer_to_symbol_table = try in.readIntLe(u32),
.number_of_symbols = try in.readIntLe(u32),
.size_of_optional_header = try in.readIntLe(u16),
.characteristics = try in.readIntLe(u16),
.machine = try in.readIntLittle(u16),
.number_of_sections = try in.readIntLittle(u16),
.timedate_stamp = try in.readIntLittle(u32),
.pointer_to_symbol_table = try in.readIntLittle(u32),
.number_of_symbols = try in.readIntLittle(u32),
.size_of_optional_header = try in.readIntLittle(u16),
.characteristics = try in.readIntLittle(u16),
};
switch (self.coff_header.machine) {
@ -79,7 +79,7 @@ pub const Coff = struct {
fn loadOptionalHeader(self: *Coff, file_stream: *os.File.InStream) !void {
const in = &file_stream.stream;
self.pe_header.magic = try in.readIntLe(u16);
self.pe_header.magic = try in.readIntLittle(u16);
// For now we're only interested in finding the reference to the .pdb,
// so we'll skip most of this header, which size is different in 32
// 64 bits by the way.
@ -93,14 +93,14 @@ pub const Coff = struct {
try self.in_file.seekForward(skip_size);
const number_of_rva_and_sizes = try in.readIntLe(u32);
const number_of_rva_and_sizes = try in.readIntLittle(u32);
if (number_of_rva_and_sizes != IMAGE_NUMBEROF_DIRECTORY_ENTRIES)
return error.InvalidPEHeader;
for (self.pe_header.data_directory) |*data_dir| {
data_dir.* = OptionalHeader.DataDirectory{
.virtual_address = try in.readIntLe(u32),
.size = try in.readIntLe(u32),
.virtual_address = try in.readIntLittle(u32),
.size = try in.readIntLittle(u32),
};
}
}
@ -124,7 +124,7 @@ pub const Coff = struct {
if (!mem.eql(u8, cv_signature, "RSDS"))
return error.InvalidPEMagic;
try in.readNoEof(self.guid[0..]);
self.age = try in.readIntLe(u32);
self.age = try in.readIntLittle(u32);
// Finally read the null-terminated string.
var byte = try in.readByte();
@ -157,15 +157,15 @@ pub const Coff = struct {
try self.sections.append(Section{
.header = SectionHeader{
.name = name,
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLe(u32) },
.virtual_address = try in.readIntLe(u32),
.size_of_raw_data = try in.readIntLe(u32),
.pointer_to_raw_data = try in.readIntLe(u32),
.pointer_to_relocations = try in.readIntLe(u32),
.pointer_to_line_numbers = try in.readIntLe(u32),
.number_of_relocations = try in.readIntLe(u16),
.number_of_line_numbers = try in.readIntLe(u16),
.characteristics = try in.readIntLe(u32),
.misc = SectionHeader.Misc{ .physical_address = try in.readIntLittle(u32) },
.virtual_address = try in.readIntLittle(u32),
.size_of_raw_data = try in.readIntLittle(u32),
.pointer_to_raw_data = try in.readIntLittle(u32),
.pointer_to_relocations = try in.readIntLittle(u32),
.pointer_to_line_numbers = try in.readIntLittle(u32),
.number_of_relocations = try in.readIntLittle(u16),
.number_of_line_numbers = try in.readIntLittle(u16),
.characteristics = try in.readIntLittle(u32),
},
});
}

View File

@ -123,7 +123,8 @@ fn Blake2s(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 32];
for (rr) |s, j| {
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
}
}
@ -134,7 +135,8 @@ fn Blake2s(comptime out_len: usize) type {
var v: [16]u32 = undefined;
for (m) |*r, i| {
r.* = mem.readIntLE(u32, b[4 * i .. 4 * i + 4]);
// TODO https://github.com/ziglang/zig/issues/863
r.* = mem.readIntSliceLittle(u32, b[4 * i .. 4 * i + 4]);
}
var k: usize = 0;
@ -356,7 +358,8 @@ fn Blake2b(comptime out_len: usize) type {
const rr = d.h[0 .. out_len / 64];
for (rr) |s, j| {
mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u64, out[8 * j .. 8 * j + 8], s);
}
}
@ -367,7 +370,7 @@ fn Blake2b(comptime out_len: usize) type {
var v: [16]u64 = undefined;
for (m) |*r, i| {
r.* = mem.readIntLE(u64, b[8 * i .. 8 * i + 8]);
r.* = mem.readIntSliceLittle(u64, b[8 * i .. 8 * i + 8]);
}
var k: usize = 0;

View File

@ -59,7 +59,8 @@ fn salsa20_wordtobyte(out: []u8, input: [16]u32) void {
}
for (x) |_, i| {
mem.writeInt(out[4 * i .. 4 * i + 4], x[i] +% input[i], builtin.Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u32, out[4 * i .. 4 * i + 4], x[i] +% input[i]);
}
}
@ -70,10 +71,10 @@ fn chaCha20_internal(out: []u8, in: []const u8, key: [8]u32, counter: [4]u32) vo
const c = "expand 32-byte k";
const constant_le = []u32{
mem.readIntLE(u32, c[0..4]),
mem.readIntLE(u32, c[4..8]),
mem.readIntLE(u32, c[8..12]),
mem.readIntLE(u32, c[12..16]),
mem.readIntSliceLittle(u32, c[0..4]),
mem.readIntSliceLittle(u32, c[4..8]),
mem.readIntSliceLittle(u32, c[8..12]),
mem.readIntSliceLittle(u32, c[12..16]),
};
mem.copy(u32, ctx[0..], constant_le[0..4]);
@ -117,19 +118,19 @@ pub fn chaCha20IETF(out: []u8, in: []const u8, counter: u32, key: [32]u8, nonce:
var k: [8]u32 = undefined;
var c: [4]u32 = undefined;
k[0] = mem.readIntLE(u32, key[0..4]);
k[1] = mem.readIntLE(u32, key[4..8]);
k[2] = mem.readIntLE(u32, key[8..12]);
k[3] = mem.readIntLE(u32, key[12..16]);
k[4] = mem.readIntLE(u32, key[16..20]);
k[5] = mem.readIntLE(u32, key[20..24]);
k[6] = mem.readIntLE(u32, key[24..28]);
k[7] = mem.readIntLE(u32, key[28..32]);
k[0] = mem.readIntSliceLittle(u32, key[0..4]);
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
c[0] = counter;
c[1] = mem.readIntLE(u32, nonce[0..4]);
c[2] = mem.readIntLE(u32, nonce[4..8]);
c[3] = mem.readIntLE(u32, nonce[8..12]);
c[1] = mem.readIntSliceLittle(u32, nonce[0..4]);
c[2] = mem.readIntSliceLittle(u32, nonce[4..8]);
c[3] = mem.readIntSliceLittle(u32, nonce[8..12]);
chaCha20_internal(out, in, k, c);
}
@ -144,19 +145,19 @@ pub fn chaCha20With64BitNonce(out: []u8, in: []const u8, counter: u64, key: [32]
var k: [8]u32 = undefined;
var c: [4]u32 = undefined;
k[0] = mem.readIntLE(u32, key[0..4]);
k[1] = mem.readIntLE(u32, key[4..8]);
k[2] = mem.readIntLE(u32, key[8..12]);
k[3] = mem.readIntLE(u32, key[12..16]);
k[4] = mem.readIntLE(u32, key[16..20]);
k[5] = mem.readIntLE(u32, key[20..24]);
k[6] = mem.readIntLE(u32, key[24..28]);
k[7] = mem.readIntLE(u32, key[28..32]);
k[0] = mem.readIntSliceLittle(u32, key[0..4]);
k[1] = mem.readIntSliceLittle(u32, key[4..8]);
k[2] = mem.readIntSliceLittle(u32, key[8..12]);
k[3] = mem.readIntSliceLittle(u32, key[12..16]);
k[4] = mem.readIntSliceLittle(u32, key[16..20]);
k[5] = mem.readIntSliceLittle(u32, key[20..24]);
k[6] = mem.readIntSliceLittle(u32, key[24..28]);
k[7] = mem.readIntSliceLittle(u32, key[28..32]);
c[0] = @truncate(u32, counter);
c[1] = @truncate(u32, counter >> 32);
c[2] = mem.readIntLE(u32, nonce[0..4]);
c[3] = mem.readIntLE(u32, nonce[4..8]);
c[2] = mem.readIntSliceLittle(u32, nonce[0..4]);
c[3] = mem.readIntSliceLittle(u32, nonce[4..8]);
const block_size = (1 << 6);
const big_block = (block_size << 32);

View File

@ -112,7 +112,8 @@ pub const Md5 = struct {
d.round(d.buf[0..]);
for (d.s) |s, j| {
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u32, out[4 * j .. 4 * j + 4], s);
}
}

View File

@ -6,8 +6,8 @@ const std = @import("../index.zig");
const builtin = @import("builtin");
const Endian = builtin.Endian;
const readInt = std.mem.readInt;
const writeInt = std.mem.writeInt;
const readIntSliceLittle = std.mem.readIntSliceLittle;
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
pub const Poly1305 = struct {
const Self = @This();
@ -59,19 +59,19 @@ pub const Poly1305 = struct {
{
var i: usize = 0;
while (i < 1) : (i += 1) {
ctx.r[0] = readInt(key[0..4], u32, Endian.Little) & 0x0fffffff;
ctx.r[0] = readIntSliceLittle(u32, key[0..4]) & 0x0fffffff;
}
}
{
var i: usize = 1;
while (i < 4) : (i += 1) {
ctx.r[i] = readInt(key[i * 4 .. i * 4 + 4], u32, Endian.Little) & 0x0ffffffc;
ctx.r[i] = readIntSliceLittle(u32, key[i * 4 .. i * 4 + 4]) & 0x0ffffffc;
}
}
{
var i: usize = 0;
while (i < 4) : (i += 1) {
ctx.pad[i] = readInt(key[i * 4 + 16 .. i * 4 + 16 + 4], u32, Endian.Little);
ctx.pad[i] = readIntSliceLittle(u32, key[i * 4 + 16 .. i * 4 + 16 + 4]);
}
}
@ -168,10 +168,10 @@ pub const Poly1305 = struct {
const nb_blocks = nmsg.len >> 4;
var i: usize = 0;
while (i < nb_blocks) : (i += 1) {
ctx.c[0] = readInt(nmsg[0..4], u32, Endian.Little);
ctx.c[1] = readInt(nmsg[4..8], u32, Endian.Little);
ctx.c[2] = readInt(nmsg[8..12], u32, Endian.Little);
ctx.c[3] = readInt(nmsg[12..16], u32, Endian.Little);
ctx.c[0] = readIntSliceLittle(u32, nmsg[0..4]);
ctx.c[1] = readIntSliceLittle(u32, nmsg[4..8]);
ctx.c[2] = readIntSliceLittle(u32, nmsg[8..12]);
ctx.c[3] = readIntSliceLittle(u32, nmsg[12..16]);
polyBlock(ctx);
nmsg = nmsg[16..];
}
@ -210,10 +210,11 @@ pub const Poly1305 = struct {
const uu2 = (uu1 >> 32) + ctx.h[2] + ctx.pad[2]; // <= 2_00000000
const uu3 = (uu2 >> 32) + ctx.h[3] + ctx.pad[3]; // <= 2_00000000
writeInt(out[0..], @truncate(u32, uu0), Endian.Little);
writeInt(out[4..], @truncate(u32, uu1), Endian.Little);
writeInt(out[8..], @truncate(u32, uu2), Endian.Little);
writeInt(out[12..], @truncate(u32, uu3), Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
writeIntSliceLittle(u32, out[0..], @truncate(u32, uu0));
writeIntSliceLittle(u32, out[4..], @truncate(u32, uu1));
writeIntSliceLittle(u32, out[8..], @truncate(u32, uu2));
writeIntSliceLittle(u32, out[12..], @truncate(u32, uu3));
ctx.secureZero();
}

View File

@ -109,7 +109,8 @@ pub const Sha1 = struct {
d.round(d.buf[0..]);
for (d.s) |s, j| {
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
}
}

View File

@ -167,7 +167,8 @@ fn Sha2_32(comptime params: Sha2Params32) type {
const rr = d.s[0 .. params.out_len / 32];
for (rr) |s, j| {
mem.writeInt(out[4 * j .. 4 * j + 4], s, builtin.Endian.Big);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceBig(u32, out[4 * j .. 4 * j + 4], s);
}
}
@ -508,7 +509,8 @@ fn Sha2_64(comptime params: Sha2Params64) type {
const rr = d.s[0 .. params.out_len / 64];
for (rr) |s, j| {
mem.writeInt(out[8 * j .. 8 * j + 8], s, builtin.Endian.Big);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceBig(u64, out[8 * j .. 8 * j + 8], s);
}
}

View File

@ -120,7 +120,7 @@ fn keccak_f(comptime F: usize, d: []u8) void {
var c = []const u64{0} ** 5;
for (s) |*r, i| {
r.* = mem.readIntLE(u64, d[8 * i .. 8 * i + 8]);
r.* = mem.readIntSliceLittle(u64, d[8 * i .. 8 * i + 8]);
}
comptime var x: usize = 0;
@ -167,7 +167,8 @@ fn keccak_f(comptime F: usize, d: []u8) void {
}
for (s) |r, i| {
mem.writeInt(d[8 * i .. 8 * i + 8], r, builtin.Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
mem.writeIntSliceLittle(u64, d[8 * i .. 8 * i + 8], r);
}
}

View File

@ -7,8 +7,8 @@ const builtin = @import("builtin");
const fmt = std.fmt;
const Endian = builtin.Endian;
const readInt = std.mem.readInt;
const writeInt = std.mem.writeInt;
const readIntSliceLittle = std.mem.readIntSliceLittle;
const writeIntSliceLittle = std.mem.writeIntSliceLittle;
// Based on Supercop's ref10 implementation.
pub const X25519 = struct {
@ -255,16 +255,16 @@ const Fe = struct {
var t: [10]i64 = undefined;
t[0] = readInt(s[0..4], u32, Endian.Little);
t[1] = readInt(s[4..7], u32, Endian.Little) << 6;
t[2] = readInt(s[7..10], u32, Endian.Little) << 5;
t[3] = readInt(s[10..13], u32, Endian.Little) << 3;
t[4] = readInt(s[13..16], u32, Endian.Little) << 2;
t[5] = readInt(s[16..20], u32, Endian.Little);
t[6] = readInt(s[20..23], u32, Endian.Little) << 7;
t[7] = readInt(s[23..26], u32, Endian.Little) << 5;
t[8] = readInt(s[26..29], u32, Endian.Little) << 4;
t[9] = (readInt(s[29..32], u32, Endian.Little) & 0x7fffff) << 2;
t[0] = readIntSliceLittle(u32, s[0..4]);
t[1] = u32(readIntSliceLittle(u24, s[4..7])) << 6;
t[2] = u32(readIntSliceLittle(u24, s[7..10])) << 5;
t[3] = u32(readIntSliceLittle(u24, s[10..13])) << 3;
t[4] = u32(readIntSliceLittle(u24, s[13..16])) << 2;
t[5] = readIntSliceLittle(u32, s[16..20]);
t[6] = u32(readIntSliceLittle(u24, s[20..23])) << 7;
t[7] = u32(readIntSliceLittle(u24, s[23..26])) << 5;
t[8] = u32(readIntSliceLittle(u24, s[26..29])) << 4;
t[9] = (u32(readIntSliceLittle(u24, s[29..32])) & 0x7fffff) << 2;
carry1(h, t[0..]);
}
@ -544,14 +544,15 @@ const Fe = struct {
ut[i] = @bitCast(u32, @intCast(i32, t[i]));
}
writeInt(s[0..], (ut[0] >> 0) | (ut[1] << 26), Endian.Little);
writeInt(s[4..], (ut[1] >> 6) | (ut[2] << 19), Endian.Little);
writeInt(s[8..], (ut[2] >> 13) | (ut[3] << 13), Endian.Little);
writeInt(s[12..], (ut[3] >> 19) | (ut[4] << 6), Endian.Little);
writeInt(s[16..], (ut[5] >> 0) | (ut[6] << 25), Endian.Little);
writeInt(s[20..], (ut[6] >> 7) | (ut[7] << 19), Endian.Little);
writeInt(s[24..], (ut[7] >> 13) | (ut[8] << 12), Endian.Little);
writeInt(s[28..], (ut[8] >> 20) | (ut[9] << 6), Endian.Little);
// TODO https://github.com/ziglang/zig/issues/863
writeIntSliceLittle(u32, s[0..4], (ut[0] >> 0) | (ut[1] << 26));
writeIntSliceLittle(u32, s[4..8], (ut[1] >> 6) | (ut[2] << 19));
writeIntSliceLittle(u32, s[8..12], (ut[2] >> 13) | (ut[3] << 13));
writeIntSliceLittle(u32, s[12..16], (ut[3] >> 19) | (ut[4] << 6));
writeIntSliceLittle(u32, s[16..20], (ut[5] >> 0) | (ut[6] << 25));
writeIntSliceLittle(u32, s[20..24], (ut[6] >> 7) | (ut[7] << 19));
writeIntSliceLittle(u32, s[24..28], (ut[7] >> 13) | (ut[8] << 12));
writeIntSliceLittle(u32, s[28..], (ut[8] >> 20) | (ut[9] << 6));
std.mem.secureZero(i64, t[0..]);
}

View File

@ -198,49 +198,44 @@ pub fn writeStackTrace(stack_trace: *const builtin.StackTrace, out_stream: var,
}
}
pub inline fn getReturnAddress(frame_count: usize) usize {
var fp = @ptrToInt(@frameAddress());
var i: usize = 0;
while (fp != 0 and i < frame_count) {
fp = @intToPtr(*const usize, fp).*;
i += 1;
pub const StackIterator = struct {
first_addr: ?usize,
fp: usize,
pub fn init(first_addr: ?usize) StackIterator {
return StackIterator{
.first_addr = first_addr,
.fp = @ptrToInt(@frameAddress()),
};
}
return @intToPtr(*const usize, fp + @sizeOf(usize)).*;
}
fn next(self: *StackIterator) ?usize {
if (self.fp == 0) return null;
self.fp = @intToPtr(*const usize, self.fp).*;
if (self.fp == 0) return null;
if (self.first_addr) |addr| {
while (self.fp != 0) : (self.fp = @intToPtr(*const usize, self.fp).*) {
const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
if (addr == return_address) {
self.first_addr = null;
return return_address;
}
}
}
const return_address = @intToPtr(*const usize, self.fp + @sizeOf(usize)).*;
return return_address;
}
};
pub fn writeCurrentStackTrace(out_stream: var, debug_info: *DebugInfo, tty_color: bool, start_addr: ?usize) !void {
switch (builtin.os) {
builtin.Os.windows => return writeCurrentStackTraceWindows(out_stream, debug_info, tty_color, start_addr),
else => {},
}
const AddressState = union(enum) {
NotLookingForStartAddress,
LookingForStartAddress: usize,
};
// TODO: I want to express like this:
//var addr_state = if (start_addr) |addr| AddressState { .LookingForStartAddress = addr }
// else AddressState.NotLookingForStartAddress;
var addr_state: AddressState = undefined;
if (start_addr) |addr| {
addr_state = AddressState{ .LookingForStartAddress = addr };
} else {
addr_state = AddressState.NotLookingForStartAddress;
}
var fp = @ptrToInt(@frameAddress());
while (fp != 0) : (fp = @intToPtr(*const usize, fp).*) {
const return_address = @intToPtr(*const usize, fp + @sizeOf(usize)).*;
switch (addr_state) {
AddressState.NotLookingForStartAddress => {},
AddressState.LookingForStartAddress => |addr| {
if (return_address == addr) {
addr_state = AddressState.NotLookingForStartAddress;
} else {
continue;
}
},
}
var it = StackIterator.init(start_addr);
while (it.next()) |return_address| {
try printSourceAtAddress(debug_info, out_stream, return_address, tty_color);
}
}
@ -282,8 +277,9 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
var coff_section: *coff.Section = undefined;
const mod_index = for (di.sect_contribs) |sect_contrib| {
if (sect_contrib.Section >= di.coff.sections.len) continue;
coff_section = &di.coff.sections.toSlice()[sect_contrib.Section];
if (sect_contrib.Section > di.coff.sections.len) continue;
// Remember that SectionContribEntry.Section is 1-based.
coff_section = &di.coff.sections.toSlice()[sect_contrib.Section - 1];
const vaddr_start = coff_section.header.virtual_address + sect_contrib.Offset;
const vaddr_end = vaddr_start + sect_contrib.Size;
@ -413,7 +409,7 @@ fn printSourceAtAddressWindows(di: *DebugInfo, out_stream: var, relocated_addres
if (opt_line_info) |line_info| {
try out_stream.print("\n");
if (printLineFromFile(out_stream, line_info)) {
if (printLineFromFileAnyOs(out_stream, line_info)) {
if (line_info.column == 0) {
try out_stream.write("\n");
} else {
@ -527,7 +523,7 @@ fn populateModule(di: *DebugInfo, mod: *Module) !void {
const modi = di.pdb.getStreamById(mod.mod_info.ModuleSymStream) orelse return error.MissingDebugInfo;
const signature = try modi.stream.readIntLe(u32);
const signature = try modi.stream.readIntLittle(u32);
if (signature != 4)
return error.InvalidDebugInfo;
@ -597,7 +593,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
} else "???";
if (getLineNumberInfoMacOs(di, symbol.*, adjusted_addr)) |line_info| {
defer line_info.deinit();
try printLineInfo(di, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color);
try printLineInfo(
out_stream,
line_info,
address,
symbol_name,
compile_unit_name,
tty_color,
printLineFromFileAnyOs,
);
} else |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
if (tty_color) {
@ -610,7 +614,15 @@ fn printSourceAtAddressMacOs(di: *DebugInfo, out_stream: var, address: usize, tt
}
}
pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
/// This function works in freestanding mode.
/// fn printLineFromFile(out_stream: var, line_info: LineInfo) !void
pub fn printSourceAtAddressDwarf(
debug_info: *DwarfInfo,
out_stream: var,
address: usize,
tty_color: bool,
comptime printLineFromFile: var,
) !void {
const compile_unit = findCompileUnit(debug_info, address) catch {
if (tty_color) {
try out_stream.print("???:?:?: " ++ DIM ++ "0x{x} in ??? (???)" ++ RESET ++ "\n\n\n", address);
@ -620,10 +632,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres
return;
};
const compile_unit_name = try compile_unit.die.getAttrString(debug_info, DW.AT_name);
if (getLineNumberInfoLinux(debug_info, compile_unit, address - 1)) |line_info| {
if (getLineNumberInfoDwarf(debug_info, compile_unit.*, address - 1)) |line_info| {
defer line_info.deinit();
const symbol_name = "???";
try printLineInfo(debug_info, out_stream, line_info, address, symbol_name, compile_unit_name, tty_color);
try printLineInfo(
out_stream,
line_info,
address,
symbol_name,
compile_unit_name,
tty_color,
printLineFromFile,
);
} else |err| switch (err) {
error.MissingDebugInfo, error.InvalidDebugInfo => {
if (tty_color) {
@ -636,14 +656,18 @@ pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, addres
}
}
pub fn printSourceAtAddressLinux(debug_info: *DebugInfo, out_stream: var, address: usize, tty_color: bool) !void {
return printSourceAtAddressDwarf(debug_info, out_stream, address, tty_color, printLineFromFileAnyOs);
}
fn printLineInfo(
debug_info: *DebugInfo,
out_stream: var,
line_info: LineInfo,
address: usize,
symbol_name: []const u8,
compile_unit_name: []const u8,
tty_color: bool,
comptime printLineFromFile: var,
) !void {
if (tty_color) {
try out_stream.print(
@ -733,9 +757,9 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
try di.pdb.openFile(di.coff, path);
var pdb_stream = di.pdb.getStream(pdb.StreamType.Pdb) orelse return error.InvalidDebugInfo;
const version = try pdb_stream.stream.readIntLe(u32);
const signature = try pdb_stream.stream.readIntLe(u32);
const age = try pdb_stream.stream.readIntLe(u32);
const version = try pdb_stream.stream.readIntLittle(u32);
const signature = try pdb_stream.stream.readIntLittle(u32);
const age = try pdb_stream.stream.readIntLittle(u32);
var guid: [16]u8 = undefined;
try pdb_stream.stream.readNoEof(guid[0..]);
if (!mem.eql(u8, di.coff.guid, guid) or di.coff.age != age)
@ -743,7 +767,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
// We validated the executable and pdb match.
const string_table_index = str_tab_index: {
const name_bytes_len = try pdb_stream.stream.readIntLe(u32);
const name_bytes_len = try pdb_stream.stream.readIntLittle(u32);
const name_bytes = try allocator.alloc(u8, name_bytes_len);
try pdb_stream.stream.readNoEof(name_bytes);
@ -773,8 +797,8 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
};
const bucket_list = try allocator.alloc(Bucket, present.len);
for (present) |_| {
const name_offset = try pdb_stream.stream.readIntLe(u32);
const name_index = try pdb_stream.stream.readIntLe(u32);
const name_offset = try pdb_stream.stream.readIntLittle(u32);
const name_index = try pdb_stream.stream.readIntLittle(u32);
const name = mem.toSlice(u8, name_bytes.ptr + name_offset);
if (mem.eql(u8, name, "/names")) {
break :str_tab_index name_index;
@ -835,7 +859,7 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
var sect_contribs = ArrayList(pdb.SectionContribEntry).init(allocator);
var sect_cont_offset: usize = 0;
if (section_contrib_size != 0) {
const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLe(u32));
const ver = @intToEnum(pdb.SectionContrSubstreamVersion, try dbi.stream.readIntLittle(u32));
if (ver != pdb.SectionContrSubstreamVersion.Ver60)
return error.InvalidDebugInfo;
sect_cont_offset += @sizeOf(u32);
@ -855,11 +879,11 @@ fn openSelfDebugInfoWindows(allocator: *mem.Allocator) !DebugInfo {
}
fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
const num_words = try stream.readIntLe(u32);
const num_words = try stream.readIntLittle(u32);
var word_i: usize = 0;
var list = ArrayList(usize).init(allocator);
while (word_i != num_words) : (word_i += 1) {
const word = try stream.readIntLe(u32);
const word = try stream.readIntLittle(u32);
var bit_i: u5 = 0;
while (true) : (bit_i += 1) {
if (word & (u32(1) << bit_i) != 0) {
@ -871,55 +895,68 @@ fn readSparseBitVector(stream: var, allocator: *mem.Allocator) ![]usize {
return list.toOwnedSlice();
}
fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DebugInfo {
var di = DebugInfo{
.self_exe_file = undefined,
.elf = undefined,
.debug_info = undefined,
.debug_abbrev = undefined,
.debug_str = undefined,
.debug_line = undefined,
.debug_ranges = null,
.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator),
.compile_unit_list = ArrayList(CompileUnit).init(allocator),
fn findDwarfSectionFromElf(elf_file: *elf.Elf, name: []const u8) !?DwarfInfo.Section {
const elf_header = (try elf_file.findSection(name)) orelse return null;
return DwarfInfo.Section{
.offset = elf_header.offset,
.size = elf_header.size,
};
di.self_exe_file = try os.openSelfExe();
errdefer di.self_exe_file.close();
}
try di.elf.openFile(allocator, di.self_exe_file);
errdefer di.elf.close();
/// Initialize DWARF info. The caller has the responsibility to initialize most
/// the DwarfInfo fields before calling. These fields can be left undefined:
/// * abbrev_table_list
/// * compile_unit_list
pub fn openDwarfDebugInfo(di: *DwarfInfo, allocator: *mem.Allocator) !void {
di.abbrev_table_list = ArrayList(AbbrevTableHeader).init(allocator);
di.compile_unit_list = ArrayList(CompileUnit).init(allocator);
try scanAllCompileUnits(di);
}
di.debug_info = (try di.elf.findSection(".debug_info")) orelse return error.MissingDebugInfo;
di.debug_abbrev = (try di.elf.findSection(".debug_abbrev")) orelse return error.MissingDebugInfo;
di.debug_str = (try di.elf.findSection(".debug_str")) orelse return error.MissingDebugInfo;
di.debug_line = (try di.elf.findSection(".debug_line")) orelse return error.MissingDebugInfo;
di.debug_ranges = (try di.elf.findSection(".debug_ranges"));
try scanAllCompileUnits(&di);
pub fn openElfDebugInfo(
allocator: *mem.Allocator,
elf_seekable_stream: *DwarfSeekableStream,
elf_in_stream: *DwarfInStream,
) !DwarfInfo {
var efile: elf.Elf = undefined;
try efile.openStream(allocator, elf_seekable_stream, elf_in_stream);
errdefer efile.close();
var di = DwarfInfo{
.dwarf_seekable_stream = elf_seekable_stream,
.dwarf_in_stream = elf_in_stream,
.endian = efile.endian,
.debug_info = (try findDwarfSectionFromElf(&efile, ".debug_info")) orelse return error.MissingDebugInfo,
.debug_abbrev = (try findDwarfSectionFromElf(&efile, ".debug_abbrev")) orelse return error.MissingDebugInfo,
.debug_str = (try findDwarfSectionFromElf(&efile, ".debug_str")) orelse return error.MissingDebugInfo,
.debug_line = (try findDwarfSectionFromElf(&efile, ".debug_line")) orelse return error.MissingDebugInfo,
.debug_ranges = (try findDwarfSectionFromElf(&efile, ".debug_ranges")),
.abbrev_table_list = undefined,
.compile_unit_list = undefined,
};
try openDwarfDebugInfo(&di, allocator);
return di;
}
pub fn findElfSection(elf: *Elf, name: []const u8) ?*elf.Shdr {
var file_stream = elf.in_file.inStream();
const in = &file_stream.stream;
fn openSelfDebugInfoLinux(allocator: *mem.Allocator) !DwarfInfo {
const S = struct {
var self_exe_file: os.File = undefined;
var self_exe_seekable_stream: os.File.SeekableStream = undefined;
var self_exe_in_stream: os.File.InStream = undefined;
};
S.self_exe_file = try os.openSelfExe();
errdefer S.self_exe_file.close();
section_loop: for (elf.section_headers) |*elf_section| {
if (elf_section.sh_type == SHT_NULL) continue;
S.self_exe_seekable_stream = S.self_exe_file.seekableStream();
S.self_exe_in_stream = S.self_exe_file.inStream();
const name_offset = elf.string_section.offset + elf_section.name;
try elf.in_file.seekTo(name_offset);
for (name) |expected_c| {
const target_c = try in.readByte();
if (target_c == 0 or expected_c != target_c) continue :section_loop;
}
{
const null_byte = try in.readByte();
if (null_byte == 0) return elf_section;
}
}
return null;
return openElfDebugInfo(
allocator,
// TODO https://github.com/ziglang/zig/issues/764
@ptrCast(*DwarfSeekableStream, &S.self_exe_seekable_stream.stream),
// TODO https://github.com/ziglang/zig/issues/764
@ptrCast(*DwarfInStream, &S.self_exe_in_stream.stream),
);
}
fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
@ -999,7 +1036,7 @@ fn openSelfDebugInfoMacOs(allocator: *mem.Allocator) !DebugInfo {
};
}
fn printLineFromFile(out_stream: var, line_info: LineInfo) !void {
fn printLineFromFileAnyOs(out_stream: var, line_info: LineInfo) !void {
var f = try os.File.openRead(line_info.file_name);
defer f.close();
// TODO fstat and make sure that the file has the correct size
@ -1052,6 +1089,35 @@ const MachOFile = struct {
sect_debug_line: ?*const macho.section_64,
};
pub const DwarfSeekableStream = io.SeekableStream(anyerror, anyerror);
pub const DwarfInStream = io.InStream(anyerror);
pub const DwarfInfo = struct {
dwarf_seekable_stream: *DwarfSeekableStream,
dwarf_in_stream: *DwarfInStream,
endian: builtin.Endian,
debug_info: Section,
debug_abbrev: Section,
debug_str: Section,
debug_line: Section,
debug_ranges: ?Section,
abbrev_table_list: ArrayList(AbbrevTableHeader),
compile_unit_list: ArrayList(CompileUnit),
pub const Section = struct {
offset: usize,
size: usize,
};
pub fn allocator(self: DwarfInfo) *mem.Allocator {
return self.abbrev_table_list.allocator;
}
pub fn readString(self: *DwarfInfo) ![]u8 {
return readStringRaw(self.allocator(), self.dwarf_in_stream);
}
};
pub const DebugInfo = switch (builtin.os) {
builtin.Os.macosx => struct {
symbols: []const MachoSymbol,
@ -1075,32 +1141,8 @@ pub const DebugInfo = switch (builtin.os) {
sect_contribs: []pdb.SectionContribEntry,
modules: []Module,
},
builtin.Os.linux => struct {
self_exe_file: os.File,
elf: elf.Elf,
debug_info: *elf.SectionHeader,
debug_abbrev: *elf.SectionHeader,
debug_str: *elf.SectionHeader,
debug_line: *elf.SectionHeader,
debug_ranges: ?*elf.SectionHeader,
abbrev_table_list: ArrayList(AbbrevTableHeader),
compile_unit_list: ArrayList(CompileUnit),
pub fn allocator(self: DebugInfo) *mem.Allocator {
return self.abbrev_table_list.allocator;
}
pub fn readString(self: *DebugInfo) ![]u8 {
var in_file_stream = self.self_exe_file.inStream();
const in_stream = &in_file_stream.stream;
return readStringRaw(self.allocator(), in_stream);
}
pub fn close(self: *DebugInfo) void {
self.self_exe_file.close();
self.elf.close();
}
},
builtin.Os.linux => DwarfInfo,
builtin.Os.freebsd => struct {},
else => @compileError("Unsupported OS"),
};
@ -1158,7 +1200,7 @@ const Constant = struct {
fn asUnsignedLe(self: *const Constant) !u64 {
if (self.payload.len > @sizeOf(u64)) return error.InvalidDebugInfo;
if (self.signed) return error.InvalidDebugInfo;
return mem.readInt(self.payload, u64, builtin.Endian.Little);
return mem.readVarInt(u64, self.payload, builtin.Endian.Little);
}
};
@ -1204,11 +1246,11 @@ const Die = struct {
};
}
fn getAttrString(self: *const Die, st: *DebugInfo, id: u64) ![]u8 {
fn getAttrString(self: *const Die, di: *DwarfInfo, id: u64) ![]u8 {
const form_value = self.getAttr(id) orelse return error.MissingDebugInfo;
return switch (form_value.*) {
FormValue.String => |value| value,
FormValue.StrPtr => |offset| getString(st, offset),
FormValue.StrPtr => |offset| getString(di, offset),
else => error.InvalidDebugInfo,
};
}
@ -1221,14 +1263,15 @@ const FileEntry = struct {
len_bytes: usize,
};
const LineInfo = struct {
pub const LineInfo = struct {
line: usize,
column: usize,
file_name: []u8,
allocator: *mem.Allocator,
file_name: []const u8,
allocator: ?*mem.Allocator,
fn deinit(self: *const LineInfo) void {
self.allocator.free(self.file_name);
fn deinit(self: LineInfo) void {
const allocator = self.allocator orelse return;
allocator.free(self.file_name);
}
};
@ -1319,10 +1362,10 @@ fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
return buf.toSlice();
}
fn getString(st: *DebugInfo, offset: u64) ![]u8 {
const pos = st.debug_str.offset + offset;
try st.self_exe_file.seekTo(pos);
return st.readString();
fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
const pos = di.debug_str.offset + offset;
try di.dwarf_seekable_stream.seekTo(pos);
return di.readString();
}
fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
@ -1338,7 +1381,7 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize
}
fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
const block_len = try in_stream.readVarInt(builtin.Endian.Little, usize, size);
const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);
return parseFormValueBlockLen(allocator, in_stream, block_len);
}
@ -1352,11 +1395,11 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
}
fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
return if (is_64) try in_stream.readIntLe(u64) else u64(try in_stream.readIntLe(u32));
return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));
}
fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLe(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLe(u64) else unreachable;
return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;
}
fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
@ -1365,18 +1408,11 @@ fn parseFormValueRefLen(allocator: *mem.Allocator, in_stream: var, size: usize)
}
fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, comptime T: type) !FormValue {
const block_len = try in_stream.readIntLe(T);
const block_len = try in_stream.readIntLittle(T);
return parseFormValueRefLen(allocator, in_stream, block_len);
}
const ParseFormValueError = error{
EndOfStream,
InvalidDebugInfo,
EndOfFile,
OutOfMemory,
} || std.os.File.ReadError;
fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) ParseFormValueError!FormValue {
fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
return switch (form_id) {
DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
DW.FORM_block1 => parseFormValueBlock(allocator, in_stream, 1),
@ -1414,7 +1450,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
},
DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLe(u64) },
DW.FORM_ref_sig8 => FormValue{ .RefSig8 = try in_stream.readIntLittle(u64) },
DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
@ -1426,25 +1462,22 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
};
}
fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
const in_file = st.self_exe_file;
var in_file_stream = in_file.inStream();
const in_stream = &in_file_stream.stream;
var result = AbbrevTable.init(st.allocator());
fn parseAbbrevTable(di: *DwarfInfo) !AbbrevTable {
var result = AbbrevTable.init(di.allocator());
while (true) {
const abbrev_code = try readULeb128(in_stream);
const abbrev_code = try readULeb128(di.dwarf_in_stream);
if (abbrev_code == 0) return result;
try result.append(AbbrevTableEntry{
.abbrev_code = abbrev_code,
.tag_id = try readULeb128(in_stream),
.has_children = (try in_stream.readByte()) == DW.CHILDREN_yes,
.attrs = ArrayList(AbbrevAttr).init(st.allocator()),
.tag_id = try readULeb128(di.dwarf_in_stream),
.has_children = (try di.dwarf_in_stream.readByte()) == DW.CHILDREN_yes,
.attrs = ArrayList(AbbrevAttr).init(di.allocator()),
});
const attrs = &result.items[result.len - 1].attrs;
while (true) {
const attr_id = try readULeb128(in_stream);
const form_id = try readULeb128(in_stream);
const attr_id = try readULeb128(di.dwarf_in_stream);
const form_id = try readULeb128(di.dwarf_in_stream);
if (attr_id == 0 and form_id == 0) break;
try attrs.append(AbbrevAttr{
.attr_id = attr_id,
@ -1456,18 +1489,18 @@ fn parseAbbrevTable(st: *DebugInfo) !AbbrevTable {
/// Gets an already existing AbbrevTable given the abbrev_offset, or if not found,
/// seeks in the stream and parses it.
fn getAbbrevTable(st: *DebugInfo, abbrev_offset: u64) !*const AbbrevTable {
for (st.abbrev_table_list.toSlice()) |*header| {
fn getAbbrevTable(di: *DwarfInfo, abbrev_offset: u64) !*const AbbrevTable {
for (di.abbrev_table_list.toSlice()) |*header| {
if (header.offset == abbrev_offset) {
return &header.table;
}
}
try st.self_exe_file.seekTo(st.debug_abbrev.offset + abbrev_offset);
try st.abbrev_table_list.append(AbbrevTableHeader{
try di.dwarf_seekable_stream.seekTo(di.debug_abbrev.offset + abbrev_offset);
try di.abbrev_table_list.append(AbbrevTableHeader{
.offset = abbrev_offset,
.table = try parseAbbrevTable(st),
.table = try parseAbbrevTable(di),
});
return &st.abbrev_table_list.items[st.abbrev_table_list.len - 1].table;
return &di.abbrev_table_list.items[di.abbrev_table_list.len - 1].table;
}
fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*const AbbrevTableEntry {
@ -1477,23 +1510,20 @@ fn getAbbrevTableEntry(abbrev_table: *const AbbrevTable, abbrev_code: u64) ?*con
return null;
}
fn parseDie(st: *DebugInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
const in_file = st.self_exe_file;
var in_file_stream = in_file.inStream();
const in_stream = &in_file_stream.stream;
const abbrev_code = try readULeb128(in_stream);
fn parseDie(di: *DwarfInfo, abbrev_table: *const AbbrevTable, is_64: bool) !Die {
const abbrev_code = try readULeb128(di.dwarf_in_stream);
const table_entry = getAbbrevTableEntry(abbrev_table, abbrev_code) orelse return error.InvalidDebugInfo;
var result = Die{
.tag_id = table_entry.tag_id,
.has_children = table_entry.has_children,
.attrs = ArrayList(Die.Attr).init(st.allocator()),
.attrs = ArrayList(Die.Attr).init(di.allocator()),
};
try result.attrs.resize(table_entry.attrs.len);
for (table_entry.attrs.toSliceConst()) |attr, i| {
result.attrs.items[i] = Die.Attr{
.id = attr.attr_id,
.value = try parseFormValue(st.allocator(), in_stream, attr.form_id, is_64),
.value = try parseFormValue(di.allocator(), di.dwarf_in_stream, attr.form_id, is_64),
};
}
return result;
@ -1697,22 +1727,18 @@ fn getLineNumberInfoMacOs(di: *DebugInfo, symbol: MachoSymbol, target_address: u
return error.MissingDebugInfo;
}
fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, target_address: usize) !LineInfo {
fn getLineNumberInfoDwarf(di: *DwarfInfo, compile_unit: CompileUnit, target_address: usize) !LineInfo {
const compile_unit_cwd = try compile_unit.die.getAttrString(di, DW.AT_comp_dir);
const in_file = di.self_exe_file;
const debug_line_end = di.debug_line.offset + di.debug_line.size;
var this_offset = di.debug_line.offset;
var this_index: usize = 0;
var in_file_stream = in_file.inStream();
const in_stream = &in_file_stream.stream;
while (this_offset < debug_line_end) : (this_index += 1) {
try in_file.seekTo(this_offset);
try di.dwarf_seekable_stream.seekTo(this_offset);
var is_64: bool = undefined;
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
if (unit_length == 0) return error.MissingDebugInfo;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
@ -1721,35 +1747,35 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
continue;
}
const version = try in_stream.readInt(di.elf.endian, u16);
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
// TODO support 3 and 5
if (version != 2 and version != 4) return error.InvalidDebugInfo;
const prologue_length = if (is_64) try in_stream.readInt(di.elf.endian, u64) else try in_stream.readInt(di.elf.endian, u32);
const prog_start_offset = (try in_file.getPos()) + prologue_length;
const prologue_length = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
const prog_start_offset = (try di.dwarf_seekable_stream.getPos()) + prologue_length;
const minimum_instruction_length = try in_stream.readByte();
const minimum_instruction_length = try di.dwarf_in_stream.readByte();
if (minimum_instruction_length == 0) return error.InvalidDebugInfo;
if (version >= 4) {
// maximum_operations_per_instruction
_ = try in_stream.readByte();
_ = try di.dwarf_in_stream.readByte();
}
const default_is_stmt = (try in_stream.readByte()) != 0;
const line_base = try in_stream.readByteSigned();
const default_is_stmt = (try di.dwarf_in_stream.readByte()) != 0;
const line_base = try di.dwarf_in_stream.readByteSigned();
const line_range = try in_stream.readByte();
const line_range = try di.dwarf_in_stream.readByte();
if (line_range == 0) return error.InvalidDebugInfo;
const opcode_base = try in_stream.readByte();
const opcode_base = try di.dwarf_in_stream.readByte();
const standard_opcode_lengths = try di.allocator().alloc(u8, opcode_base - 1);
{
var i: usize = 0;
while (i < opcode_base - 1) : (i += 1) {
standard_opcode_lengths[i] = try in_stream.readByte();
standard_opcode_lengths[i] = try di.dwarf_in_stream.readByte();
}
}
@ -1767,9 +1793,9 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
while (true) {
const file_name = try di.readString();
if (file_name.len == 0) break;
const dir_index = try readULeb128(in_stream);
const mtime = try readULeb128(in_stream);
const len_bytes = try readULeb128(in_stream);
const dir_index = try readULeb128(di.dwarf_in_stream);
const mtime = try readULeb128(di.dwarf_in_stream);
const len_bytes = try readULeb128(di.dwarf_in_stream);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@ -1778,15 +1804,15 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
});
}
try in_file.seekTo(prog_start_offset);
try di.dwarf_seekable_stream.seekTo(prog_start_offset);
while (true) {
const opcode = try in_stream.readByte();
const opcode = try di.dwarf_in_stream.readByte();
if (opcode == DW.LNS_extended_op) {
const op_size = try readULeb128(in_stream);
const op_size = try readULeb128(di.dwarf_in_stream);
if (op_size < 1) return error.InvalidDebugInfo;
var sub_op = try in_stream.readByte();
var sub_op = try di.dwarf_in_stream.readByte();
switch (sub_op) {
DW.LNE_end_sequence => {
prog.end_sequence = true;
@ -1794,14 +1820,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
return error.MissingDebugInfo;
},
DW.LNE_set_address => {
const addr = try in_stream.readInt(di.elf.endian, usize);
const addr = try di.dwarf_in_stream.readInt(usize, di.endian);
prog.address = addr;
},
DW.LNE_define_file => {
const file_name = try di.readString();
const dir_index = try readULeb128(in_stream);
const mtime = try readULeb128(in_stream);
const len_bytes = try readULeb128(in_stream);
const dir_index = try readULeb128(di.dwarf_in_stream);
const mtime = try readULeb128(di.dwarf_in_stream);
const len_bytes = try readULeb128(di.dwarf_in_stream);
try file_entries.append(FileEntry{
.file_name = file_name,
.dir_index = dir_index,
@ -1811,7 +1837,7 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
},
else => {
const fwd_amt = math.cast(isize, op_size - 1) catch return error.InvalidDebugInfo;
try in_file.seekForward(fwd_amt);
try di.dwarf_seekable_stream.seekForward(fwd_amt);
},
}
} else if (opcode >= opcode_base) {
@ -1830,19 +1856,19 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
prog.basic_block = false;
},
DW.LNS_advance_pc => {
const arg = try readULeb128(in_stream);
const arg = try readULeb128(di.dwarf_in_stream);
prog.address += arg * minimum_instruction_length;
},
DW.LNS_advance_line => {
const arg = try readILeb128(in_stream);
const arg = try readILeb128(di.dwarf_in_stream);
prog.line += arg;
},
DW.LNS_set_file => {
const arg = try readULeb128(in_stream);
const arg = try readULeb128(di.dwarf_in_stream);
prog.file = arg;
},
DW.LNS_set_column => {
const arg = try readULeb128(in_stream);
const arg = try readULeb128(di.dwarf_in_stream);
prog.column = arg;
},
DW.LNS_negate_stmt => {
@ -1856,14 +1882,14 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
prog.address += inc_addr;
},
DW.LNS_fixed_advance_pc => {
const arg = try in_stream.readInt(di.elf.endian, u16);
const arg = try di.dwarf_in_stream.readInt(u16, di.endian);
prog.address += arg;
},
DW.LNS_set_prologue_end => {},
else => {
if (opcode - 1 >= standard_opcode_lengths.len) return error.InvalidDebugInfo;
const len_bytes = standard_opcode_lengths[opcode - 1];
try in_file.seekForward(len_bytes);
try di.dwarf_seekable_stream.seekForward(len_bytes);
},
}
}
@ -1875,36 +1901,33 @@ fn getLineNumberInfoLinux(di: *DebugInfo, compile_unit: *const CompileUnit, targ
return error.MissingDebugInfo;
}
fn scanAllCompileUnits(st: *DebugInfo) !void {
const debug_info_end = st.debug_info.offset + st.debug_info.size;
var this_unit_offset = st.debug_info.offset;
fn scanAllCompileUnits(di: *DwarfInfo) !void {
const debug_info_end = di.debug_info.offset + di.debug_info.size;
var this_unit_offset = di.debug_info.offset;
var cu_index: usize = 0;
var in_file_stream = st.self_exe_file.inStream();
const in_stream = &in_file_stream.stream;
while (this_unit_offset < debug_info_end) {
try st.self_exe_file.seekTo(this_unit_offset);
try di.dwarf_seekable_stream.seekTo(this_unit_offset);
var is_64: bool = undefined;
const unit_length = try readInitialLength(@typeOf(in_stream.readFn).ReturnType.ErrorSet, in_stream, &is_64);
const unit_length = try readInitialLength(@typeOf(di.dwarf_in_stream.readFn).ReturnType.ErrorSet, di.dwarf_in_stream, &is_64);
if (unit_length == 0) return;
const next_offset = unit_length + (if (is_64) usize(12) else usize(4));
const version = try in_stream.readInt(st.elf.endian, u16);
const version = try di.dwarf_in_stream.readInt(u16, di.endian);
if (version < 2 or version > 5) return error.InvalidDebugInfo;
const debug_abbrev_offset = if (is_64) try in_stream.readInt(st.elf.endian, u64) else try in_stream.readInt(st.elf.endian, u32);
const debug_abbrev_offset = if (is_64) try di.dwarf_in_stream.readInt(u64, di.endian) else try di.dwarf_in_stream.readInt(u32, di.endian);
const address_size = try in_stream.readByte();
const address_size = try di.dwarf_in_stream.readByte();
if (address_size != @sizeOf(usize)) return error.InvalidDebugInfo;
const compile_unit_pos = try st.self_exe_file.getPos();
const abbrev_table = try getAbbrevTable(st, debug_abbrev_offset);
const compile_unit_pos = try di.dwarf_seekable_stream.getPos();
const abbrev_table = try getAbbrevTable(di, debug_abbrev_offset);
try st.self_exe_file.seekTo(compile_unit_pos);
try di.dwarf_seekable_stream.seekTo(compile_unit_pos);
const compile_unit_die = try st.allocator().create(try parseDie(st, abbrev_table, is_64));
const compile_unit_die = try di.allocator().create(try parseDie(di, abbrev_table, is_64));
if (compile_unit_die.tag_id != DW.TAG_compile_unit) return error.InvalidDebugInfo;
@ -1932,7 +1955,7 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
}
};
try st.compile_unit_list.append(CompileUnit{
try di.compile_unit_list.append(CompileUnit{
.version = version,
.is_64 = is_64,
.pc_range = pc_range,
@ -1945,20 +1968,18 @@ fn scanAllCompileUnits(st: *DebugInfo) !void {
}
}
fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
var in_file_stream = st.self_exe_file.inStream();
const in_stream = &in_file_stream.stream;
for (st.compile_unit_list.toSlice()) |*compile_unit| {
fn findCompileUnit(di: *DwarfInfo, target_address: u64) !*const CompileUnit {
for (di.compile_unit_list.toSlice()) |*compile_unit| {
if (compile_unit.pc_range) |range| {
if (target_address >= range.start and target_address < range.end) return compile_unit;
}
if (compile_unit.die.getAttrSecOffset(DW.AT_ranges)) |ranges_offset| {
var base_address: usize = 0;
if (st.debug_ranges) |debug_ranges| {
try st.self_exe_file.seekTo(debug_ranges.offset + ranges_offset);
if (di.debug_ranges) |debug_ranges| {
try di.dwarf_seekable_stream.seekTo(debug_ranges.offset + ranges_offset);
while (true) {
const begin_addr = try in_stream.readIntLe(usize);
const end_addr = try in_stream.readIntLe(usize);
const begin_addr = try di.dwarf_in_stream.readIntLittle(usize);
const end_addr = try di.dwarf_in_stream.readIntLittle(usize);
if (begin_addr == 0 and end_addr == 0) {
break;
}
@ -1980,7 +2001,8 @@ fn findCompileUnit(st: *DebugInfo, target_address: u64) !*const CompileUnit {
}
fn readIntMem(ptr: *[*]const u8, comptime T: type, endian: builtin.Endian) T {
const result = mem.readInt(ptr.*[0..@sizeOf(T)], T, endian);
// TODO https://github.com/ziglang/zig/issues/863
const result = mem.readIntSlice(T, ptr.*[0..@sizeOf(T)], endian);
ptr.* += @sizeOf(T);
return result;
}
@ -1996,11 +2018,12 @@ fn readByteSignedMem(ptr: *[*]const u8) i8 {
}
fn readInitialLengthMem(ptr: *[*]const u8, is_64: *bool) !u64 {
const first_32_bits = mem.readIntLE(u32, ptr.*[0..4]);
// TODO this code can be improved with https://github.com/ziglang/zig/issues/863
const first_32_bits = mem.readIntSliceLittle(u32, ptr.*[0..4]);
is_64.* = (first_32_bits == 0xffffffff);
if (is_64.*) {
ptr.* += 4;
const result = mem.readIntLE(u64, ptr.*[0..8]);
const result = mem.readIntSliceLittle(u64, ptr.*[0..8]);
ptr.* += 8;
return result;
} else {
@ -2063,10 +2086,10 @@ fn readILeb128Mem(ptr: *[*]const u8) !i64 {
}
fn readInitialLength(comptime E: type, in_stream: *io.InStream(E), is_64: *bool) !u64 {
const first_32_bits = try in_stream.readIntLe(u32);
const first_32_bits = try in_stream.readIntLittle(u32);
is_64.* = (first_32_bits == 0xffffffff);
if (is_64.*) {
return in_stream.readIntLe(u64);
return in_stream.readIntLittle(u64);
} else {
if (first_32_bits >= 0xfffffff0) return error.InvalidDebugInfo;
return u64(first_32_bits);

View File

@ -19,7 +19,6 @@ pub const DynLib = switch (builtin.os) {
};
pub const LinuxDynLib = struct {
allocator: *mem.Allocator,
elf_lib: ElfLib,
fd: i32,
map_addr: usize,
@ -27,7 +26,7 @@ pub const LinuxDynLib = struct {
/// Trusts the file
pub fn open(allocator: *mem.Allocator, path: []const u8) !DynLib {
const fd = try std.os.posixOpen(allocator, path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
const fd = try std.os.posixOpen(path, 0, linux.O_RDONLY | linux.O_CLOEXEC);
errdefer std.os.close(fd);
const size = @intCast(usize, (try std.os.posixFStat(fd)).size);
@ -45,7 +44,6 @@ pub const LinuxDynLib = struct {
const bytes = @intToPtr([*]align(std.os.page_size) u8, addr)[0..size];
return DynLib{
.allocator = allocator,
.elf_lib = try ElfLib.init(bytes),
.fd = fd,
.map_addr = addr,

View File

@ -353,7 +353,8 @@ pub const SectionHeader = struct {
};
pub const Elf = struct {
in_file: os.File,
seekable_stream: *io.SeekableStream(anyerror, anyerror),
in_stream: *io.InStream(anyerror),
auto_close_stream: bool,
is_64: bool,
endian: builtin.Endian,
@ -370,19 +371,24 @@ pub const Elf = struct {
/// Call close when done.
pub fn openPath(elf: *Elf, allocator: *mem.Allocator, path: []const u8) !void {
try elf.prealloc_file.open(path);
try elf.openFile(allocator, *elf.prealloc_file);
elf.auto_close_stream = true;
@compileError("TODO implement");
}
/// Call close when done.
pub fn openFile(elf: *Elf, allocator: *mem.Allocator, file: os.File) !void {
elf.allocator = allocator;
elf.in_file = file;
elf.auto_close_stream = false;
@compileError("TODO implement");
}
var file_stream = elf.in_file.inStream();
const in = &file_stream.stream;
pub fn openStream(
elf: *Elf,
allocator: *mem.Allocator,
seekable_stream: *io.SeekableStream(anyerror, anyerror),
in: *io.InStream(anyerror),
) !void {
elf.auto_close_stream = false;
elf.allocator = allocator;
elf.seekable_stream = seekable_stream;
elf.in_stream = in;
var magic: [4]u8 = undefined;
try in.readNoEof(magic[0..]);
@ -404,9 +410,9 @@ pub const Elf = struct {
if (version_byte != 1) return error.InvalidFormat;
// skip over padding
try elf.in_file.seekForward(9);
try seekable_stream.seekForward(9);
elf.file_type = switch (try in.readInt(elf.endian, u16)) {
elf.file_type = switch (try in.readInt(u16, elf.endian)) {
1 => FileType.Relocatable,
2 => FileType.Executable,
3 => FileType.Shared,
@ -414,7 +420,7 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
elf.arch = switch (try in.readInt(elf.endian, u16)) {
elf.arch = switch (try in.readInt(u16, elf.endian)) {
0x02 => Arch.Sparc,
0x03 => Arch.x86,
0x08 => Arch.Mips,
@ -427,32 +433,32 @@ pub const Elf = struct {
else => return error.InvalidFormat,
};
const elf_version = try in.readInt(elf.endian, u32);
const elf_version = try in.readInt(u32, elf.endian);
if (elf_version != 1) return error.InvalidFormat;
if (elf.is_64) {
elf.entry_addr = try in.readInt(elf.endian, u64);
elf.program_header_offset = try in.readInt(elf.endian, u64);
elf.section_header_offset = try in.readInt(elf.endian, u64);
elf.entry_addr = try in.readInt(u64, elf.endian);
elf.program_header_offset = try in.readInt(u64, elf.endian);
elf.section_header_offset = try in.readInt(u64, elf.endian);
} else {
elf.entry_addr = u64(try in.readInt(elf.endian, u32));
elf.program_header_offset = u64(try in.readInt(elf.endian, u32));
elf.section_header_offset = u64(try in.readInt(elf.endian, u32));
elf.entry_addr = u64(try in.readInt(u32, elf.endian));
elf.program_header_offset = u64(try in.readInt(u32, elf.endian));
elf.section_header_offset = u64(try in.readInt(u32, elf.endian));
}
// skip over flags
try elf.in_file.seekForward(4);
try seekable_stream.seekForward(4);
const header_size = try in.readInt(elf.endian, u16);
const header_size = try in.readInt(u16, elf.endian);
if ((elf.is_64 and header_size != 64) or (!elf.is_64 and header_size != 52)) {
return error.InvalidFormat;
}
const ph_entry_size = try in.readInt(elf.endian, u16);
const ph_entry_count = try in.readInt(elf.endian, u16);
const sh_entry_size = try in.readInt(elf.endian, u16);
const sh_entry_count = try in.readInt(elf.endian, u16);
elf.string_section_index = u64(try in.readInt(elf.endian, u16));
const ph_entry_size = try in.readInt(u16, elf.endian);
const ph_entry_count = try in.readInt(u16, elf.endian);
const sh_entry_size = try in.readInt(u16, elf.endian);
const sh_entry_count = try in.readInt(u16, elf.endian);
elf.string_section_index = u64(try in.readInt(u16, elf.endian));
if (elf.string_section_index >= sh_entry_count) return error.InvalidFormat;
@ -461,12 +467,12 @@ pub const Elf = struct {
const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
const end_ph = try math.add(u64, elf.program_header_offset, ph_byte_count);
const stream_end = try elf.in_file.getEndPos();
const stream_end = try seekable_stream.getEndPos();
if (stream_end < end_sh or stream_end < end_ph) {
return error.InvalidFormat;
}
try elf.in_file.seekTo(elf.section_header_offset);
try seekable_stream.seekTo(elf.section_header_offset);
elf.section_headers = try elf.allocator.alloc(SectionHeader, sh_entry_count);
errdefer elf.allocator.free(elf.section_headers);
@ -475,32 +481,32 @@ pub const Elf = struct {
if (sh_entry_size != 64) return error.InvalidFormat;
for (elf.section_headers) |*elf_section| {
elf_section.name = try in.readInt(elf.endian, u32);
elf_section.sh_type = try in.readInt(elf.endian, u32);
elf_section.flags = try in.readInt(elf.endian, u64);
elf_section.addr = try in.readInt(elf.endian, u64);
elf_section.offset = try in.readInt(elf.endian, u64);
elf_section.size = try in.readInt(elf.endian, u64);
elf_section.link = try in.readInt(elf.endian, u32);
elf_section.info = try in.readInt(elf.endian, u32);
elf_section.addr_align = try in.readInt(elf.endian, u64);
elf_section.ent_size = try in.readInt(elf.endian, u64);
elf_section.name = try in.readInt(u32, elf.endian);
elf_section.sh_type = try in.readInt(u32, elf.endian);
elf_section.flags = try in.readInt(u64, elf.endian);
elf_section.addr = try in.readInt(u64, elf.endian);
elf_section.offset = try in.readInt(u64, elf.endian);
elf_section.size = try in.readInt(u64, elf.endian);
elf_section.link = try in.readInt(u32, elf.endian);
elf_section.info = try in.readInt(u32, elf.endian);
elf_section.addr_align = try in.readInt(u64, elf.endian);
elf_section.ent_size = try in.readInt(u64, elf.endian);
}
} else {
if (sh_entry_size != 40) return error.InvalidFormat;
for (elf.section_headers) |*elf_section| {
// TODO (multiple occurrences) allow implicit cast from %u32 -> %u64 ?
elf_section.name = try in.readInt(elf.endian, u32);
elf_section.sh_type = try in.readInt(elf.endian, u32);
elf_section.flags = u64(try in.readInt(elf.endian, u32));
elf_section.addr = u64(try in.readInt(elf.endian, u32));
elf_section.offset = u64(try in.readInt(elf.endian, u32));
elf_section.size = u64(try in.readInt(elf.endian, u32));
elf_section.link = try in.readInt(elf.endian, u32);
elf_section.info = try in.readInt(elf.endian, u32);
elf_section.addr_align = u64(try in.readInt(elf.endian, u32));
elf_section.ent_size = u64(try in.readInt(elf.endian, u32));
elf_section.name = try in.readInt(u32, elf.endian);
elf_section.sh_type = try in.readInt(u32, elf.endian);
elf_section.flags = u64(try in.readInt(u32, elf.endian));
elf_section.addr = u64(try in.readInt(u32, elf.endian));
elf_section.offset = u64(try in.readInt(u32, elf.endian));
elf_section.size = u64(try in.readInt(u32, elf.endian));
elf_section.link = try in.readInt(u32, elf.endian);
elf_section.info = try in.readInt(u32, elf.endian);
elf_section.addr_align = u64(try in.readInt(u32, elf.endian));
elf_section.ent_size = u64(try in.readInt(u32, elf.endian));
}
}
@ -521,26 +527,23 @@ pub const Elf = struct {
pub fn close(elf: *Elf) void {
elf.allocator.free(elf.section_headers);
if (elf.auto_close_stream) elf.in_file.close();
if (elf.auto_close_stream) elf.prealloc_file.close();
}
pub fn findSection(elf: *Elf, name: []const u8) !?*SectionHeader {
var file_stream = elf.in_file.inStream();
const in = &file_stream.stream;
section_loop: for (elf.section_headers) |*elf_section| {
if (elf_section.sh_type == SHT_NULL) continue;
const name_offset = elf.string_section.offset + elf_section.name;
try elf.in_file.seekTo(name_offset);
try elf.seekable_stream.seekTo(name_offset);
for (name) |expected_c| {
const target_c = try in.readByte();
const target_c = try elf.in_stream.readByte();
if (target_c == 0 or expected_c != target_c) continue :section_loop;
}
{
const null_byte = try in.readByte();
const null_byte = try elf.in_stream.readByte();
if (null_byte == 0) return elf_section;
}
}
@ -549,7 +552,7 @@ pub const Elf = struct {
}
pub fn seekToSection(elf: *Elf, elf_section: *SectionHeader) !void {
try elf.in_file.seekTo(elf_section.offset);
try elf.seekable_stream.seekTo(elf_section.offset);
}
};

View File

@ -83,6 +83,7 @@ pub async fn pwritev(loop: *Loop, fd: os.FileHandle, data: []const []const u8, o
switch (builtin.os) {
builtin.Os.macosx,
builtin.Os.linux,
builtin.Os.freebsd,
=> {
const iovecs = try loop.allocator.alloc(os.posix.iovec_const, data.len);
defer loop.allocator.free(iovecs);
@ -219,6 +220,7 @@ pub async fn preadv(loop: *Loop, fd: os.FileHandle, data: []const []u8, offset:
switch (builtin.os) {
builtin.Os.macosx,
builtin.Os.linux,
builtin.Os.freebsd,
=> {
const iovecs = try loop.allocator.alloc(os.posix.iovec, data.len);
defer loop.allocator.free(iovecs);
@ -399,7 +401,7 @@ pub async fn openPosix(
pub async fn openRead(loop: *Loop, path: []const u8) os.File.OpenError!os.FileHandle {
switch (builtin.os) {
builtin.Os.macosx, builtin.Os.linux => {
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => {
const flags = posix.O_LARGEFILE | posix.O_RDONLY | posix.O_CLOEXEC;
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
},
@ -427,6 +429,7 @@ pub async fn openWriteMode(loop: *Loop, path: []const u8, mode: os.File.Mode) os
switch (builtin.os) {
builtin.Os.macosx,
builtin.Os.linux,
builtin.Os.freebsd,
=> {
const flags = posix.O_LARGEFILE | posix.O_WRONLY | posix.O_CREAT | posix.O_CLOEXEC | posix.O_TRUNC;
return await (async openPosix(loop, path, flags, os.File.default_mode) catch unreachable);
@ -449,7 +452,7 @@ pub async fn openReadWrite(
mode: os.File.Mode,
) os.File.OpenError!os.FileHandle {
switch (builtin.os) {
builtin.Os.macosx, builtin.Os.linux => {
builtin.Os.macosx, builtin.Os.linux, builtin.Os.freebsd => {
const flags = posix.O_LARGEFILE | posix.O_RDWR | posix.O_CREAT | posix.O_CLOEXEC;
return await (async openPosix(loop, path, flags, mode) catch unreachable);
},
@ -477,7 +480,7 @@ pub const CloseOperation = struct {
os_data: OsData,
const OsData = switch (builtin.os) {
builtin.Os.linux, builtin.Os.macosx => OsDataPosix,
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => OsDataPosix,
builtin.Os.windows => struct {
handle: ?os.FileHandle,
@ -496,7 +499,7 @@ pub const CloseOperation = struct {
self.* = CloseOperation{
.loop = loop,
.os_data = switch (builtin.os) {
builtin.Os.linux, builtin.Os.macosx => initOsDataPosix(self),
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => initOsDataPosix(self),
builtin.Os.windows => OsData{ .handle = null },
else => @compileError("Unsupported OS"),
},
@ -525,6 +528,7 @@ pub const CloseOperation = struct {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
=> {
if (self.os_data.have_fd) {
self.loop.posixFsRequest(&self.os_data.close_req_node);
@ -546,6 +550,7 @@ pub const CloseOperation = struct {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
=> {
self.os_data.close_req_node.data.msg.Close.fd = handle;
self.os_data.have_fd = true;
@ -562,6 +567,7 @@ pub const CloseOperation = struct {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
=> {
self.os_data.have_fd = false;
},
@ -576,6 +582,7 @@ pub const CloseOperation = struct {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
=> {
assert(self.os_data.have_fd);
return self.os_data.close_req_node.data.msg.Close.fd;
@ -599,6 +606,7 @@ pub async fn writeFileMode(loop: *Loop, path: []const u8, contents: []const u8,
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
=> return await (async writeFileModeThread(loop, path, contents, mode) catch unreachable),
builtin.Os.windows => return await (async writeFileWindows(loop, path, contents) catch unreachable),
else => @compileError("Unsupported OS"),
@ -704,7 +712,7 @@ pub fn Watch(comptime V: type) type {
os_data: OsData,
const OsData = switch (builtin.os) {
builtin.Os.macosx => struct {
builtin.Os.macosx, builtin.Os.freebsd => struct {
file_table: FileTable,
table_lock: event.Lock,
@ -793,7 +801,7 @@ pub fn Watch(comptime V: type) type {
return self;
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
const self = try loop.allocator.createOne(Self);
errdefer loop.allocator.destroy(self);
@ -813,7 +821,7 @@ pub fn Watch(comptime V: type) type {
/// All addFile calls and removeFile calls must have completed.
pub fn destroy(self: *Self) void {
switch (builtin.os) {
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
// TODO we need to cancel the coroutines before destroying the lock
self.os_data.table_lock.deinit();
var it = self.os_data.file_table.iterator();
@ -855,14 +863,14 @@ pub fn Watch(comptime V: type) type {
pub async fn addFile(self: *Self, file_path: []const u8, value: V) !?V {
switch (builtin.os) {
builtin.Os.macosx => return await (async addFileMacosx(self, file_path, value) catch unreachable),
builtin.Os.macosx, builtin.Os.freebsd => return await (async addFileKEvent(self, file_path, value) catch unreachable),
builtin.Os.linux => return await (async addFileLinux(self, file_path, value) catch unreachable),
builtin.Os.windows => return await (async addFileWindows(self, file_path, value) catch unreachable),
else => @compileError("Unsupported OS"),
}
}
async fn addFileMacosx(self: *Self, file_path: []const u8, value: V) !?V {
async fn addFileKEvent(self: *Self, file_path: []const u8, value: V) !?V {
const resolved_path = try os.path.resolve(self.channel.loop.allocator, file_path);
var resolved_path_consumed = false;
defer if (!resolved_path_consumed) self.channel.loop.allocator.free(resolved_path);
@ -871,7 +879,10 @@ pub fn Watch(comptime V: type) type {
var close_op_consumed = false;
defer if (!close_op_consumed) close_op.finish();
const flags = posix.O_SYMLINK | posix.O_EVTONLY;
const flags = switch (builtin.os) {
builtin.Os.macosx => posix.O_SYMLINK | posix.O_EVTONLY,
else => 0,
};
const mode = 0;
const fd = try await (async openPosix(self.channel.loop, resolved_path, flags, mode) catch unreachable);
close_op.setHandle(fd);

View File

@ -39,18 +39,22 @@ pub fn InStream(comptime ReadError: type) type {
if (amt_read < buf.len) return error.EndOfStream;
}
pub async fn readIntLe(self: *Self, comptime T: type) !T {
return await (async self.readInt(builtin.Endian.Little, T) catch unreachable);
pub async fn readIntLittle(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try await (async self.readNoEof(bytes[0..]) catch unreachable);
return mem.readIntLittle(T, &bytes);
}
pub async fn readIntBe(self: *Self, comptime T: type) !T {
return await (async self.readInt(builtin.Endian.Big, T) catch unreachable);
}
pub async fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try await (async self.readNoEof(bytes[0..]) catch unreachable);
return mem.readInt(bytes, T, endian);
return mem.readIntBig(T, &bytes);
}
pub async fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try await (async self.readNoEof(bytes[0..]) catch unreachable);
return mem.readInt(T, &bytes, endian);
}
pub async fn readStruct(self: *Self, comptime T: type) !T {

View File

@ -49,7 +49,7 @@ pub const Loop = struct {
};
pub const EventFd = switch (builtin.os) {
builtin.Os.macosx => MacOsEventFd,
builtin.Os.macosx, builtin.Os.freebsd => KEventFd,
builtin.Os.linux => struct {
base: ResumeNode,
epoll_op: u32,
@ -62,13 +62,13 @@ pub const Loop = struct {
else => @compileError("unsupported OS"),
};
const MacOsEventFd = struct {
const KEventFd = struct {
base: ResumeNode,
kevent: posix.Kevent,
};
pub const Basic = switch (builtin.os) {
builtin.Os.macosx => MacOsBasic,
builtin.Os.macosx, builtin.Os.freebsd => KEventBasic,
builtin.Os.linux => struct {
base: ResumeNode,
},
@ -78,7 +78,7 @@ pub const Loop = struct {
else => @compileError("unsupported OS"),
};
const MacOsBasic = struct {
const KEventBasic = struct {
base: ResumeNode,
kev: posix.Kevent,
};
@ -214,7 +214,7 @@ pub const Loop = struct {
self.extra_threads[extra_thread_index] = try os.spawnThread(self, workerRun);
}
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
self.os_data.kqfd = try os.bsdKQueue();
errdefer os.close(self.os_data.kqfd);
@ -369,7 +369,7 @@ pub const Loop = struct {
os.close(self.os_data.epollfd);
self.allocator.free(self.eventfd_resume_nodes);
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
os.close(self.os_data.kqfd);
os.close(self.os_data.fs_kqfd);
},
@ -484,7 +484,7 @@ pub const Loop = struct {
const eventfd_node = &resume_stack_node.data;
eventfd_node.base.handle = next_tick_node.data;
switch (builtin.os) {
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
const kevent_array = (*[1]posix.Kevent)(&eventfd_node.kevent);
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
_ = os.bsdKEvent(self.os_data.kqfd, kevent_array, empty_kevs, null) catch {
@ -546,6 +546,7 @@ pub const Loop = struct {
switch (builtin.os) {
builtin.Os.linux,
builtin.Os.macosx,
builtin.Os.freebsd,
=> self.os_data.fs_thread.wait(),
else => {},
}
@ -610,7 +611,7 @@ pub const Loop = struct {
os.posixWrite(self.os_data.final_eventfd, wakeup_bytes) catch unreachable;
return;
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
self.posixFsRequest(&self.os_data.fs_end_request);
const final_kevent = (*[1]posix.Kevent)(&self.os_data.final_kevent);
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
@ -668,7 +669,7 @@ pub const Loop = struct {
}
}
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
var eventlist: [1]posix.Kevent = undefined;
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
const count = os.bsdKEvent(self.os_data.kqfd, empty_kevs, eventlist[0..], null) catch unreachable;
@ -731,7 +732,7 @@ pub const Loop = struct {
self.beginOneEvent(); // finished in posixFsRun after processing the msg
self.os_data.fs_queue.put(request_node);
switch (builtin.os) {
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wake);
const empty_kevs = ([*]posix.Kevent)(undefined)[0..0];
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, empty_kevs, null) catch unreachable;
@ -801,7 +802,7 @@ pub const Loop = struct {
else => unreachable,
}
},
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
const fs_kevs = (*[1]posix.Kevent)(&self.os_data.fs_kevent_wait);
var out_kevs: [1]posix.Kevent = undefined;
_ = os.bsdKEvent(self.os_data.fs_kqfd, fs_kevs, out_kevs[0..], null) catch unreachable;
@ -813,7 +814,7 @@ pub const Loop = struct {
const OsData = switch (builtin.os) {
builtin.Os.linux => LinuxOsData,
builtin.Os.macosx => MacOsData,
builtin.Os.macosx, builtin.Os.freebsd => KEventData,
builtin.Os.windows => struct {
io_port: windows.HANDLE,
extra_thread_count: usize,
@ -821,7 +822,7 @@ pub const Loop = struct {
else => struct {},
};
const MacOsData = struct {
const KEventData = struct {
kqfd: i32,
final_kevent: posix.Kevent,
fs_kevent_wake: posix.Kevent,

View File

@ -2,6 +2,7 @@ const std = @import("../index.zig");
const math = std.math;
const debug = std.debug;
const assert = debug.assert;
const assertError = debug.assertError;
const mem = std.mem;
const builtin = @import("builtin");
const errol = @import("errol/index.zig");
@ -116,7 +117,7 @@ pub fn formatType(
return output(context, @errorName(value));
}
switch (@typeInfo(T)) {
builtin.TypeId.Int, builtin.TypeId.Float => {
builtin.TypeId.ComptimeInt, builtin.TypeId.Int, builtin.TypeId.Float => {
return formatValue(value, fmt, context, Errors, output);
},
builtin.TypeId.Void => {
@ -242,6 +243,9 @@ pub fn formatType(
}
return format(context, Errors, output, "{}@{x}", @typeName(T.Child), @ptrToInt(&value));
},
builtin.TypeId.Fn => {
return format(context, Errors, output, "{}@{x}", @typeName(T), @ptrToInt(value));
},
else => @compileError("Unable to format type '" ++ @typeName(T) ++ "'"),
}
}
@ -267,11 +271,15 @@ fn formatValue(
}
}
comptime var T = @typeOf(value);
const T = @typeOf(value);
switch (@typeId(T)) {
builtin.TypeId.Float => return formatFloatValue(value, fmt, context, Errors, output),
builtin.TypeId.Int => return formatIntValue(value, fmt, context, Errors, output),
else => unreachable,
builtin.TypeId.ComptimeInt => {
const Int = math.IntFittingRange(value, value);
return formatIntValue(Int(value), fmt, context, Errors, output);
},
else => comptime unreachable,
}
}
@ -288,9 +296,10 @@ pub fn formatIntValue(
if (fmt.len > 0) {
switch (fmt[0]) {
'c' => {
if (@typeOf(value) == u8) {
if (fmt.len > 1) @compileError("Unknown format character: " ++ []u8{fmt[1]});
return formatAsciiChar(value, context, Errors, output);
if (@typeOf(value).bit_count <= 8) {
if (fmt.len > 1)
@compileError("Unknown format character: " ++ []u8{fmt[1]});
return formatAsciiChar(u8(value), context, Errors, output);
}
},
'b' => {
@ -811,13 +820,41 @@ pub fn parseUnsigned(comptime T: type, buf: []const u8, radix: u8) ParseUnsigned
for (buf) |c| {
const digit = try charToDigit(c, radix);
x = try math.mul(T, x, radix);
x = try math.add(T, x, digit);
if (x != 0) x = try math.mul(T, x, try math.cast(T, radix));
x = try math.add(T, x, try math.cast(T, digit));
}
return x;
}
test "parseUnsigned" {
assert((try parseUnsigned(u16, "050124", 10)) == 50124);
assert((try parseUnsigned(u16, "65535", 10)) == 65535);
assertError(parseUnsigned(u16, "65536", 10), error.Overflow);
assert((try parseUnsigned(u64, "0ffffffffffffffff", 16)) == 0xffffffffffffffff);
assertError(parseUnsigned(u64, "10000000000000000", 16), error.Overflow);
assert((try parseUnsigned(u32, "DeadBeef", 16)) == 0xDEADBEEF);
assert((try parseUnsigned(u7, "1", 10)) == 1);
assert((try parseUnsigned(u7, "1000", 2)) == 8);
assertError(parseUnsigned(u32, "f", 10), error.InvalidCharacter);
assertError(parseUnsigned(u8, "109", 8), error.InvalidCharacter);
assert((try parseUnsigned(u32, "NUMBER", 36)) == 1442151747);
// these numbers should fit even though the radix itself doesn't fit in the destination type
assert((try parseUnsigned(u1, "0", 10)) == 0);
assert((try parseUnsigned(u1, "1", 10)) == 1);
assertError(parseUnsigned(u1, "2", 10), error.Overflow);
assert((try parseUnsigned(u1, "001", 16)) == 1);
assert((try parseUnsigned(u2, "3", 16)) == 3);
assertError(parseUnsigned(u2, "4", 16), error.Overflow);
}
pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) {
const value = switch (c) {
'0'...'9' => c - '0',
@ -935,6 +972,25 @@ test "fmt.format" {
const value: u8 = 0b1100;
try testFmt("u8: 0b1100\n", "u8: 0b{b}\n", value);
}
{
var buf1: [32]u8 = undefined;
var context = BufPrintContext{ .remaining = buf1[0..] };
try formatType(1234, "", &context, error{BufferTooSmall}, bufPrintWrite);
var res = buf1[0 .. buf1.len - context.remaining.len];
assert(mem.eql(u8, res, "1234"));
context = BufPrintContext{ .remaining = buf1[0..] };
try formatType('a', "c", &context, error{BufferTooSmall}, bufPrintWrite);
res = buf1[0 .. buf1.len - context.remaining.len];
debug.warn("{}\n", res);
assert(mem.eql(u8, res, "a"));
context = BufPrintContext{ .remaining = buf1[0..] };
try formatType(0b1100, "b", &context, error{BufferTooSmall}, bufPrintWrite);
res = buf1[0 .. buf1.len - context.remaining.len];
debug.warn("{}\n", res);
assert(mem.eql(u8, res, "1100"));
}
{
const value: [3]u8 = "abc";
try testFmt("array: abc\n", "array: {}\n", value);
@ -956,6 +1012,14 @@ test "fmt.format" {
try testFmt("pointer: i32@deadbeef\n", "pointer: {}\n", value);
try testFmt("pointer: i32@deadbeef\n", "pointer: {*}\n", value);
}
{
const value = @intToPtr(fn () void, 0xdeadbeef);
try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
}
{
const value = @intToPtr(fn () void, 0xdeadbeef);
try testFmt("pointer: fn() void@deadbeef\n", "pointer: {}\n", value);
}
try testFmt("buf: Test \n", "buf: {s5}\n", "Test");
try testFmt("buf: Test\n Other text", "buf: {s}\n Other text", "Test");
try testFmt("cstr: Test C\n", "cstr: {s}\n", c"Test C");

View File

@ -42,8 +42,8 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
pub fn init(key: []const u8) Self {
debug.assert(key.len >= 16);
const k0 = mem.readInt(key[0..8], u64, Endian.Little);
const k1 = mem.readInt(key[8..16], u64, Endian.Little);
const k0 = mem.readIntSliceLittle(u64, key[0..8]);
const k1 = mem.readIntSliceLittle(u64, key[8..16]);
var d = Self{
.v0 = k0 ^ 0x736f6d6570736575,
@ -121,7 +121,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
fn round(d: *Self, b: []const u8) void {
debug.assert(b.len == 8);
const m = mem.readInt(b[0..], u64, Endian.Little);
const m = mem.readIntSliceLittle(u64, b[0..]);
d.v3 ^= m;
comptime var i: usize = 0;
@ -162,7 +162,7 @@ fn SipHash(comptime T: type, comptime c_rounds: usize, comptime d_rounds: usize)
const test_key = "\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f";
test "siphash64-2-4 sanity" {
const vectors = [][]const u8{
const vectors = [][8]u8{
"\x31\x0e\x0e\xdd\x47\xdb\x6f\x72", // ""
"\xfd\x67\xdc\x93\xc5\x39\xf8\x74", // "\x00"
"\x5a\x4f\xa9\xd9\x09\x80\x6c\x0d", // "\x00\x01" ... etc
@ -235,13 +235,13 @@ test "siphash64-2-4 sanity" {
for (vectors) |vector, i| {
buffer[i] = @intCast(u8, i);
const expected = mem.readInt(vector, u64, Endian.Little);
const expected = mem.readIntLittle(u64, &vector);
debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
}
}
test "siphash128-2-4 sanity" {
const vectors = [][]const u8{
const vectors = [][16]u8{
"\xa3\x81\x7f\x04\xba\x25\xa8\xe6\x6d\xf6\x72\x14\xc7\x55\x02\x93",
"\xda\x87\xc1\xd8\x6b\x99\xaf\x44\x34\x76\x59\x11\x9b\x22\xfc\x45",
"\x81\x77\x22\x8d\xa4\xa4\x5d\xc7\xfc\xa3\x8b\xde\xf6\x0a\xff\xe4",
@ -314,7 +314,7 @@ test "siphash128-2-4 sanity" {
for (vectors) |vector, i| {
buffer[i] = @intCast(u8, i);
const expected = mem.readInt(vector, u128, Endian.Little);
const expected = mem.readIntLittle(u128, &vector);
debug.assert(siphash.hash(test_key, buffer[0..i]) == expected);
}
}

View File

@ -126,6 +126,14 @@ pub fn HashMap(comptime K: type, comptime V: type, comptime hash: fn (key: K) u3
};
}
pub fn getOrPutValue(self: *Self, key: K, value: V) !*KV {
const res = try self.getOrPut(key);
if (!res.found_existing)
res.kv.value = value;
return res.kv;
}
fn ensureCapacity(self: *Self) !void {
if (self.entries.len == 0) {
return self.initCapacity(16);
@ -354,6 +362,12 @@ test "basic hash map usage" {
gop2.kv.value = 42;
assert(map.get(99).?.value == 42);
const gop3 = try map.getOrPutValue(5, 5);
assert(gop3.value == 77);
const gop4 = try map.getOrPutValue(100, 41);
assert(gop4.value == 41);
assert(map.contains(2));
assert(map.get(2).?.value == 22);
_ = map.remove(2);

View File

@ -66,11 +66,11 @@ pub const DirectAllocator = struct {
}
}
fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
fn alloc(allocator: *Allocator, n: usize, alignment: u29) error{OutOfMemory}![]u8 {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const p = os.posix;
const alloc_size = if (alignment <= os.page_size) n else n + alignment;
const addr = p.mmap(null, alloc_size, p.PROT_READ | p.PROT_WRITE, p.MAP_PRIVATE | p.MAP_ANONYMOUS, -1, 0);
@ -121,7 +121,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
if (new_size <= old_mem.len) {
const base_addr = @ptrToInt(old_mem.ptr);
const old_addr_end = base_addr + old_mem.len;
@ -166,7 +166,7 @@ pub const DirectAllocator = struct {
const self = @fieldParentPtr(DirectAllocator, "allocator", allocator);
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
_ = os.posix.munmap(@ptrToInt(bytes.ptr), bytes.len);
},
Os.windows => {

View File

@ -57,7 +57,8 @@ test "std" {
_ = @import("mutex.zig");
_ = @import("segmented_list.zig");
_ = @import("spinlock.zig");
_ = @import("dynamic_library.zig");
_ = @import("base64.zig");
_ = @import("build.zig");
_ = @import("c/index.zig");

View File

@ -32,6 +32,8 @@ pub fn getStdIn() GetStdIoErrs!File {
return File.openHandle(handle);
}
pub const SeekableStream = @import("io/seekable_stream.zig").SeekableStream;
pub fn InStream(comptime ReadError: type) type {
return struct {
const Self = @This();
@ -150,35 +152,43 @@ pub fn InStream(comptime ReadError: type) type {
}
/// Reads a native-endian integer
pub fn readIntNe(self: *Self, comptime T: type) !T {
return self.readInt(builtin.endian, T);
}
pub fn readIntLe(self: *Self, comptime T: type) !T {
pub fn readIntNative(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntLE(T, bytes);
return mem.readIntNative(T, &bytes);
}
pub fn readIntBe(self: *Self, comptime T: type) !T {
/// Reads a foreign-endian integer
pub fn readIntForeign(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntBE(T, bytes);
return mem.readIntForeign(T, &bytes);
}
pub fn readInt(self: *Self, endian: builtin.Endian, comptime T: type) !T {
pub fn readIntLittle(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readInt(bytes, T, endian);
return mem.readIntLittle(T, &bytes);
}
pub fn readVarInt(self: *Self, endian: builtin.Endian, comptime T: type, size: usize) !T {
assert(size <= @sizeOf(T));
assert(size <= 8);
var input_buf: [8]u8 = undefined;
const input_slice = input_buf[0..size];
try self.readNoEof(input_slice);
return mem.readInt(input_slice, T, endian);
pub fn readIntBig(self: *Self, comptime T: type) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readIntBig(T, &bytes);
}
pub fn readInt(self: *Self, comptime T: type, endian: builtin.Endian) !T {
var bytes: [@sizeOf(T)]u8 = undefined;
try self.readNoEof(bytes[0..]);
return mem.readInt(T, &bytes, endian);
}
pub fn readVarInt(self: *Self, comptime ReturnType: type, endian: builtin.Endian, size: usize) !ReturnType {
assert(size <= @sizeOf(ReturnType));
var bytes_buf: [@sizeOf(ReturnType)]u8 = undefined;
const bytes = bytes_buf[0..size];
try self.readNoEof(bytes);
return mem.readVarInt(ReturnType, bytes, endian);
}
pub fn skipBytes(self: *Self, num_bytes: usize) !void {
@ -227,25 +237,34 @@ pub fn OutStream(comptime WriteError: type) type {
}
/// Write a native-endian integer.
pub fn writeIntNe(self: *Self, comptime T: type, value: T) Error!void {
return self.writeInt(builtin.endian, T, value);
}
pub fn writeIntLe(self: *Self, comptime T: type, value: T) Error!void {
pub fn writeIntNative(self: *Self, comptime T: type, value: T) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
mem.writeIntLE(T, &bytes, value);
mem.writeIntNative(T, &bytes, value);
return self.writeFn(self, bytes);
}
pub fn writeIntBe(self: *Self, comptime T: type, value: T) Error!void {
/// Write a foreign-endian integer.
pub fn writeIntForeign(self: *Self, comptime T: type, value: T) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
mem.writeIntBE(T, &bytes, value);
mem.writeIntForeign(T, &bytes, value);
return self.writeFn(self, bytes);
}
pub fn writeInt(self: *Self, endian: builtin.Endian, comptime T: type, value: T) Error!void {
pub fn writeIntLittle(self: *Self, comptime T: type, value: T) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
mem.writeInt(bytes[0..], value, endian);
mem.writeIntLittle(T, &bytes, value);
return self.writeFn(self, bytes);
}
pub fn writeIntBig(self: *Self, comptime T: type, value: T) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
mem.writeIntBig(T, &bytes, value);
return self.writeFn(self, bytes);
}
pub fn writeInt(self: *Self, comptime T: type, value: T, endian: builtin.Endian) Error!void {
var bytes: [@sizeOf(T)]u8 = undefined;
mem.writeInt(T, &bytes, value, endian);
return self.writeFn(self, bytes);
}
};
@ -683,25 +702,73 @@ test "import io tests" {
}
}
pub fn readLine(buf: []u8) !usize {
var stdin = getStdIn() catch return error.StdInUnavailable;
var adapter = stdin.inStream();
var stream = &adapter.stream;
var index: usize = 0;
pub fn readLine(buf: *std.Buffer) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
return readLineFrom(&stdin_stream.stream, buf);
}
/// Reads all characters until the next newline into buf, and returns
/// a slice of the characters read (excluding the newline character(s)).
pub fn readLineFrom(stream: var, buf: *std.Buffer) ![]u8 {
const start = buf.len();
while (true) {
const byte = stream.readByte() catch return error.EndOfFile;
const byte = try stream.readByte();
switch (byte) {
'\r' => {
// trash the following \n
_ = stream.readByte() catch return error.EndOfFile;
return index;
},
'\n' => return index,
else => {
if (index == buf.len) return error.InputTooLong;
buf[index] = byte;
index += 1;
_ = try stream.readByte();
return buf.toSlice()[start..];
},
'\n' => return buf.toSlice()[start..],
else => try buf.appendByte(byte),
}
}
}
test "io.readLineFrom" {
var bytes: [128]u8 = undefined;
const allocator = &std.heap.FixedBufferAllocator.init(bytes[0..]).allocator;
var buf = try std.Buffer.initSize(allocator, 0);
var mem_stream = SliceInStream.init(
\\Line 1
\\Line 22
\\Line 333
);
const stream = &mem_stream.stream;
debug.assert(mem.eql(u8, "Line 1", try readLineFrom(stream, &buf)));
debug.assert(mem.eql(u8, "Line 22", try readLineFrom(stream, &buf)));
debug.assertError(readLineFrom(stream, &buf), error.EndOfStream);
debug.assert(mem.eql(u8, buf.toSlice(), "Line 1Line 22Line 333"));
}
pub fn readLineSlice(slice: []u8) ![]u8 {
var stdin = try getStdIn();
var stdin_stream = stdin.inStream();
return readLineSliceFrom(&stdin_stream.stream, slice);
}
/// Reads all characters until the next newline into slice, and returns
/// a slice of the characters read (excluding the newline character(s)).
pub fn readLineSliceFrom(stream: var, slice: []u8) ![]u8 {
// We cannot use Buffer.fromOwnedSlice, as it wants to append a null byte
// after taking ownership, which would always require an allocation.
var buf = std.Buffer{ .list = std.ArrayList(u8).fromOwnedSlice(debug.failing_allocator, slice) };
try buf.resize(0);
return try readLineFrom(stream, &buf);
}
test "io.readLineSliceFrom" {
var buf: [7]u8 = undefined;
var mem_stream = SliceInStream.init(
\\Line 1
\\Line 22
\\Line 333
);
const stream = &mem_stream.stream;
debug.assert(mem.eql(u8, "Line 1", try readLineSliceFrom(stream, buf[0..])));
debug.assertError(readLineSliceFrom(stream, buf[0..]), error.OutOfMemory);
}

View File

@ -0,0 +1,32 @@
const std = @import("../index.zig");
const InStream = std.io.InStream;
pub fn SeekableStream(comptime SeekErrorType: type, comptime GetSeekPosErrorType: type) type {
return struct {
const Self = @This();
pub const SeekError = SeekErrorType;
pub const GetSeekPosError = GetSeekPosErrorType;
seekToFn: fn (self: *Self, pos: usize) SeekError!void,
seekForwardFn: fn (self: *Self, pos: isize) SeekError!void,
getPosFn: fn (self: *Self) GetSeekPosError!usize,
getEndPosFn: fn (self: *Self) GetSeekPosError!usize,
pub fn seekTo(self: *Self, pos: usize) SeekError!void {
return self.seekToFn(self, pos);
}
pub fn seekForward(self: *Self, amt: isize) SeekError!void {
return self.seekForwardFn(self, amt);
}
pub fn getEndPos(self: *Self) GetSeekPosError!usize {
return self.getEndPosFn(self);
}
pub fn getPos(self: *Self) GetSeekPosError!usize {
return self.getPosFn(self);
}
};
}

View File

@ -910,7 +910,7 @@ fn checkNext(p: *TokenStream, id: Token.Id) void {
debug.assert(token.id == id);
}
test "token" {
test "json.token" {
const s =
\\{
\\ "Image": {
@ -980,7 +980,7 @@ pub fn validate(s: []const u8) bool {
return p.complete;
}
test "json validate" {
test "json.validate" {
debug.assert(validate("{}"));
}
@ -1188,7 +1188,7 @@ pub const Parser = struct {
}
var value = p.stack.pop();
try p.pushToParent(value);
try p.pushToParent(&value);
},
Token.Id.String => {
try p.stack.append(try p.parseString(allocator, token, input, i));
@ -1251,7 +1251,7 @@ pub const Parser = struct {
}
var value = p.stack.pop();
try p.pushToParent(value);
try p.pushToParent(&value);
},
Token.Id.ObjectBegin => {
try p.stack.append(Value{ .Object = ObjectMap.init(allocator) });
@ -1312,19 +1312,19 @@ pub const Parser = struct {
}
}
fn pushToParent(p: *Parser, value: Value) !void {
switch (p.stack.at(p.stack.len - 1)) {
fn pushToParent(p: *Parser, value: *const Value) !void {
switch (p.stack.toSlice()[p.stack.len - 1]) {
// Object Parent -> [ ..., object, <key>, value ]
Value.String => |key| {
_ = p.stack.pop();
var object = &p.stack.items[p.stack.len - 1].Object;
_ = try object.put(key, value);
_ = try object.put(key, value.*);
p.state = State.ObjectKey;
},
// Array Parent -> [ ..., <array>, value ]
Value.Array => |*array| {
try array.append(value);
try array.append(value.*);
p.state = State.ArrayValue;
},
else => {
@ -1348,7 +1348,7 @@ pub const Parser = struct {
}
};
test "json parser dynamic" {
test "json.parser.dynamic" {
var p = Parser.init(debug.global_allocator, false);
defer p.deinit();
@ -1364,7 +1364,8 @@ test "json parser dynamic" {
\\ "Width": 100
\\ },
\\ "Animated" : false,
\\ "IDs": [116, 943, 234, 38793]
\\ "IDs": [116, 943, 234, 38793],
\\ "ArrayOfObject": [{"n": "m"}]
\\ }
\\}
;
@ -1387,4 +1388,10 @@ test "json parser dynamic" {
const animated = image.Object.get("Animated").?.value;
debug.assert(animated.Bool == false);
const array_of_object = image.Object.get("ArrayOfObject").?.value;
debug.assert(array_of_object.Array.len == 1);
const obj0 = array_of_object.Array.at(0).Object.get("n").?.value;
debug.assert(mem.eql(u8, obj0.String, "m"));
}

File diff suppressed because it is too large Load Diff

View File

@ -82,6 +82,28 @@ pub fn LinkedList(comptime T: type) type {
list.len += 1;
}
/// Concatenate list2 onto the end of list1, removing all entries from the former.
///
/// Arguments:
/// list1: the list to concatenate onto
/// list2: the list to be concatenated
pub fn concatByMoving(list1: *Self, list2: *Self) void {
const l2_first = list2.first orelse return;
if (list1.last) |l1_last| {
l1_last.next = list2.first;
l2_first.prev = list1.last;
list1.len += list2.len;
} else {
// list1 was empty
list1.first = list2.first;
list1.len = list2.len;
}
list1.last = list2.last;
list2.first = null;
list2.last = null;
list2.len = 0;
}
/// Insert a new node at the end of the list.
///
/// Arguments:
@ -247,3 +269,77 @@ test "basic linked list test" {
assert(list.last.?.data == 4);
assert(list.len == 2);
}
test "linked list concatenation" {
const allocator = debug.global_allocator;
var list1 = LinkedList(u32).init();
var list2 = LinkedList(u32).init();
var one = try list1.createNode(1, allocator);
defer list1.destroyNode(one, allocator);
var two = try list1.createNode(2, allocator);
defer list1.destroyNode(two, allocator);
var three = try list1.createNode(3, allocator);
defer list1.destroyNode(three, allocator);
var four = try list1.createNode(4, allocator);
defer list1.destroyNode(four, allocator);
var five = try list1.createNode(5, allocator);
defer list1.destroyNode(five, allocator);
list1.append(one);
list1.append(two);
list2.append(three);
list2.append(four);
list2.append(five);
list1.concatByMoving(&list2);
assert(list1.last == five);
assert(list1.len == 5);
assert(list2.first == null);
assert(list2.last == null);
assert(list2.len == 0);
// Traverse forwards.
{
var it = list1.first;
var index: u32 = 1;
while (it) |node| : (it = node.next) {
assert(node.data == index);
index += 1;
}
}
// Traverse backwards.
{
var it = list1.last;
var index: u32 = 1;
while (it) |node| : (it = node.prev) {
assert(node.data == (6 - index));
index += 1;
}
}
// Swap them back, this verifies that concating to an empty list works.
list2.concatByMoving(&list1);
// Traverse forwards.
{
var it = list2.first;
var index: u32 = 1;
while (it) |node| : (it = node.next) {
assert(node.data == index);
index += 1;
}
}
// Traverse backwards.
{
var it = list2.last;
var index: u32 = 1;
while (it) |node| : (it = node.prev) {
assert(node.data == (6 - index));
index += 1;
}
}
}

View File

@ -6,6 +6,13 @@ const assert = std.debug.assert;
pub const e = 2.71828182845904523536028747135266249775724709369995;
pub const pi = 3.14159265358979323846264338327950288419716939937510;
// From a small c++ [program using boost float128](https://github.com/winksaville/cpp_boost_float128)
pub const f128_true_min = @bitCast(f128, u128(0x00000000000000000000000000000001));
pub const f128_min = @bitCast(f128, u128(0x00010000000000000000000000000000));
pub const f128_max = @bitCast(f128, u128(0x7FFEFFFFFFFFFFFFFFFFFFFFFFFFFFFF));
pub const f128_epsilon = @bitCast(f128, u128(0x3F8F0000000000000000000000000000));
pub const f128_toint = 1.0 / f128_epsilon;
// float.h details
pub const f64_true_min = 4.94065645841246544177e-324;
pub const f64_min = 2.2250738585072014e-308;
@ -365,6 +372,69 @@ pub fn Log2Int(comptime T: type) type {
return @IntType(false, count);
}
pub fn IntFittingRange(comptime from: comptime_int, comptime to: comptime_int) type {
assert(from <= to);
if (from == 0 and to == 0) {
return u0;
}
const is_signed = from < 0;
const largest_positive_integer = max(if (from<0) (-from)-1 else from, to); // two's complement
const base = log2(largest_positive_integer);
const upper = (1 << base) - 1;
var magnitude_bits = if (upper >= largest_positive_integer) base else base + 1;
if (is_signed) {
magnitude_bits += 1;
}
return @IntType(is_signed, magnitude_bits);
}
test "math.IntFittingRange" {
assert(IntFittingRange(0, 0) == u0);
assert(IntFittingRange(0, 1) == u1);
assert(IntFittingRange(0, 2) == u2);
assert(IntFittingRange(0, 3) == u2);
assert(IntFittingRange(0, 4) == u3);
assert(IntFittingRange(0, 7) == u3);
assert(IntFittingRange(0, 8) == u4);
assert(IntFittingRange(0, 9) == u4);
assert(IntFittingRange(0, 15) == u4);
assert(IntFittingRange(0, 16) == u5);
assert(IntFittingRange(0, 17) == u5);
assert(IntFittingRange(0, 4095) == u12);
assert(IntFittingRange(2000, 4095) == u12);
assert(IntFittingRange(0, 4096) == u13);
assert(IntFittingRange(2000, 4096) == u13);
assert(IntFittingRange(0, 4097) == u13);
assert(IntFittingRange(2000, 4097) == u13);
assert(IntFittingRange(0, 123456789123456798123456789) == u87);
assert(IntFittingRange(0, 123456789123456798123456789123456789123456798123456789) == u177);
assert(IntFittingRange(-1, -1) == i1);
assert(IntFittingRange(-1, 0) == i1);
assert(IntFittingRange(-1, 1) == i2);
assert(IntFittingRange(-2, -2) == i2);
assert(IntFittingRange(-2, -1) == i2);
assert(IntFittingRange(-2, 0) == i2);
assert(IntFittingRange(-2, 1) == i2);
assert(IntFittingRange(-2, 2) == i3);
assert(IntFittingRange(-1, 2) == i3);
assert(IntFittingRange(-1, 3) == i3);
assert(IntFittingRange(-1, 4) == i4);
assert(IntFittingRange(-1, 7) == i4);
assert(IntFittingRange(-1, 8) == i5);
assert(IntFittingRange(-1, 9) == i5);
assert(IntFittingRange(-1, 15) == i5);
assert(IntFittingRange(-1, 16) == i6);
assert(IntFittingRange(-1, 17) == i6);
assert(IntFittingRange(-1, 4095) == i13);
assert(IntFittingRange(-4096, 4095) == i13);
assert(IntFittingRange(-1, 4096) == i14);
assert(IntFittingRange(-4097, 4095) == i14);
assert(IntFittingRange(-1, 4097) == i14);
assert(IntFittingRange(-1, 123456789123456798123456789) == i88);
assert(IntFittingRange(-1, 123456789123456798123456789123456789123456798123456789) == i178);
}
test "math overflow functions" {
testOverflow();
comptime testOverflow();

View File

@ -410,12 +410,8 @@ test "mem.indexOf" {
/// Reads an integer from memory with size equal to bytes.len.
/// T specifies the return type, which must be large enough to store
/// the result.
/// See also ::readIntBE or ::readIntLE.
pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T {
if (T.bit_count == 8) {
return bytes[0];
}
var result: T = 0;
pub fn readVarInt(comptime ReturnType: type, bytes: []const u8, endian: builtin.Endian) ReturnType {
var result: ReturnType = 0;
switch (endian) {
builtin.Endian.Big => {
for (bytes) |b| {
@ -423,172 +419,270 @@ pub fn readInt(bytes: []const u8, comptime T: type, endian: builtin.Endian) T {
}
},
builtin.Endian.Little => {
const ShiftType = math.Log2Int(T);
const ShiftType = math.Log2Int(ReturnType);
for (bytes) |b, index| {
result = result | (T(b) << @intCast(ShiftType, index * 8));
result = result | (ReturnType(b) << @intCast(ShiftType, index * 8));
}
},
}
return result;
}
/// Reads a big-endian int of type T from bytes.
/// bytes.len must be exactly @sizeOf(T).
pub fn readIntBE(comptime T: type, bytes: []const u8) T {
if (T.is_signed) {
return @bitCast(T, readIntBE(@IntType(false, T.bit_count), bytes));
}
assert(bytes.len == @sizeOf(T));
if (T == u8) return bytes[0];
var result: T = 0;
{
comptime var i = 0;
inline while (i < @sizeOf(T)) : (i += 1) {
result = (result << 8) | T(bytes[i]);
}
}
return result;
/// Reads an integer from memory with bit count specified by T.
/// The bit count of T must be evenly divisible by 8.
/// This function cannot fail and cannot cause undefined behavior.
/// Assumes the endianness of memory is native. This means the function can
/// simply pointer cast memory.
pub fn readIntNative(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
comptime assert(T.bit_count % 8 == 0);
return @ptrCast(*align(1) const T, bytes).*;
}
/// Reads a little-endian int of type T from bytes.
/// bytes.len must be exactly @sizeOf(T).
pub fn readIntLE(comptime T: type, bytes: []const u8) T {
if (T.is_signed) {
return @bitCast(T, readIntLE(@IntType(false, T.bit_count), bytes));
}
assert(bytes.len == @sizeOf(T));
if (T == u8) return bytes[0];
var result: T = 0;
{
comptime var i = 0;
inline while (i < @sizeOf(T)) : (i += 1) {
result |= T(bytes[i]) << i * 8;
}
}
return result;
/// Reads an integer from memory with bit count specified by T.
/// The bit count of T must be evenly divisible by 8.
/// This function cannot fail and cannot cause undefined behavior.
/// Assumes the endianness of memory is foreign, so it must byte-swap.
pub fn readIntForeign(comptime T: type, bytes: *const [@sizeOf(T)]u8) T {
return @bswap(T, readIntNative(T, bytes));
}
test "readIntBE/LE" {
assert(readIntBE(u0, []u8{}) == 0x0);
assert(readIntLE(u0, []u8{}) == 0x0);
pub const readIntLittle = switch (builtin.endian) {
builtin.Endian.Little => readIntNative,
builtin.Endian.Big => readIntForeign,
};
assert(readIntBE(u8, []u8{0x32}) == 0x32);
assert(readIntLE(u8, []u8{0x12}) == 0x12);
pub const readIntBig = switch (builtin.endian) {
builtin.Endian.Little => readIntForeign,
builtin.Endian.Big => readIntNative,
};
assert(readIntBE(u16, []u8{0x12, 0x34}) == 0x1234);
assert(readIntLE(u16, []u8{0x12, 0x34}) == 0x3412);
assert(readIntBE(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024);
assert(readIntLE(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec);
assert(readIntBE(i8, []u8{0xff}) == -1);
assert(readIntLE(i8, []u8{0xfe}) == -2);
assert(readIntBE(i16, []u8{0xff, 0xfd}) == -3);
assert(readIntLE(i16, []u8{0xfc, 0xff}) == -4);
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
/// and ignores extra bytes.
/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
/// Assumes the endianness of memory is native. This means the function can
/// simply pointer cast memory.
pub fn readIntSliceNative(comptime T: type, bytes: []const u8) T {
assert(@sizeOf(u24) == 3);
assert(bytes.len >= @sizeOf(T));
// TODO https://github.com/ziglang/zig/issues/863
return readIntNative(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr));
}
/// Writes an integer to memory with size equal to bytes.len. Pads with zeroes
/// to fill the entire buffer provided.
/// value must be an integer.
pub fn writeInt(buf: []u8, value: var, endian: builtin.Endian) void {
const uint = @IntType(false, @typeOf(value).bit_count);
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
/// and ignores extra bytes.
/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
/// Assumes the endianness of memory is foreign, so it must byte-swap.
pub fn readIntSliceForeign(comptime T: type, bytes: []const u8) T {
return @bswap(T, readIntSliceNative(T, bytes));
}
pub const readIntSliceLittle = switch (builtin.endian) {
builtin.Endian.Little => readIntSliceNative,
builtin.Endian.Big => readIntSliceForeign,
};
pub const readIntSliceBig = switch (builtin.endian) {
builtin.Endian.Little => readIntSliceForeign,
builtin.Endian.Big => readIntSliceNative,
};
/// Reads an integer from memory with bit count specified by T.
/// The bit count of T must be evenly divisible by 8.
/// This function cannot fail and cannot cause undefined behavior.
pub fn readInt(comptime T: type, bytes: *const [@sizeOf(T)]u8, endian: builtin.Endian) T {
if (endian == builtin.endian) {
return readIntNative(T, bytes);
} else {
return readIntForeign(T, bytes);
}
}
/// Asserts that bytes.len >= @sizeOf(T). Reads the integer starting from index 0
/// and ignores extra bytes.
/// Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
pub fn readIntSlice(comptime T: type, bytes: []const u8, endian: builtin.Endian) T {
assert(@sizeOf(u24) == 3);
assert(bytes.len >= @sizeOf(T));
// TODO https://github.com/ziglang/zig/issues/863
return readInt(T, @ptrCast(*const [@sizeOf(T)]u8, bytes.ptr), endian);
}
test "comptime read/write int" {
comptime {
var bytes: [2]u8 = undefined;
std.mem.writeIntLittle(u16, &bytes, 0x1234);
const result = std.mem.readIntBig(u16, &bytes);
std.debug.assert(result == 0x3412);
}
comptime {
var bytes: [2]u8 = undefined;
std.mem.writeIntBig(u16, &bytes, 0x1234);
const result = std.mem.readIntLittle(u16, &bytes);
std.debug.assert(result == 0x3412);
}
}
test "readIntBig and readIntLittle" {
assert(readIntSliceBig(u0, []u8{}) == 0x0);
assert(readIntSliceLittle(u0, []u8{}) == 0x0);
assert(readIntSliceBig(u8, []u8{0x32}) == 0x32);
assert(readIntSliceLittle(u8, []u8{0x12}) == 0x12);
assert(readIntSliceBig(u16, []u8{ 0x12, 0x34 }) == 0x1234);
assert(readIntSliceLittle(u16, []u8{ 0x12, 0x34 }) == 0x3412);
assert(readIntSliceBig(u72, []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }) == 0x123456789abcdef024);
assert(readIntSliceLittle(u72, []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }) == 0xfedcba9876543210ec);
assert(readIntSliceBig(i8, []u8{0xff}) == -1);
assert(readIntSliceLittle(i8, []u8{0xfe}) == -2);
assert(readIntSliceBig(i16, []u8{ 0xff, 0xfd }) == -3);
assert(readIntSliceLittle(i16, []u8{ 0xfc, 0xff }) == -4);
}
/// Writes an integer to memory, storing it in twos-complement.
/// This function always succeeds, has defined behavior for all inputs, and
/// accepts any integer bit width.
/// This function stores in native endian, which means it is implemented as a simple
/// memory store.
pub fn writeIntNative(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
@ptrCast(*align(1) T, buf).* = value;
}
/// Writes an integer to memory, storing it in twos-complement.
/// This function always succeeds, has defined behavior for all inputs, but
/// the integer bit width must be divisible by 8.
/// This function stores in foreign endian, which means it does a @bswap first.
pub fn writeIntForeign(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
writeIntNative(T, buf, @bswap(T, value));
}
pub const writeIntLittle = switch (builtin.endian) {
builtin.Endian.Little => writeIntNative,
builtin.Endian.Big => writeIntForeign,
};
pub const writeIntBig = switch (builtin.endian) {
builtin.Endian.Little => writeIntForeign,
builtin.Endian.Big => writeIntNative,
};
/// Writes an integer to memory, storing it in twos-complement.
/// This function always succeeds, has defined behavior for all inputs, but
/// the integer bit width must be divisible by 8.
pub fn writeInt(comptime T: type, buffer: *[@sizeOf(T)]u8, value: T, endian: builtin.Endian) void {
comptime assert(T.bit_count % 8 == 0);
if (endian == builtin.endian) {
return writeIntNative(T, buffer, value);
} else {
return writeIntForeign(T, buffer, value);
}
}
/// Writes a twos-complement little-endian integer to memory.
/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
/// The bit count of T must be divisible by 8.
/// Any extra bytes in buffer after writing the integer are set to zero. To
/// avoid the branch to check for extra buffer bytes, use writeIntLittle
/// instead.
pub fn writeIntSliceLittle(comptime T: type, buffer: []u8, value: T) void {
comptime assert(@sizeOf(u24) == 3);
comptime assert(T.bit_count % 8 == 0);
assert(buffer.len >= @sizeOf(T));
// TODO I want to call writeIntLittle here but comptime eval facilities aren't good enough
const uint = @IntType(false, T.bit_count);
var bits = @truncate(uint, value);
switch (endian) {
builtin.Endian.Big => {
var index: usize = buf.len;
while (index != 0) {
index -= 1;
buf[index] = @truncate(u8, bits);
bits >>= 8;
}
},
builtin.Endian.Little => {
for (buf) |*b| {
b.* = @truncate(u8, bits);
bits >>= 8;
}
},
}
assert(bits == 0);
}
pub fn writeIntBE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
assert(T.bit_count % 8 == 0);
const uint = @IntType(false, T.bit_count);
if (uint == u0) {
return;
}
var bits = @bitCast(uint, value);
if (uint == u8) {
buf[0] = bits;
return;
}
var index: usize = buf.len;
while (index != 0) {
index -= 1;
buf[index] = @truncate(u8, bits);
bits >>= 8;
}
assert(bits == 0);
}
pub fn writeIntLE(comptime T: type, buf: *[@sizeOf(T)]u8, value: T) void {
assert(T.bit_count % 8 == 0);
const uint = @IntType(false, T.bit_count);
if (uint == u0) {
return;
}
var bits = @bitCast(uint, value);
if (uint == u8) {
buf[0] = bits;
return;
}
// FIXME: this should just be for (buf).
// See https://github.com/ziglang/zig/issues/1663
for (buf.*) |*b| {
for (buffer) |*b| {
b.* = @truncate(u8, bits);
bits >>= 8;
}
assert(bits == 0);
}
test "writeIntBE/LE" {
/// Writes a twos-complement big-endian integer to memory.
/// Asserts that buffer.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
/// The bit count of T must be divisible by 8.
/// Any extra bytes in buffer before writing the integer are set to zero. To
/// avoid the branch to check for extra buffer bytes, use writeIntBig instead.
pub fn writeIntSliceBig(comptime T: type, buffer: []u8, value: T) void {
comptime assert(@sizeOf(u24) == 3);
comptime assert(T.bit_count % 8 == 0);
assert(buffer.len >= @sizeOf(T));
// TODO I want to call writeIntBig here but comptime eval facilities aren't good enough
const uint = @IntType(false, T.bit_count);
var bits = @truncate(uint, value);
var index: usize = buffer.len;
while (index != 0) {
index -= 1;
buffer[index] = @truncate(u8, bits);
bits >>= 8;
}
}
pub const writeIntSliceNative = switch (builtin.endian) {
builtin.Endian.Little => writeIntSliceLittle,
builtin.Endian.Big => writeIntSliceBig,
};
pub const writeIntSliceForeign = switch (builtin.endian) {
builtin.Endian.Little => writeIntSliceBig,
builtin.Endian.Big => writeIntSliceLittle,
};
/// Writes a twos-complement integer to memory, with the specified endianness.
/// Asserts that buf.len >= @sizeOf(T). Note that @sizeOf(u24) is 3.
/// The bit count of T must be evenly divisible by 8.
/// Any extra bytes in buffer not part of the integer are set to zero, with
/// respect to endianness. To avoid the branch to check for extra buffer bytes,
/// use writeInt instead.
pub fn writeIntSlice(comptime T: type, buffer: []u8, value: T, endian: builtin.Endian) void {
comptime assert(T.bit_count % 8 == 0);
switch (endian) {
builtin.Endian.Little => return writeIntSliceLittle(T, buffer, value),
builtin.Endian.Big => return writeIntSliceBig(T, buffer, value),
}
}
test "writeIntBig and writeIntLittle" {
var buf0: [0]u8 = undefined;
var buf1: [1]u8 = undefined;
var buf2: [2]u8 = undefined;
var buf9: [9]u8 = undefined;
writeIntBE(u0, &buf0, 0x0);
writeIntBig(u0, &buf0, 0x0);
assert(eql_slice_u8(buf0[0..], []u8{}));
writeIntLE(u0, &buf0, 0x0);
writeIntLittle(u0, &buf0, 0x0);
assert(eql_slice_u8(buf0[0..], []u8{}));
writeIntBE(u8, &buf1, 0x12);
writeIntBig(u8, &buf1, 0x12);
assert(eql_slice_u8(buf1[0..], []u8{0x12}));
writeIntLE(u8, &buf1, 0x34);
writeIntLittle(u8, &buf1, 0x34);
assert(eql_slice_u8(buf1[0..], []u8{0x34}));
writeIntBE(u16, &buf2, 0x1234);
writeIntBig(u16, &buf2, 0x1234);
assert(eql_slice_u8(buf2[0..], []u8{ 0x12, 0x34 }));
writeIntLE(u16, &buf2, 0x5678);
writeIntLittle(u16, &buf2, 0x5678);
assert(eql_slice_u8(buf2[0..], []u8{ 0x78, 0x56 }));
writeIntBE(u72, &buf9, 0x123456789abcdef024);
writeIntBig(u72, &buf9, 0x123456789abcdef024);
assert(eql_slice_u8(buf9[0..], []u8{ 0x12, 0x34, 0x56, 0x78, 0x9a, 0xbc, 0xde, 0xf0, 0x24 }));
writeIntLE(u72, &buf9, 0xfedcba9876543210ec);
writeIntLittle(u72, &buf9, 0xfedcba9876543210ec);
assert(eql_slice_u8(buf9[0..], []u8{ 0xec, 0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe }));
writeIntBE(i8, &buf1, -1);
writeIntBig(i8, &buf1, -1);
assert(eql_slice_u8(buf1[0..], []u8{0xff}));
writeIntLE(i8, &buf1, -2);
writeIntLittle(i8, &buf1, -2);
assert(eql_slice_u8(buf1[0..], []u8{0xfe}));
writeIntBE(i16, &buf2, -3);
writeIntBig(i16, &buf2, -3);
assert(eql_slice_u8(buf2[0..], []u8{ 0xff, 0xfd }));
writeIntLE(i16, &buf2, -4);
writeIntLittle(i16, &buf2, -4);
assert(eql_slice_u8(buf2[0..], []u8{ 0xfc, 0xff }));
}
@ -737,12 +831,12 @@ fn testReadIntImpl() void {
0x56,
0x78,
};
assert(readInt(bytes, u32, builtin.Endian.Big) == 0x12345678);
assert(readIntBE(u32, bytes) == 0x12345678);
assert(readIntBE(i32, bytes) == 0x12345678);
assert(readInt(bytes, u32, builtin.Endian.Little) == 0x78563412);
assert(readIntLE(u32, bytes) == 0x78563412);
assert(readIntLE(i32, bytes) == 0x78563412);
assert(readInt(u32, &bytes, builtin.Endian.Big) == 0x12345678);
assert(readIntBig(u32, &bytes) == 0x12345678);
assert(readIntBig(i32, &bytes) == 0x12345678);
assert(readInt(u32, &bytes, builtin.Endian.Little) == 0x78563412);
assert(readIntLittle(u32, &bytes) == 0x78563412);
assert(readIntLittle(i32, &bytes) == 0x78563412);
}
{
const buf = []u8{
@ -751,7 +845,7 @@ fn testReadIntImpl() void {
0x12,
0x34,
};
const answer = readInt(buf, u64, builtin.Endian.Big);
const answer = readInt(u32, &buf, builtin.Endian.Big);
assert(answer == 0x00001234);
}
{
@ -761,7 +855,7 @@ fn testReadIntImpl() void {
0x00,
0x00,
};
const answer = readInt(buf, u64, builtin.Endian.Little);
const answer = readInt(u32, &buf, builtin.Endian.Little);
assert(answer == 0x00003412);
}
{
@ -769,21 +863,33 @@ fn testReadIntImpl() void {
0xff,
0xfe,
};
assert(readIntBE(u16, bytes) == 0xfffe);
assert(readIntBE(i16, bytes) == -0x0002);
assert(readIntLE(u16, bytes) == 0xfeff);
assert(readIntLE(i16, bytes) == -0x0101);
assert(readIntBig(u16, &bytes) == 0xfffe);
assert(readIntBig(i16, &bytes) == -0x0002);
assert(readIntLittle(u16, &bytes) == 0xfeff);
assert(readIntLittle(i16, &bytes) == -0x0101);
}
}
test "testWriteInt" {
test "std.mem.writeIntSlice" {
testWriteIntImpl();
comptime testWriteIntImpl();
}
fn testWriteIntImpl() void {
var bytes: [8]u8 = undefined;
writeInt(bytes[0..], u64(0x12345678CAFEBABE), builtin.Endian.Big);
writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}));
writeIntSlice(u0, bytes[0..], 0, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00,
}));
writeIntSlice(u64, bytes[0..], 0x12345678CAFEBABE, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x12,
0x34,
@ -795,7 +901,7 @@ fn testWriteIntImpl() void {
0xBE,
}));
writeInt(bytes[0..], u64(0xBEBAFECA78563412), builtin.Endian.Little);
writeIntSlice(u64, bytes[0..], 0xBEBAFECA78563412, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x12,
0x34,
@ -807,7 +913,7 @@ fn testWriteIntImpl() void {
0xBE,
}));
writeInt(bytes[0..], u32(0x12345678), builtin.Endian.Big);
writeIntSlice(u32, bytes[0..], 0x12345678, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x00,
0x00,
@ -819,7 +925,7 @@ fn testWriteIntImpl() void {
0x78,
}));
writeInt(bytes[0..], u32(0x78563412), builtin.Endian.Little);
writeIntSlice(u32, bytes[0..], 0x78563412, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x12,
0x34,
@ -831,7 +937,7 @@ fn testWriteIntImpl() void {
0x00,
}));
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Big);
writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Big);
assert(eql(u8, bytes, []u8{
0x00,
0x00,
@ -843,7 +949,7 @@ fn testWriteIntImpl() void {
0x34,
}));
writeInt(bytes[0..], u16(0x1234), builtin.Endian.Little);
writeIntSlice(u16, bytes[0..], 0x1234, builtin.Endian.Little);
assert(eql(u8, bytes, []u8{
0x34,
0x12,
@ -941,29 +1047,52 @@ test "std.mem.rotate" {
}));
}
// TODO: When https://github.com/ziglang/zig/issues/649 is solved these can be done by
// endian-casting the pointer and then dereferencing
pub fn endianSwapIfLe(comptime T: type, x: T) T {
return endianSwapIf(builtin.Endian.Little, T, x);
/// Converts a little-endian integer to host endianness.
pub fn littleToNative(comptime T: type, x: T) T {
return switch (builtin.endian) {
builtin.Endian.Little => x,
builtin.Endian.Big => @bswap(T, x),
};
}
pub fn endianSwapIfBe(comptime T: type, x: T) T {
return endianSwapIf(builtin.Endian.Big, T, x);
/// Converts a big-endian integer to host endianness.
pub fn bigToNative(comptime T: type, x: T) T {
return switch (builtin.endian) {
builtin.Endian.Little => @bswap(T, x),
builtin.Endian.Big => x,
};
}
pub fn endianSwapIf(endian: builtin.Endian, comptime T: type, x: T) T {
return if (builtin.endian == endian) endianSwap(T, x) else x;
/// Converts an integer from specified endianness to host endianness.
pub fn toNative(comptime T: type, x: T, endianness_of_x: builtin.Endian) T {
return switch (endianness_of_x) {
builtin.Endian.Little => littleToNative(T, x),
builtin.Endian.Big => bigToNative(T, x),
};
}
pub fn endianSwap(comptime T: type, x: T) T {
var buf: [@sizeOf(T)]u8 = undefined;
mem.writeInt(buf[0..], x, builtin.Endian.Little);
return mem.readInt(buf, T, builtin.Endian.Big);
/// Converts an integer which has host endianness to the desired endianness.
pub fn nativeTo(comptime T: type, x: T, desired_endianness: builtin.Endian) T {
return switch (desired_endianness) {
builtin.Endian.Little => nativeToLittle(T, x),
builtin.Endian.Big => nativeToBig(T, x),
};
}
test "std.mem.endianSwap" {
assert(endianSwap(u32, 0xDEADBEEF) == 0xEFBEADDE);
/// Converts an integer which has host endianness to little endian.
pub fn nativeToLittle(comptime T: type, x: T) T {
return switch (builtin.endian) {
builtin.Endian.Little => x,
builtin.Endian.Big => @bswap(T, x),
};
}
/// Converts an integer which has host endianness to big endian.
pub fn nativeToBig(comptime T: type, x: T) T {
return switch (builtin.endian) {
builtin.Endian.Little => @bswap(T, x),
builtin.Endian.Big => x,
};
}
fn AsBytesReturnType(comptime P: type) type {

View File

@ -76,6 +76,25 @@ test "std.meta.tagName" {
debug.assert(mem.eql(u8, tagName(u2b), "D"));
}
pub fn stringToEnum(comptime T: type, str: []const u8) ?T {
inline for (@typeInfo(T).Enum.fields) |enumField| {
if (std.mem.eql(u8, str, enumField.name)) {
return @field(T, enumField.name);
}
}
return null;
}
test "std.meta.stringToEnum" {
const E1 = enum {
A,
B,
};
debug.assert(E1.A == stringToEnum(E1, "A").?);
debug.assert(E1.B == stringToEnum(E1, "B").?);
debug.assert(null == stringToEnum(E1, "C"));
}
pub fn bitCount(comptime T: type) u32 {
return switch (@typeInfo(T)) {
TypeId.Int => |info| info.bits,
@ -483,3 +502,32 @@ test "std.meta.eql" {
debug.assert(eql(EU.tst(false), EU.tst(false)));
debug.assert(!eql(EU.tst(false), EU.tst(true)));
}
test "intToEnum with error return" {
const E1 = enum {
A,
};
const E2 = enum {
A,
B,
};
var zero: u8 = 0;
var one: u16 = 1;
debug.assert(intToEnum(E1, zero) catch unreachable == E1.A);
debug.assert(intToEnum(E2, one) catch unreachable == E2.B);
debug.assertError(intToEnum(E1, one), error.InvalidEnumTag);
}
pub const IntToEnumError = error{InvalidEnumTag};
pub fn intToEnum(comptime Tag: type, tag_int: var) IntToEnumError!Tag {
comptime var i = 0;
inline while (i != @memberCount(Tag)) : (i += 1) {
const this_tag_value = @field(Tag, @memberName(Tag, i));
if (tag_int == @enumToInt(this_tag_value)) {
return this_tag_value;
}
}
return error.InvalidEnumTag;
}

View File

@ -23,7 +23,7 @@ pub const Address = struct {
.os_addr = posix.sockaddr{
.in = posix.sockaddr_in{
.family = posix.AF_INET,
.port = std.mem.endianSwapIfLe(u16, _port),
.port = mem.nativeToBig(u16, _port),
.addr = ip4,
.zero = []u8{0} ** 8,
},
@ -37,7 +37,7 @@ pub const Address = struct {
.os_addr = posix.sockaddr{
.in6 = posix.sockaddr_in6{
.family = posix.AF_INET6,
.port = std.mem.endianSwapIfLe(u16, _port),
.port = mem.nativeToBig(u16, _port),
.flowinfo = 0,
.addr = ip6.addr,
.scope_id = ip6.scope_id,
@ -47,7 +47,7 @@ pub const Address = struct {
}
pub fn port(self: Address) u16 {
return std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
return mem.bigToNative(u16, self.os_addr.in.port);
}
pub fn initPosix(addr: posix.sockaddr) Address {
@ -57,12 +57,12 @@ pub const Address = struct {
pub fn format(self: *const Address, out_stream: var) !void {
switch (self.os_addr.in.family) {
posix.AF_INET => {
const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in.port);
const native_endian_port = mem.bigToNative(u16, self.os_addr.in.port);
const bytes = ([]const u8)((*self.os_addr.in.addr)[0..1]);
try out_stream.print("{}.{}.{}.{}:{}", bytes[0], bytes[1], bytes[2], bytes[3], native_endian_port);
},
posix.AF_INET6 => {
const native_endian_port = std.mem.endianSwapIfLe(u16, self.os_addr.in6.port);
const native_endian_port = mem.bigToNative(u16, self.os_addr.in6.port);
try out_stream.print("[TODO render ip6 address]:{}", native_endian_port);
},
else => try out_stream.write("(unrecognized address family)"),
@ -193,7 +193,7 @@ pub fn parseIp6(buf: []const u8) !Ip6Addr {
}
test "std.net.parseIp4" {
assert((try parseIp4("127.0.0.1")) == std.mem.endianSwapIfLe(u32, 0x7f000001));
assert((try parseIp4("127.0.0.1")) == mem.bigToNative(u32, 0x7f000001));
testParseIp4Fail("256.0.0.1", error.Overflow);
testParseIp4Fail("x.0.0.1", error.InvalidCharacter);

View File

@ -390,6 +390,19 @@ pub const ChildProcess = struct {
setUpChildIo(self.stdout_behavior, stdout_pipe[1], posix.STDOUT_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
setUpChildIo(self.stderr_behavior, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) catch |err| forkChildErrReport(err_pipe[1], err);
if (self.stdin_behavior == StdIo.Pipe) {
os.close(stdin_pipe[0]);
os.close(stdin_pipe[1]);
}
if (self.stdout_behavior == StdIo.Pipe) {
os.close(stdout_pipe[0]);
os.close(stdout_pipe[1]);
}
if (self.stderr_behavior == StdIo.Pipe) {
os.close(stderr_pipe[0]);
os.close(stderr_pipe[1]);
}
if (self.cwd) |cwd| {
os.changeCurDir(self.allocator, cwd) catch |err| forkChildErrReport(err_pipe[1], err);
}
@ -794,10 +807,10 @@ const ErrInt = @IntType(false, @sizeOf(anyerror) * 8);
fn writeIntFd(fd: i32, value: ErrInt) !void {
const stream = &os.File.openHandle(fd).outStream().stream;
stream.writeIntNe(ErrInt, value) catch return error.SystemResources;
stream.writeIntNative(ErrInt, value) catch return error.SystemResources;
}
fn readIntFd(fd: i32) !ErrInt {
const stream = &os.File.openHandle(fd).inStream().stream;
return stream.readIntNe(ErrInt) catch return error.SystemResources;
return stream.readIntNative(ErrInt) catch return error.SystemResources;
}

View File

@ -228,9 +228,16 @@ pub const File = struct {
return os.isTty(self.handle);
}
pub fn seekForward(self: File, amount: isize) !void {
pub const SeekError = error{
/// TODO make this error impossible to get
Overflow,
Unseekable,
Unexpected,
};
pub fn seekForward(self: File, amount: isize) SeekError!void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const result = posix.lseek(self.handle, amount, posix.SEEK_CUR);
const err = posix.getErrno(result);
if (err > 0) {
@ -259,9 +266,9 @@ pub const File = struct {
}
}
pub fn seekTo(self: File, pos: usize) !void {
pub fn seekTo(self: File, pos: usize) SeekError!void {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const ipos = try math.cast(isize, pos);
const result = posix.lseek(self.handle, ipos, posix.SEEK_SET);
const err = posix.getErrno(result);
@ -293,9 +300,16 @@ pub const File = struct {
}
}
pub fn getPos(self: File) !usize {
pub const GetSeekPosError = error{
Overflow,
SystemResources,
Unseekable,
Unexpected,
};
pub fn getPos(self: File) GetSeekPosError!usize {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const result = posix.lseek(self.handle, 0, posix.SEEK_CUR);
const err = posix.getErrno(result);
if (err > 0) {
@ -323,13 +337,13 @@ pub const File = struct {
}
assert(pos >= 0);
return math.cast(usize, pos) catch error.FilePosLargerThanPointerRange;
return math.cast(usize, pos);
},
else => @compileError("unsupported OS"),
}
}
pub fn getEndPos(self: File) !usize {
pub fn getEndPos(self: File) GetSeekPosError!usize {
if (is_posix) {
const stat = try os.posixFStat(self.handle);
return @intCast(usize, stat.size);
@ -431,6 +445,18 @@ pub const File = struct {
};
}
pub fn seekableStream(file: File) SeekableStream {
return SeekableStream{
.file = file,
.stream = SeekableStream.Stream{
.seekToFn = SeekableStream.seekToFn,
.seekForwardFn = SeekableStream.seekForwardFn,
.getPosFn = SeekableStream.getPosFn,
.getEndPosFn = SeekableStream.getEndPosFn,
},
};
}
/// Implementation of io.InStream trait for File
pub const InStream = struct {
file: File,
@ -458,4 +484,32 @@ pub const File = struct {
return self.file.write(bytes);
}
};
/// Implementation of io.SeekableStream trait for File
pub const SeekableStream = struct {
file: File,
stream: Stream,
pub const Stream = io.SeekableStream(SeekError, GetSeekPosError);
pub fn seekToFn(seekable_stream: *Stream, pos: usize) SeekError!void {
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
return self.file.seekTo(pos);
}
pub fn seekForwardFn(seekable_stream: *Stream, amt: isize) SeekError!void {
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
return self.file.seekForward(amt);
}
pub fn getEndPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
return self.file.getEndPos();
}
pub fn getPosFn(seekable_stream: *Stream) GetSeekPosError!usize {
const self = @fieldParentPtr(SeekableStream, "stream", seekable_stream);
return self.file.getPos();
}
};
};

121
std/os/freebsd/errno.zig Normal file
View File

@ -0,0 +1,121 @@
pub const EPERM = 1; // Operation not permitted
pub const ENOENT = 2; // No such file or directory
pub const ESRCH = 3; // No such process
pub const EINTR = 4; // Interrupted system call
pub const EIO = 5; // Input/output error
pub const ENXIO = 6; // Device not configured
pub const E2BIG = 7; // Argument list too long
pub const ENOEXEC = 8; // Exec format error
pub const EBADF = 9; // Bad file descriptor
pub const ECHILD = 10; // No child processes
pub const EDEADLK = 11; // Resource deadlock avoided
// 11 was EAGAIN
pub const ENOMEM = 12; // Cannot allocate memory
pub const EACCES = 13; // Permission denied
pub const EFAULT = 14; // Bad address
pub const ENOTBLK = 15; // Block device required
pub const EBUSY = 16; // Device busy
pub const EEXIST = 17; // File exists
pub const EXDEV = 18; // Cross-device link
pub const ENODEV = 19; // Operation not supported by device
pub const ENOTDIR = 20; // Not a directory
pub const EISDIR = 21; // Is a directory
pub const EINVAL = 22; // Invalid argument
pub const ENFILE = 23; // Too many open files in system
pub const EMFILE = 24; // Too many open files
pub const ENOTTY = 25; // Inappropriate ioctl for device
pub const ETXTBSY = 26; // Text file busy
pub const EFBIG = 27; // File too large
pub const ENOSPC = 28; // No space left on device
pub const ESPIPE = 29; // Illegal seek
pub const EROFS = 30; // Read-only filesystem
pub const EMLINK = 31; // Too many links
pub const EPIPE = 32; // Broken pipe
// math software
pub const EDOM = 33; // Numerical argument out of domain
pub const ERANGE = 34; // Result too large
// non-blocking and interrupt i/o
pub const EAGAIN = 35; // Resource temporarily unavailable
pub const EWOULDBLOCK = EAGAIN; // Operation would block
pub const EINPROGRESS = 36; // Operation now in progress
pub const EALREADY = 37; // Operation already in progress
// ipc/network software -- argument errors
pub const ENOTSOCK = 38; // Socket operation on non-socket
pub const EDESTADDRREQ = 39; // Destination address required
pub const EMSGSIZE = 40; // Message too long
pub const EPROTOTYPE = 41; // Protocol wrong type for socket
pub const ENOPROTOOPT = 42; // Protocol not available
pub const EPROTONOSUPPORT = 43; // Protocol not supported
pub const ESOCKTNOSUPPORT = 44; // Socket type not supported
pub const EOPNOTSUPP = 45; // Operation not supported
pub const ENOTSUP = EOPNOTSUPP; // Operation not supported
pub const EPFNOSUPPORT = 46; // Protocol family not supported
pub const EAFNOSUPPORT = 47; // Address family not supported by protocol family
pub const EADDRINUSE = 48; // Address already in use
pub const EADDRNOTAVAIL = 49; // Can't assign requested address
// ipc/network software -- operational errors
pub const ENETDOWN = 50; // Network is down
pub const ENETUNREACH = 51; // Network is unreachable
pub const ENETRESET = 52; // Network dropped connection on reset
pub const ECONNABORTED = 53; // Software caused connection abort
pub const ECONNRESET = 54; // Connection reset by peer
pub const ENOBUFS = 55; // No buffer space available
pub const EISCONN = 56; // Socket is already connected
pub const ENOTCONN = 57; // Socket is not connected
pub const ESHUTDOWN = 58; // Can't send after socket shutdown
pub const ETOOMANYREFS = 59; // Too many references: can't splice
pub const ETIMEDOUT = 60; // Operation timed out
pub const ECONNREFUSED = 61; // Connection refused
pub const ELOOP = 62; // Too many levels of symbolic links
pub const ENAMETOOLONG = 63; // File name too long
// should be rearranged
pub const EHOSTDOWN = 64; // Host is down
pub const EHOSTUNREACH = 65; // No route to host
pub const ENOTEMPTY = 66; // Directory not empty
// quotas & mush
pub const EPROCLIM = 67; // Too many processes
pub const EUSERS = 68; // Too many users
pub const EDQUOT = 69; // Disc quota exceeded
// Network File System
pub const ESTALE = 70; // Stale NFS file handle
pub const EREMOTE = 71; // Too many levels of remote in path
pub const EBADRPC = 72; // RPC struct is bad
pub const ERPCMISMATCH = 73; // RPC version wrong
pub const EPROGUNAVAIL = 74; // RPC prog. not avail
pub const EPROGMISMATCH = 75; // Program version wrong
pub const EPROCUNAVAIL = 76; // Bad procedure for program
pub const ENOLCK = 77; // No locks available
pub const ENOSYS = 78; // Function not implemented
pub const EFTYPE = 79; // Inappropriate file type or format
pub const EAUTH = 80; // Authentication error
pub const ENEEDAUTH = 81; // Need authenticator
pub const EIDRM = 82; // Identifier removed
pub const ENOMSG = 83; // No message of desired type
pub const EOVERFLOW = 84; // Value too large to be stored in data type
pub const ECANCELED = 85; // Operation canceled
pub const EILSEQ = 86; // Illegal byte sequence
pub const ENOATTR = 87; // Attribute not found
pub const EDOOFUS = 88; // Programming error
pub const EBADMSG = 89; // Bad message
pub const EMULTIHOP = 90; // Multihop attempted
pub const ENOLINK = 91; // Link has been severed
pub const EPROTO = 92; // Protocol error
pub const ENOTCAPABLE = 93; // Capabilities insufficient
pub const ECAPMODE = 94; // Not permitted in capability mode
pub const ENOTRECOVERABLE = 95; // State not recoverable
pub const EOWNERDEAD = 96; // Previous owner died
pub const ELAST = 96; // Must be equal largest errno

801
std/os/freebsd/index.zig Normal file
View File

@ -0,0 +1,801 @@
const assert = @import("../debug.zig").assert;
const builtin = @import("builtin");
const arch = switch (builtin.arch) {
builtin.Arch.x86_64 => @import("x86_64.zig"),
else => @compileError("unsupported arch"),
};
pub use @import("syscall.zig");
pub use @import("errno.zig");
const std = @import("../../index.zig");
const c = std.c;
const maxInt = std.math.maxInt;
pub const Kevent = c.Kevent;
pub const PATH_MAX = 1024;
pub const STDIN_FILENO = 0;
pub const STDOUT_FILENO = 1;
pub const STDERR_FILENO = 2;
pub const PROT_NONE = 0;
pub const PROT_READ = 1;
pub const PROT_WRITE = 2;
pub const PROT_EXEC = 4;
pub const MAP_FAILED = maxInt(usize);
pub const MAP_SHARED = 0x0001;
pub const MAP_PRIVATE = 0x0002;
pub const MAP_FIXED = 0x0010;
pub const MAP_STACK = 0x0400;
pub const MAP_NOSYNC = 0x0800;
pub const MAP_ANON = 0x1000;
pub const MAP_ANONYMOUS = MAP_ANON;
pub const MAP_FILE = 0;
pub const MAP_NORESERVE = 0;
pub const MAP_GUARD = 0x00002000;
pub const MAP_EXCL = 0x00004000;
pub const MAP_NOCORE = 0x00020000;
pub const MAP_PREFAULT_READ = 0x00040000;
pub const MAP_32BIT = 0x00080000;
pub const WNOHANG = 1;
pub const WUNTRACED = 2;
pub const WSTOPPED = WUNTRACED;
pub const WCONTINUED = 4;
pub const WNOWAIT = 8;
pub const WEXITED = 16;
pub const WTRAPPED = 32;
pub const SA_ONSTACK = 0x0001;
pub const SA_RESTART = 0x0002;
pub const SA_RESETHAND = 0x0004;
pub const SA_NOCLDSTOP = 0x0008;
pub const SA_NODEFER = 0x0010;
pub const SA_NOCLDWAIT = 0x0020;
pub const SA_SIGINFO = 0x0040;
pub const SIGHUP = 1;
pub const SIGINT = 2;
pub const SIGQUIT = 3;
pub const SIGILL = 4;
pub const SIGTRAP = 5;
pub const SIGABRT = 6;
pub const SIGIOT = SIGABRT;
pub const SIGEMT = 7;
pub const SIGFPE = 8;
pub const SIGKILL = 9;
pub const SIGBUS = 10;
pub const SIGSEGV = 11;
pub const SIGSYS = 12;
pub const SIGPIPE = 13;
pub const SIGALRM = 14;
pub const SIGTERM = 15;
pub const SIGURG = 16;
pub const SIGSTOP = 17;
pub const SIGTSTP = 18;
pub const SIGCONT = 19;
pub const SIGCHLD = 20;
pub const SIGTTIN = 21;
pub const SIGTTOU = 22;
pub const SIGIO = 23;
pub const SIGXCPU = 24;
pub const SIGXFSZ = 25;
pub const SIGVTALRM = 26;
pub const SIGPROF = 27;
pub const SIGWINCH = 28;
pub const SIGINFO = 29;
pub const SIGUSR1 = 30;
pub const SIGUSR2 = 31;
pub const SIGTHR = 32;
pub const SIGLWP = SIGTHR;
pub const SIGLIBRT = 33;
pub const SIGRTMIN = 65;
pub const SIGRTMAX = 126;
pub const O_RDONLY = 0o0;
pub const O_WRONLY = 0o1;
pub const O_RDWR = 0o2;
pub const O_ACCMODE = 0o3;
pub const O_CREAT = 0o100;
pub const O_EXCL = 0o200;
pub const O_NOCTTY = 0o400;
pub const O_TRUNC = 0o1000;
pub const O_APPEND = 0o2000;
pub const O_NONBLOCK = 0o4000;
pub const O_DSYNC = 0o10000;
pub const O_SYNC = 0o4010000;
pub const O_RSYNC = 0o4010000;
pub const O_DIRECTORY = 0o200000;
pub const O_NOFOLLOW = 0o400000;
pub const O_CLOEXEC = 0o2000000;
pub const O_ASYNC = 0o20000;
pub const O_DIRECT = 0o40000;
pub const O_LARGEFILE = 0;
pub const O_NOATIME = 0o1000000;
pub const O_PATH = 0o10000000;
pub const O_TMPFILE = 0o20200000;
pub const O_NDELAY = O_NONBLOCK;
pub const F_DUPFD = 0;
pub const F_GETFD = 1;
pub const F_SETFD = 2;
pub const F_GETFL = 3;
pub const F_SETFL = 4;
pub const F_SETOWN = 8;
pub const F_GETOWN = 9;
pub const F_SETSIG = 10;
pub const F_GETSIG = 11;
pub const F_GETLK = 5;
pub const F_SETLK = 6;
pub const F_SETLKW = 7;
pub const F_SETOWN_EX = 15;
pub const F_GETOWN_EX = 16;
pub const F_GETOWNER_UIDS = 17;
pub const SEEK_SET = 0;
pub const SEEK_CUR = 1;
pub const SEEK_END = 2;
pub const SIG_BLOCK = 1;
pub const SIG_UNBLOCK = 2;
pub const SIG_SETMASK = 3;
pub const SOCK_STREAM = 1;
pub const SOCK_DGRAM = 2;
pub const SOCK_RAW = 3;
pub const SOCK_RDM = 4;
pub const SOCK_SEQPACKET = 5;
pub const SOCK_CLOEXEC = 0x10000000;
pub const SOCK_NONBLOCK = 0x20000000;
pub const PROTO_ip = 0o000;
pub const PROTO_icmp = 0o001;
pub const PROTO_igmp = 0o002;
pub const PROTO_ggp = 0o003;
pub const PROTO_ipencap = 0o004;
pub const PROTO_st = 0o005;
pub const PROTO_tcp = 0o006;
pub const PROTO_egp = 0o010;
pub const PROTO_pup = 0o014;
pub const PROTO_udp = 0o021;
pub const PROTO_hmp = 0o024;
pub const PROTO_xns_idp = 0o026;
pub const PROTO_rdp = 0o033;
pub const PROTO_iso_tp4 = 0o035;
pub const PROTO_xtp = 0o044;
pub const PROTO_ddp = 0o045;
pub const PROTO_idpr_cmtp = 0o046;
pub const PROTO_ipv6 = 0o051;
pub const PROTO_ipv6_route = 0o053;
pub const PROTO_ipv6_frag = 0o054;
pub const PROTO_idrp = 0o055;
pub const PROTO_rsvp = 0o056;
pub const PROTO_gre = 0o057;
pub const PROTO_esp = 0o062;
pub const PROTO_ah = 0o063;
pub const PROTO_skip = 0o071;
pub const PROTO_ipv6_icmp = 0o072;
pub const PROTO_ipv6_nonxt = 0o073;
pub const PROTO_ipv6_opts = 0o074;
pub const PROTO_rspf = 0o111;
pub const PROTO_vmtp = 0o121;
pub const PROTO_ospf = 0o131;
pub const PROTO_ipip = 0o136;
pub const PROTO_encap = 0o142;
pub const PROTO_pim = 0o147;
pub const PROTO_raw = 0o377;
pub const PF_UNSPEC = 0;
pub const PF_LOCAL = 1;
pub const PF_UNIX = PF_LOCAL;
pub const PF_FILE = PF_LOCAL;
pub const PF_INET = 2;
pub const PF_AX25 = 3;
pub const PF_IPX = 4;
pub const PF_APPLETALK = 5;
pub const PF_NETROM = 6;
pub const PF_BRIDGE = 7;
pub const PF_ATMPVC = 8;
pub const PF_X25 = 9;
pub const PF_INET6 = 10;
pub const PF_ROSE = 11;
pub const PF_DECnet = 12;
pub const PF_NETBEUI = 13;
pub const PF_SECURITY = 14;
pub const PF_KEY = 15;
pub const PF_NETLINK = 16;
pub const PF_ROUTE = PF_NETLINK;
pub const PF_PACKET = 17;
pub const PF_ASH = 18;
pub const PF_ECONET = 19;
pub const PF_ATMSVC = 20;
pub const PF_RDS = 21;
pub const PF_SNA = 22;
pub const PF_IRDA = 23;
pub const PF_PPPOX = 24;
pub const PF_WANPIPE = 25;
pub const PF_LLC = 26;
pub const PF_IB = 27;
pub const PF_MPLS = 28;
pub const PF_CAN = 29;
pub const PF_TIPC = 30;
pub const PF_BLUETOOTH = 31;
pub const PF_IUCV = 32;
pub const PF_RXRPC = 33;
pub const PF_ISDN = 34;
pub const PF_PHONET = 35;
pub const PF_IEEE802154 = 36;
pub const PF_CAIF = 37;
pub const PF_ALG = 38;
pub const PF_NFC = 39;
pub const PF_VSOCK = 40;
pub const PF_MAX = 41;
pub const AF_UNSPEC = PF_UNSPEC;
pub const AF_LOCAL = PF_LOCAL;
pub const AF_UNIX = AF_LOCAL;
pub const AF_FILE = AF_LOCAL;
pub const AF_INET = PF_INET;
pub const AF_AX25 = PF_AX25;
pub const AF_IPX = PF_IPX;
pub const AF_APPLETALK = PF_APPLETALK;
pub const AF_NETROM = PF_NETROM;
pub const AF_BRIDGE = PF_BRIDGE;
pub const AF_ATMPVC = PF_ATMPVC;
pub const AF_X25 = PF_X25;
pub const AF_INET6 = PF_INET6;
pub const AF_ROSE = PF_ROSE;
pub const AF_DECnet = PF_DECnet;
pub const AF_NETBEUI = PF_NETBEUI;
pub const AF_SECURITY = PF_SECURITY;
pub const AF_KEY = PF_KEY;
pub const AF_NETLINK = PF_NETLINK;
pub const AF_ROUTE = PF_ROUTE;
pub const AF_PACKET = PF_PACKET;
pub const AF_ASH = PF_ASH;
pub const AF_ECONET = PF_ECONET;
pub const AF_ATMSVC = PF_ATMSVC;
pub const AF_RDS = PF_RDS;
pub const AF_SNA = PF_SNA;
pub const AF_IRDA = PF_IRDA;
pub const AF_PPPOX = PF_PPPOX;
pub const AF_WANPIPE = PF_WANPIPE;
pub const AF_LLC = PF_LLC;
pub const AF_IB = PF_IB;
pub const AF_MPLS = PF_MPLS;
pub const AF_CAN = PF_CAN;
pub const AF_TIPC = PF_TIPC;
pub const AF_BLUETOOTH = PF_BLUETOOTH;
pub const AF_IUCV = PF_IUCV;
pub const AF_RXRPC = PF_RXRPC;
pub const AF_ISDN = PF_ISDN;
pub const AF_PHONET = PF_PHONET;
pub const AF_IEEE802154 = PF_IEEE802154;
pub const AF_CAIF = PF_CAIF;
pub const AF_ALG = PF_ALG;
pub const AF_NFC = PF_NFC;
pub const AF_VSOCK = PF_VSOCK;
pub const AF_MAX = PF_MAX;
pub const DT_UNKNOWN = 0;
pub const DT_FIFO = 1;
pub const DT_CHR = 2;
pub const DT_DIR = 4;
pub const DT_BLK = 6;
pub const DT_REG = 8;
pub const DT_LNK = 10;
pub const DT_SOCK = 12;
pub const DT_WHT = 14;
/// add event to kq (implies enable)
pub const EV_ADD = 0x0001;
/// delete event from kq
pub const EV_DELETE = 0x0002;
/// enable event
pub const EV_ENABLE = 0x0004;
/// disable event (not reported)
pub const EV_DISABLE = 0x0008;
/// only report one occurrence
pub const EV_ONESHOT = 0x0010;
/// clear event state after reporting
pub const EV_CLEAR = 0x0020;
/// force immediate event output
/// ... with or without EV_ERROR
/// ... use KEVENT_FLAG_ERROR_EVENTS
/// on syscalls supporting flags
pub const EV_RECEIPT = 0x0040;
/// disable event after reporting
pub const EV_DISPATCH = 0x0080;
pub const EVFILT_READ = -1;
pub const EVFILT_WRITE = -2;
/// attached to aio requests
pub const EVFILT_AIO = -3;
/// attached to vnodes
pub const EVFILT_VNODE = -4;
/// attached to struct proc
pub const EVFILT_PROC = -5;
/// attached to struct proc
pub const EVFILT_SIGNAL = -6;
/// timers
pub const EVFILT_TIMER = -7;
/// Process descriptors
pub const EVFILT_PROCDESC = -8;
/// Filesystem events
pub const EVFILT_FS = -9;
pub const EVFILT_LIO = -10;
/// User events
pub const EVFILT_USER = -11;
/// Sendfile events
pub const EVFILT_SENDFILE = -12;
pub const EVFILT_EMPTY = -13;
/// On input, NOTE_TRIGGER causes the event to be triggered for output.
pub const NOTE_TRIGGER = 0x01000000;
/// ignore input fflags
pub const NOTE_FFNOP = 0x00000000;
/// and fflags
pub const NOTE_FFAND = 0x40000000;
/// or fflags
pub const NOTE_FFOR = 0x80000000;
/// copy fflags
pub const NOTE_FFCOPY = 0xc0000000;
/// mask for operations
pub const NOTE_FFCTRLMASK = 0xc0000000;
pub const NOTE_FFLAGSMASK = 0x00ffffff;
/// low water mark
pub const NOTE_LOWAT = 0x00000001;
/// behave like poll()
pub const NOTE_FILE_POLL = 0x00000002;
/// vnode was removed
pub const NOTE_DELETE = 0x00000001;
/// data contents changed
pub const NOTE_WRITE = 0x00000002;
/// size increased
pub const NOTE_EXTEND = 0x00000004;
/// attributes changed
pub const NOTE_ATTRIB = 0x00000008;
/// link count changed
pub const NOTE_LINK = 0x00000010;
/// vnode was renamed
pub const NOTE_RENAME = 0x00000020;
/// vnode access was revoked
pub const NOTE_REVOKE = 0x00000040;
/// vnode was opened
pub const NOTE_OPEN = 0x00000080;
/// file closed, fd did not allow write
pub const NOTE_CLOSE = 0x00000100;
/// file closed, fd did allow write
pub const NOTE_CLOSE_WRITE = 0x00000200;
/// file was read
pub const NOTE_READ = 0x00000400;
/// process exited
pub const NOTE_EXIT = 0x80000000;
/// process forked
pub const NOTE_FORK = 0x40000000;
/// process exec'd
pub const NOTE_EXEC = 0x20000000;
/// mask for signal & exit status
pub const NOTE_PDATAMASK = 0x000fffff;
pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK);
/// data is seconds
pub const NOTE_SECONDS = 0x00000001;
/// data is milliseconds
pub const NOTE_MSECONDS = 0x00000002;
/// data is microseconds
pub const NOTE_USECONDS = 0x00000004;
/// data is nanoseconds
pub const NOTE_NSECONDS = 0x00000008;
/// timeout is absolute
pub const NOTE_ABSTIME = 0x00000010;
pub const TCGETS = 0x5401;
pub const TCSETS = 0x5402;
pub const TCSETSW = 0x5403;
pub const TCSETSF = 0x5404;
pub const TCGETA = 0x5405;
pub const TCSETA = 0x5406;
pub const TCSETAW = 0x5407;
pub const TCSETAF = 0x5408;
pub const TCSBRK = 0x5409;
pub const TCXONC = 0x540A;
pub const TCFLSH = 0x540B;
pub const TIOCEXCL = 0x540C;
pub const TIOCNXCL = 0x540D;
pub const TIOCSCTTY = 0x540E;
pub const TIOCGPGRP = 0x540F;
pub const TIOCSPGRP = 0x5410;
pub const TIOCOUTQ = 0x5411;
pub const TIOCSTI = 0x5412;
pub const TIOCGWINSZ = 0x5413;
pub const TIOCSWINSZ = 0x5414;
pub const TIOCMGET = 0x5415;
pub const TIOCMBIS = 0x5416;
pub const TIOCMBIC = 0x5417;
pub const TIOCMSET = 0x5418;
pub const TIOCGSOFTCAR = 0x5419;
pub const TIOCSSOFTCAR = 0x541A;
pub const FIONREAD = 0x541B;
pub const TIOCINQ = FIONREAD;
pub const TIOCLINUX = 0x541C;
pub const TIOCCONS = 0x541D;
pub const TIOCGSERIAL = 0x541E;
pub const TIOCSSERIAL = 0x541F;
pub const TIOCPKT = 0x5420;
pub const FIONBIO = 0x5421;
pub const TIOCNOTTY = 0x5422;
pub const TIOCSETD = 0x5423;
pub const TIOCGETD = 0x5424;
pub const TCSBRKP = 0x5425;
pub const TIOCSBRK = 0x5427;
pub const TIOCCBRK = 0x5428;
pub const TIOCGSID = 0x5429;
pub const TIOCGRS485 = 0x542E;
pub const TIOCSRS485 = 0x542F;
pub const TIOCGPTN = 0x80045430;
pub const TIOCSPTLCK = 0x40045431;
pub const TIOCGDEV = 0x80045432;
pub const TCGETX = 0x5432;
pub const TCSETX = 0x5433;
pub const TCSETXF = 0x5434;
pub const TCSETXW = 0x5435;
pub const TIOCSIG = 0x40045436;
pub const TIOCVHANGUP = 0x5437;
pub const TIOCGPKT = 0x80045438;
pub const TIOCGPTLCK = 0x80045439;
pub const TIOCGEXCL = 0x80045440;
fn unsigned(s: i32) u32 {
return @bitCast(u32, s);
}
fn signed(s: u32) i32 {
return @bitCast(i32, s);
}
pub fn WEXITSTATUS(s: i32) i32 {
return signed((unsigned(s) & 0xff00) >> 8);
}
pub fn WTERMSIG(s: i32) i32 {
return signed(unsigned(s) & 0x7f);
}
pub fn WSTOPSIG(s: i32) i32 {
return WEXITSTATUS(s);
}
pub fn WIFEXITED(s: i32) bool {
return WTERMSIG(s) == 0;
}
pub fn WIFSTOPPED(s: i32) bool {
return @intCast(u16, (((unsigned(s) & 0xffff) *% 0x10001) >> 8)) > 0x7f00;
}
pub fn WIFSIGNALED(s: i32) bool {
return (unsigned(s) & 0xffff) -% 1 < 0xff;
}
pub const winsize = extern struct {
ws_row: u16,
ws_col: u16,
ws_xpixel: u16,
ws_ypixel: u16,
};
/// Get the errno from a syscall return value, or 0 for no error.
pub fn getErrno(r: usize) usize {
const signed_r = @bitCast(isize, r);
return if (signed_r > -4096 and signed_r < 0) @intCast(usize, -signed_r) else 0;
}
pub fn dup2(old: i32, new: i32) usize {
return arch.syscall2(SYS_dup2, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)));
}
pub fn chdir(path: [*]const u8) usize {
return arch.syscall1(SYS_chdir, @ptrToInt(path));
}
pub fn execve(path: [*]const u8, argv: [*]const ?[*]const u8, envp: [*]const ?[*]const u8) usize {
return arch.syscall3(SYS_execve, @ptrToInt(path), @ptrToInt(argv), @ptrToInt(envp));
}
pub fn fork() usize {
return arch.syscall0(SYS_fork);
}
pub fn getcwd(buf: [*]u8, size: usize) usize {
return arch.syscall2(SYS___getcwd, @ptrToInt(buf), size);
}
pub fn getdents(fd: i32, dirp: [*]u8, count: usize) usize {
return arch.syscall3(SYS_getdents, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
}
pub fn isatty(fd: i32) bool {
var wsz: winsize = undefined;
return arch.syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
}
pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
return arch.syscall3(SYS_readlink, @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
}
pub fn mkdir(path: [*]const u8, mode: u32) usize {
return arch.syscall2(SYS_mkdir, @ptrToInt(path), mode);
}
pub fn mmap(address: ?*u8, length: usize, prot: usize, flags: usize, fd: i32, offset: isize) usize {
return arch.syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
}
pub fn munmap(address: usize, length: usize) usize {
return arch.syscall2(SYS_munmap, address, length);
}
pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
return arch.syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
}
pub fn rmdir(path: [*]const u8) usize {
return arch.syscall1(SYS_rmdir, @ptrToInt(path));
}
pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
return arch.syscall2(SYS_symlink, @ptrToInt(existing), @ptrToInt(new));
}
pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
return arch.syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
}
pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: usize) usize {
return arch.syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
}
pub fn pipe(fd: *[2]i32) usize {
return pipe2(fd, 0);
}
pub fn pipe2(fd: *[2]i32, flags: usize) usize {
return arch.syscall2(SYS_pipe2, @ptrToInt(fd), flags);
}
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
return arch.syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
}
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
return arch.syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
}
pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: usize) usize {
return arch.syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
}
pub fn rename(old: [*]const u8, new: [*]const u8) usize {
return arch.syscall2(SYS_rename, @ptrToInt(old), @ptrToInt(new));
}
pub fn open(path: [*]const u8, flags: u32, perm: usize) usize {
return arch.syscall3(SYS_open, @ptrToInt(path), flags, perm);
}
pub fn create(path: [*]const u8, perm: usize) usize {
return arch.syscall2(SYS_creat, @ptrToInt(path), perm);
}
pub fn openat(dirfd: i32, path: [*]const u8, flags: usize, mode: usize) usize {
return arch.syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
}
pub fn close(fd: i32) usize {
return arch.syscall1(SYS_close, @bitCast(usize, isize(fd)));
}
pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
return arch.syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
}
pub fn exit(status: i32) noreturn {
_ = arch.syscall1(SYS_exit, @bitCast(usize, isize(status)));
unreachable;
}
pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
return arch.syscall3(SYS_getrandom, @ptrToInt(buf), count, usize(flags));
}
pub fn kill(pid: i32, sig: i32) usize {
return arch.syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
}
pub fn unlink(path: [*]const u8) usize {
return arch.syscall1(SYS_unlink, @ptrToInt(path));
}
pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
return arch.syscall4(SYS_wait4, @bitCast(usize, isize(pid)), @ptrToInt(status), @bitCast(usize, isize(options)), 0);
}
pub fn nanosleep(req: *const timespec, rem: ?*timespec) usize {
return arch.syscall2(SYS_nanosleep, @ptrToInt(req), @ptrToInt(rem));
}
pub fn setuid(uid: u32) usize {
return arch.syscall1(SYS_setuid, uid);
}
pub fn setgid(gid: u32) usize {
return arch.syscall1(SYS_setgid, gid);
}
pub fn setreuid(ruid: u32, euid: u32) usize {
return arch.syscall2(SYS_setreuid, ruid, euid);
}
pub fn setregid(rgid: u32, egid: u32) usize {
return arch.syscall2(SYS_setregid, rgid, egid);
}
const NSIG = 32;
pub const SIG_ERR = @intToPtr(extern fn (i32) void, maxInt(usize));
pub const SIG_DFL = @intToPtr(extern fn (i32) void, 0);
pub const SIG_IGN = @intToPtr(extern fn (i32) void, 1);
/// Renamed from `sigaction` to `Sigaction` to avoid conflict with the syscall.
pub const Sigaction = extern struct {
/// signal handler
__sigaction_u: extern union {
__sa_handler: extern fn (i32) void,
__sa_sigaction: extern fn (i32, *__siginfo, usize) void,
},
/// see signal options
sa_flags: u32,
/// signal mask to apply
sa_mask: sigset_t,
};
pub const _SIG_WORDS = 4;
pub const _SIG_MAXSIG = 128;
pub inline fn _SIG_IDX(sig: usize) usize {
return sig - 1;
}
pub inline fn _SIG_WORD(sig: usize) usize {
return_SIG_IDX(sig) >> 5;
}
pub inline fn _SIG_BIT(sig: usize) usize {
return 1 << (_SIG_IDX(sig) & 31);
}
pub inline fn _SIG_VALID(sig: usize) usize {
return sig <= _SIG_MAXSIG and sig > 0;
}
pub const sigset_t = extern struct {
__bits: [_SIG_WORDS]u32,
};
pub fn raise(sig: i32) usize {
// TODO have a chat with the freebsd folks and make sure there's no bug in
// their libc. musl-libc blocks signals in between these calls because
// if a signal handler runs and forks between the gettid and sending the
// signal, the parent will get 2 signals, one from itself and one from the child
// if the protection does not belong here, then it belongs in abort(),
// like it does in freebsd's libc.
var id: usize = undefined;
const rc = arch.syscall1(SYS_thr_self, @ptrToInt(&id));
if (getErrno(rc) != 0) return rc;
return arch.syscall2(SYS_thr_kill, id, @bitCast(usize, isize(sig)));
}
pub const Stat = arch.Stat;
pub const timespec = arch.timespec;
pub fn fstat(fd: i32, stat_buf: *Stat) usize {
return arch.syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
}
pub const iovec = extern struct {
iov_base: [*]u8,
iov_len: usize,
};
pub const iovec_const = extern struct {
iov_base: [*]const u8,
iov_len: usize,
};
// TODO avoid libc dependency
pub fn kqueue() usize {
return errnoWrap(c.kqueue());
}
// TODO avoid libc dependency
pub fn kevent(kq: i32, changelist: []const Kevent, eventlist: []Kevent, timeout: ?*const timespec) usize {
return errnoWrap(c.kevent(
kq,
changelist.ptr,
@intCast(c_int, changelist.len),
eventlist.ptr,
@intCast(c_int, eventlist.len),
timeout,
));
}
// TODO avoid libc dependency
pub fn sysctl(name: [*]c_int, namelen: c_uint, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
return errnoWrap(c.sysctl(name, namelen, oldp, oldlenp, newp, newlen));
}
// TODO avoid libc dependency
pub fn sysctlbyname(name: [*]const u8, oldp: ?*c_void, oldlenp: ?*usize, newp: ?*c_void, newlen: usize) usize {
return errnoWrap(c.sysctlbyname(name, oldp, oldlenp, newp, newlen));
}
// TODO avoid libc dependency
pub fn sysctlnametomib(name: [*]const u8, mibp: ?*c_int, sizep: ?*usize) usize {
return errnoWrap(c.sysctlnametomib(name, wibp, sizep));
}
// TODO avoid libc dependency
/// Takes the return value from a syscall and formats it back in the way
/// that the kernel represents it to libc. Errno was a mistake, let's make
/// it go away forever.
fn errnoWrap(value: isize) usize {
return @bitCast(usize, if (value == -1) -isize(c._errno().*) else value);
}

493
std/os/freebsd/syscall.zig Normal file
View File

@ -0,0 +1,493 @@
pub const SYS_syscall = 0;
pub const SYS_exit = 1;
pub const SYS_fork = 2;
pub const SYS_read = 3;
pub const SYS_write = 4;
pub const SYS_open = 5;
pub const SYS_close = 6;
pub const SYS_wait4 = 7;
// 8 is old creat
pub const SYS_link = 9;
pub const SYS_unlink = 10;
// 11 is obsolete execv
pub const SYS_chdir = 12;
pub const SYS_fchdir = 13;
pub const SYS_freebsd11_mknod = 14;
pub const SYS_chmod = 15;
pub const SYS_chown = 16;
pub const SYS_break = 17;
// 18 is freebsd4 getfsstat
// 19 is old lseek
pub const SYS_getpid = 20;
pub const SYS_mount = 21;
pub const SYS_unmount = 22;
pub const SYS_setuid = 23;
pub const SYS_getuid = 24;
pub const SYS_geteuid = 25;
pub const SYS_ptrace = 26;
pub const SYS_recvmsg = 27;
pub const SYS_sendmsg = 28;
pub const SYS_recvfrom = 29;
pub const SYS_accept = 30;
pub const SYS_getpeername = 31;
pub const SYS_getsockname = 32;
pub const SYS_access = 33;
pub const SYS_chflags = 34;
pub const SYS_fchflags = 35;
pub const SYS_sync = 36;
pub const SYS_kill = 37;
// 38 is old stat
pub const SYS_getppid = 39;
// 40 is old lstat
pub const SYS_dup = 41;
pub const SYS_freebsd10_pipe = 42;
pub const SYS_getegid = 43;
pub const SYS_profil = 44;
pub const SYS_ktrace = 45;
// 46 is old sigaction
pub const SYS_getgid = 47;
// 48 is old sigprocmask
pub const SYS_getlogin = 49;
pub const SYS_setlogin = 50;
pub const SYS_acct = 51;
// 52 is old sigpending
pub const SYS_sigaltstack = 53;
pub const SYS_ioctl = 54;
pub const SYS_reboot = 55;
pub const SYS_revoke = 56;
pub const SYS_symlink = 57;
pub const SYS_readlink = 58;
pub const SYS_execve = 59;
pub const SYS_umask = 60;
pub const SYS_chroot = 61;
// 62 is old fstat
// 63 is old getkerninfo
// 64 is old getpagesize
pub const SYS_msync = 65;
pub const SYS_vfork = 66;
// 67 is obsolete vread
// 68 is obsolete vwrite
// 69 is obsolete sbrk (still present on some platforms)
pub const SYS_sstk = 70;
// 71 is old mmap
pub const SYS_vadvise = 72;
pub const SYS_munmap = 73;
pub const SYS_mprotect = 74;
pub const SYS_madvise = 75;
// 76 is obsolete vhangup
// 77 is obsolete vlimit
pub const SYS_mincore = 78;
pub const SYS_getgroups = 79;
pub const SYS_setgroups = 80;
pub const SYS_getpgrp = 81;
pub const SYS_setpgid = 82;
pub const SYS_setitimer = 83;
// 84 is old wait
pub const SYS_swapon = 85;
pub const SYS_getitimer = 86;
// 87 is old gethostname
// 88 is old sethostname
pub const SYS_getdtablesize = 89;
pub const SYS_dup2 = 90;
pub const SYS_fcntl = 92;
pub const SYS_select = 93;
pub const SYS_fsync = 95;
pub const SYS_setpriority = 96;
pub const SYS_socket = 97;
pub const SYS_connect = 98;
// 99 is old accept
pub const SYS_getpriority = 100;
// 101 is old send
// 102 is old recv
// 103 is old sigreturn
pub const SYS_bind = 104;
pub const SYS_setsockopt = 105;
pub const SYS_listen = 106;
// 107 is obsolete vtimes
// 108 is old sigvec
// 109 is old sigblock
// 110 is old sigsetmask
// 111 is old sigsuspend
// 112 is old sigstack
// 113 is old recvmsg
// 114 is old sendmsg
// 115 is obsolete vtrace
pub const SYS_gettimeofday = 116;
pub const SYS_getrusage = 117;
pub const SYS_getsockopt = 118;
pub const SYS_readv = 120;
pub const SYS_writev = 121;
pub const SYS_settimeofday = 122;
pub const SYS_fchown = 123;
pub const SYS_fchmod = 124;
// 125 is old recvfrom
pub const SYS_setreuid = 126;
pub const SYS_setregid = 127;
pub const SYS_rename = 128;
// 129 is old truncate
// 130 is old ftruncate
pub const SYS_flock = 131;
pub const SYS_mkfifo = 132;
pub const SYS_sendto = 133;
pub const SYS_shutdown = 134;
pub const SYS_socketpair = 135;
pub const SYS_mkdir = 136;
pub const SYS_rmdir = 137;
pub const SYS_utimes = 138;
// 139 is obsolete 4.2 sigreturn
pub const SYS_adjtime = 140;
// 141 is old getpeername
// 142 is old gethostid
// 143 is old sethostid
// 144 is old getrlimit
// 145 is old setrlimit
// 146 is old killpg
pub const SYS_setsid = 147;
pub const SYS_quotactl = 148;
// 149 is old quota
// 150 is old getsockname
pub const SYS_nlm_syscall = 154;
pub const SYS_nfssvc = 155;
// 156 is old getdirentries
// 157 is freebsd4 statfs
// 158 is freebsd4 fstatfs
pub const SYS_lgetfh = 160;
pub const SYS_getfh = 161;
// 162 is freebsd4 getdomainname
// 163 is freebsd4 setdomainname
// 164 is freebsd4 uname
pub const SYS_sysarch = 165;
pub const SYS_rtprio = 166;
pub const SYS_semsys = 169;
pub const SYS_msgsys = 170;
pub const SYS_shmsys = 171;
// 173 is freebsd6 pread
// 174 is freebsd6 pwrite
pub const SYS_setfib = 175;
pub const SYS_ntp_adjtime = 176;
pub const SYS_setgid = 181;
pub const SYS_setegid = 182;
pub const SYS_seteuid = 183;
// 184 is obsolete lfs_bmapv
// 185 is obsolete lfs_markv
// 186 is obsolete lfs_segclean
// 187 is obsolete lfs_segwait
pub const SYS_freebsd11_stat = 188;
pub const SYS_freebsd11_fstat = 189;
pub const SYS_freebsd11_lstat = 190;
pub const SYS_pathconf = 191;
pub const SYS_fpathconf = 192;
pub const SYS_getrlimit = 194;
pub const SYS_setrlimit = 195;
pub const SYS_freebsd11_getdirentries = 196;
// 197 is freebsd6 mmap
pub const SYS___syscall = 198;
// 199 is freebsd6 lseek
// 200 is freebsd6 truncate
// 201 is freebsd6 ftruncate
pub const SYS___sysctl = 202;
pub const SYS_mlock = 203;
pub const SYS_munlock = 204;
pub const SYS_undelete = 205;
pub const SYS_futimes = 206;
pub const SYS_getpgid = 207;
pub const SYS_poll = 209;
pub const SYS_freebsd7___semctl = 220;
pub const SYS_semget = 221;
pub const SYS_semop = 222;
pub const SYS_freebsd7_msgctl = 224;
pub const SYS_msgget = 225;
pub const SYS_msgsnd = 226;
pub const SYS_msgrcv = 227;
pub const SYS_shmat = 228;
pub const SYS_freebsd7_shmctl = 229;
pub const SYS_shmdt = 230;
pub const SYS_shmget = 231;
pub const SYS_clock_gettime = 232;
pub const SYS_clock_settime = 233;
pub const SYS_clock_getres = 234;
pub const SYS_ktimer_create = 235;
pub const SYS_ktimer_delete = 236;
pub const SYS_ktimer_settime = 237;
pub const SYS_ktimer_gettime = 238;
pub const SYS_ktimer_getoverrun = 239;
pub const SYS_nanosleep = 240;
pub const SYS_ffclock_getcounter = 241;
pub const SYS_ffclock_setestimate = 242;
pub const SYS_ffclock_getestimate = 243;
pub const SYS_clock_nanosleep = 244;
pub const SYS_clock_getcpuclockid2 = 247;
pub const SYS_ntp_gettime = 248;
pub const SYS_minherit = 250;
pub const SYS_rfork = 251;
// 252 is obsolete openbsd_poll
pub const SYS_issetugid = 253;
pub const SYS_lchown = 254;
pub const SYS_aio_read = 255;
pub const SYS_aio_write = 256;
pub const SYS_lio_listio = 257;
pub const SYS_freebsd11_getdents = 272;
pub const SYS_lchmod = 274;
// 275 is obsolete netbsd_lchown
pub const SYS_lutimes = 276;
// 277 is obsolete netbsd_msync
pub const SYS_freebsd11_nstat = 278;
pub const SYS_freebsd11_nfstat = 279;
pub const SYS_freebsd11_nlstat = 280;
pub const SYS_preadv = 289;
pub const SYS_pwritev = 290;
// 297 is freebsd4 fhstatfs
pub const SYS_fhopen = 298;
pub const SYS_freebsd11_fhstat = 299;
pub const SYS_modnext = 300;
pub const SYS_modstat = 301;
pub const SYS_modfnext = 302;
pub const SYS_modfind = 303;
pub const SYS_kldload = 304;
pub const SYS_kldunload = 305;
pub const SYS_kldfind = 306;
pub const SYS_kldnext = 307;
pub const SYS_kldstat = 308;
pub const SYS_kldfirstmod = 309;
pub const SYS_getsid = 310;
pub const SYS_setresuid = 311;
pub const SYS_setresgid = 312;
// 313 is obsolete signanosleep
pub const SYS_aio_return = 314;
pub const SYS_aio_suspend = 315;
pub const SYS_aio_cancel = 316;
pub const SYS_aio_error = 317;
// 318 is freebsd6 aio_read
// 319 is freebsd6 aio_write
// 320 is freebsd6 lio_listio
pub const SYS_yield = 321;
// 322 is obsolete thr_sleep
// 323 is obsolete thr_wakeup
pub const SYS_mlockall = 324;
pub const SYS_munlockall = 325;
pub const SYS___getcwd = 326;
pub const SYS_sched_setparam = 327;
pub const SYS_sched_getparam = 328;
pub const SYS_sched_setscheduler = 329;
pub const SYS_sched_getscheduler = 330;
pub const SYS_sched_yield = 331;
pub const SYS_sched_get_priority_max = 332;
pub const SYS_sched_get_priority_min = 333;
pub const SYS_sched_rr_get_interval = 334;
pub const SYS_utrace = 335;
// 336 is freebsd4 sendfile
pub const SYS_kldsym = 337;
pub const SYS_jail = 338;
pub const SYS_nnpfs_syscall = 339;
pub const SYS_sigprocmask = 340;
pub const SYS_sigsuspend = 341;
// 342 is freebsd4 sigaction
pub const SYS_sigpending = 343;
// 344 is freebsd4 sigreturn
pub const SYS_sigtimedwait = 345;
pub const SYS_sigwaitinfo = 346;
pub const SYS___acl_get_file = 347;
pub const SYS___acl_set_file = 348;
pub const SYS___acl_get_fd = 349;
pub const SYS___acl_set_fd = 350;
pub const SYS___acl_delete_file = 351;
pub const SYS___acl_delete_fd = 352;
pub const SYS___acl_aclcheck_file = 353;
pub const SYS___acl_aclcheck_fd = 354;
pub const SYS_extattrctl = 355;
pub const SYS_extattr_set_file = 356;
pub const SYS_extattr_get_file = 357;
pub const SYS_extattr_delete_file = 358;
pub const SYS_aio_waitcomplete = 359;
pub const SYS_getresuid = 360;
pub const SYS_getresgid = 361;
pub const SYS_kqueue = 362;
pub const SYS_freebsd11_kevent = 363;
// 364 is obsolete __cap_get_proc
// 365 is obsolete __cap_set_proc
// 366 is obsolete __cap_get_fd
// 367 is obsolete __cap_get_file
// 368 is obsolete __cap_set_fd
// 369 is obsolete __cap_set_file
pub const SYS_extattr_set_fd = 371;
pub const SYS_extattr_get_fd = 372;
pub const SYS_extattr_delete_fd = 373;
pub const SYS___setugid = 374;
pub const SYS_eaccess = 376;
pub const SYS_afs3_syscall = 377;
pub const SYS_nmount = 378;
// 379 is obsolete kse_exit
// 380 is obsolete kse_wakeup
// 381 is obsolete kse_create
// 382 is obsolete kse_thr_interrupt
// 383 is obsolete kse_release
pub const SYS___mac_get_proc = 384;
pub const SYS___mac_set_proc = 385;
pub const SYS___mac_get_fd = 386;
pub const SYS___mac_get_file = 387;
pub const SYS___mac_set_fd = 388;
pub const SYS___mac_set_file = 389;
pub const SYS_kenv = 390;
pub const SYS_lchflags = 391;
pub const SYS_uuidgen = 392;
pub const SYS_sendfile = 393;
pub const SYS_mac_syscall = 394;
pub const SYS_freebsd11_getfsstat = 395;
pub const SYS_freebsd11_statfs = 396;
pub const SYS_freebsd11_fstatfs = 397;
pub const SYS_freebsd11_fhstatfs = 398;
pub const SYS_ksem_close = 400;
pub const SYS_ksem_post = 401;
pub const SYS_ksem_wait = 402;
pub const SYS_ksem_trywait = 403;
pub const SYS_ksem_init = 404;
pub const SYS_ksem_open = 405;
pub const SYS_ksem_unlink = 406;
pub const SYS_ksem_getvalue = 407;
pub const SYS_ksem_destroy = 408;
pub const SYS___mac_get_pid = 409;
pub const SYS___mac_get_link = 410;
pub const SYS___mac_set_link = 411;
pub const SYS_extattr_set_link = 412;
pub const SYS_extattr_get_link = 413;
pub const SYS_extattr_delete_link = 414;
pub const SYS___mac_execve = 415;
pub const SYS_sigaction = 416;
pub const SYS_sigreturn = 417;
pub const SYS_getcontext = 421;
pub const SYS_setcontext = 422;
pub const SYS_swapcontext = 423;
pub const SYS_swapoff = 424;
pub const SYS___acl_get_link = 425;
pub const SYS___acl_set_link = 426;
pub const SYS___acl_delete_link = 427;
pub const SYS___acl_aclcheck_link = 428;
pub const SYS_sigwait = 429;
pub const SYS_thr_create = 430;
pub const SYS_thr_exit = 431;
pub const SYS_thr_self = 432;
pub const SYS_thr_kill = 433;
pub const SYS_jail_attach = 436;
pub const SYS_extattr_list_fd = 437;
pub const SYS_extattr_list_file = 438;
pub const SYS_extattr_list_link = 439;
// 440 is obsolete kse_switchin
pub const SYS_ksem_timedwait = 441;
pub const SYS_thr_suspend = 442;
pub const SYS_thr_wake = 443;
pub const SYS_kldunloadf = 444;
pub const SYS_audit = 445;
pub const SYS_auditon = 446;
pub const SYS_getauid = 447;
pub const SYS_setauid = 448;
pub const SYS_getaudit = 449;
pub const SYS_setaudit = 450;
pub const SYS_getaudit_addr = 451;
pub const SYS_setaudit_addr = 452;
pub const SYS_auditctl = 453;
pub const SYS__umtx_op = 454;
pub const SYS_thr_new = 455;
pub const SYS_sigqueue = 456;
pub const SYS_kmq_open = 457;
pub const SYS_kmq_setattr = 458;
pub const SYS_kmq_timedreceive = 459;
pub const SYS_kmq_timedsend = 460;
pub const SYS_kmq_notify = 461;
pub const SYS_kmq_unlink = 462;
pub const SYS_abort2 = 463;
pub const SYS_thr_set_name = 464;
pub const SYS_aio_fsync = 465;
pub const SYS_rtprio_thread = 466;
pub const SYS_sctp_peeloff = 471;
pub const SYS_sctp_generic_sendmsg = 472;
pub const SYS_sctp_generic_sendmsg_iov = 473;
pub const SYS_sctp_generic_recvmsg = 474;
pub const SYS_pread = 475;
pub const SYS_pwrite = 476;
pub const SYS_mmap = 477;
pub const SYS_lseek = 478;
pub const SYS_truncate = 479;
pub const SYS_ftruncate = 480;
pub const SYS_thr_kill2 = 481;
pub const SYS_shm_open = 482;
pub const SYS_shm_unlink = 483;
pub const SYS_cpuset = 484;
pub const SYS_cpuset_setid = 485;
pub const SYS_cpuset_getid = 486;
pub const SYS_cpuset_getaffinity = 487;
pub const SYS_cpuset_setaffinity = 488;
pub const SYS_faccessat = 489;
pub const SYS_fchmodat = 490;
pub const SYS_fchownat = 491;
pub const SYS_fexecve = 492;
pub const SYS_freebsd11_fstatat = 493;
pub const SYS_futimesat = 494;
pub const SYS_linkat = 495;
pub const SYS_mkdirat = 496;
pub const SYS_mkfifoat = 497;
pub const SYS_freebsd11_mknodat = 498;
pub const SYS_openat = 499;
pub const SYS_readlinkat = 500;
pub const SYS_renameat = 501;
pub const SYS_symlinkat = 502;
pub const SYS_unlinkat = 503;
pub const SYS_posix_openpt = 504;
pub const SYS_gssd_syscall = 505;
pub const SYS_jail_get = 506;
pub const SYS_jail_set = 507;
pub const SYS_jail_remove = 508;
pub const SYS_closefrom = 509;
pub const SYS___semctl = 510;
pub const SYS_msgctl = 511;
pub const SYS_shmctl = 512;
pub const SYS_lpathconf = 513;
// 514 is obsolete cap_new
pub const SYS___cap_rights_get = 515;
pub const SYS_cap_enter = 516;
pub const SYS_cap_getmode = 517;
pub const SYS_pdfork = 518;
pub const SYS_pdkill = 519;
pub const SYS_pdgetpid = 520;
pub const SYS_pselect = 522;
pub const SYS_getloginclass = 523;
pub const SYS_setloginclass = 524;
pub const SYS_rctl_get_racct = 525;
pub const SYS_rctl_get_rules = 526;
pub const SYS_rctl_get_limits = 527;
pub const SYS_rctl_add_rule = 528;
pub const SYS_rctl_remove_rule = 529;
pub const SYS_posix_fallocate = 530;
pub const SYS_posix_fadvise = 531;
pub const SYS_wait6 = 532;
pub const SYS_cap_rights_limit = 533;
pub const SYS_cap_ioctls_limit = 534;
pub const SYS_cap_ioctls_get = 535;
pub const SYS_cap_fcntls_limit = 536;
pub const SYS_cap_fcntls_get = 537;
pub const SYS_bindat = 538;
pub const SYS_connectat = 539;
pub const SYS_chflagsat = 540;
pub const SYS_accept4 = 541;
pub const SYS_pipe2 = 542;
pub const SYS_aio_mlock = 543;
pub const SYS_procctl = 544;
pub const SYS_ppoll = 545;
pub const SYS_futimens = 546;
pub const SYS_utimensat = 547;
// 548 is obsolete numa_getaffinity
// 549 is obsolete numa_setaffinity
pub const SYS_fdatasync = 550;
pub const SYS_fstat = 551;
pub const SYS_fstatat = 552;
pub const SYS_fhstat = 553;
pub const SYS_getdirentries = 554;
pub const SYS_statfs = 555;
pub const SYS_fstatfs = 556;
pub const SYS_getfsstat = 557;
pub const SYS_fhstatfs = 558;
pub const SYS_mknodat = 559;
pub const SYS_kevent = 560;
pub const SYS_cpuset_getdomain = 561;
pub const SYS_cpuset_setdomain = 562;
pub const SYS_getrandom = 563;
pub const SYS_MAXSYSCALL = 564;

136
std/os/freebsd/x86_64.zig Normal file
View File

@ -0,0 +1,136 @@
const freebsd = @import("index.zig");
const socklen_t = freebsd.socklen_t;
const iovec = freebsd.iovec;
pub const SYS_sbrk = 69;
pub fn syscall0(number: usize) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number)
: "rcx", "r11"
);
}
pub fn syscall1(number: usize, arg1: usize) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1)
: "rcx", "r11"
);
}
pub fn syscall2(number: usize, arg1: usize, arg2: usize) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2)
: "rcx", "r11"
);
}
pub fn syscall3(number: usize, arg1: usize, arg2: usize, arg3: usize) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2),
[arg3] "{rdx}" (arg3)
: "rcx", "r11"
);
}
pub fn syscall4(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2),
[arg3] "{rdx}" (arg3),
[arg4] "{r10}" (arg4)
: "rcx", "r11"
);
}
pub fn syscall5(number: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2),
[arg3] "{rdx}" (arg3),
[arg4] "{r10}" (arg4),
[arg5] "{r8}" (arg5)
: "rcx", "r11"
);
}
pub fn syscall6(
number: usize,
arg1: usize,
arg2: usize,
arg3: usize,
arg4: usize,
arg5: usize,
arg6: usize,
) usize {
return asm volatile ("syscall"
: [ret] "={rax}" (-> usize)
: [number] "{rax}" (number),
[arg1] "{rdi}" (arg1),
[arg2] "{rsi}" (arg2),
[arg3] "{rdx}" (arg3),
[arg4] "{r10}" (arg4),
[arg5] "{r8}" (arg5),
[arg6] "{r9}" (arg6)
: "rcx", "r11"
);
}
pub nakedcc fn restore_rt() void {
asm volatile ("syscall"
:
: [number] "{rax}" (usize(SYS_rt_sigreturn))
: "rcx", "r11"
);
}
pub const msghdr = extern struct {
msg_name: *u8,
msg_namelen: socklen_t,
msg_iov: *iovec,
msg_iovlen: i32,
__pad1: i32,
msg_control: *u8,
msg_controllen: socklen_t,
__pad2: socklen_t,
msg_flags: i32,
};
/// Renamed to Stat to not conflict with the stat function.
pub const Stat = extern struct {
dev: u64,
ino: u64,
nlink: usize,
mode: u32,
uid: u32,
gid: u32,
__pad0: u32,
rdev: u64,
size: i64,
blksize: isize,
blocks: i64,
atim: timespec,
mtim: timespec,
ctim: timespec,
__unused: [3]isize,
};
pub const timespec = extern struct {
tv_sec: isize,
tv_nsec: isize,
};

View File

@ -43,7 +43,7 @@ pub fn getAppDataDir(allocator: *mem.Allocator, appname: []const u8) GetAppDataD
};
return os.path.join(allocator, home_dir, "Library", "Application Support", appname);
},
builtin.Os.linux => {
builtin.Os.linux, builtin.Os.freebsd => {
const home_dir = os.getEnvPosix("HOME") orelse {
// TODO look in /etc/passwd
return error.AppDataDirUnavailable;

View File

@ -11,7 +11,7 @@ pub const UserInfo = struct {
/// POSIX function which gets a uid from username.
pub fn getUserInfo(name: []const u8) !UserInfo {
return switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => posixGetUserInfo(name),
Os.linux, Os.macosx, Os.ios, Os.freebsd => posixGetUserInfo(name),
else => @compileError("Unsupported OS"),
};
}

View File

@ -3,7 +3,7 @@ const builtin = @import("builtin");
const Os = builtin.Os;
const is_windows = builtin.os == Os.windows;
const is_posix = switch (builtin.os) {
builtin.Os.linux, builtin.Os.macosx => true,
builtin.Os.linux, builtin.Os.macosx, builtin.Os.freebsd => true,
else => false,
};
const os = @This();
@ -24,10 +24,12 @@ test "std.os" {
pub const windows = @import("windows/index.zig");
pub const darwin = @import("darwin.zig");
pub const linux = @import("linux/index.zig");
pub const freebsd = @import("freebsd/index.zig");
pub const zen = @import("zen.zig");
pub const posix = switch (builtin.os) {
Os.linux => linux,
Os.macosx, Os.ios => darwin,
Os.freebsd => freebsd,
Os.zen => zen,
else => @compileError("Unsupported OS"),
};
@ -40,7 +42,7 @@ pub const time = @import("time.zig");
pub const page_size = 4 * 1024;
pub const MAX_PATH_BYTES = switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => posix.PATH_MAX,
Os.linux, Os.macosx, Os.ios, Os.freebsd => posix.PATH_MAX,
// Each UTF-16LE character may be expanded to 3 UTF-8 bytes.
// If it would require 4 UTF-8 bytes, then there would be a surrogate
// pair in the UTF-16LE, and we (over)account 3 bytes for it that way.
@ -101,7 +103,7 @@ const math = std.math;
/// library implementation.
pub fn getRandomBytes(buf: []u8) !void {
switch (builtin.os) {
Os.linux => while (true) {
Os.linux, Os.freebsd => while (true) {
// TODO check libc version and potentially call c.getrandom.
// See #397
const errno = posix.getErrno(posix.getrandom(buf.ptr, buf.len, 0));
@ -174,7 +176,7 @@ pub fn abort() noreturn {
c.abort();
}
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
_ = posix.raise(posix.SIGABRT);
_ = posix.raise(posix.SIGKILL);
while (true) {}
@ -196,7 +198,7 @@ pub fn exit(status: u8) noreturn {
c.exit(status);
}
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
posix.exit(status);
},
Os.windows => {
@ -419,7 +421,7 @@ pub fn posix_pwritev(fd: i32, iov: [*]const posix.iovec_const, count: usize, off
}
}
},
builtin.Os.linux => while (true) {
builtin.Os.linux, builtin.Os.freebsd => while (true) {
const rc = posix.pwritev(fd, iov, count, offset);
const err = posix.getErrno(rc);
switch (err) {
@ -457,6 +459,7 @@ pub const PosixOpenError = error{
NoSpaceLeft,
NotDir,
PathAlreadyExists,
DeviceBusy,
/// See https://github.com/ziglang/zig/issues/1396
Unexpected,
@ -495,6 +498,7 @@ pub fn posixOpenC(file_path: [*]const u8, flags: u32, perm: usize) !i32 {
posix.ENOTDIR => return PosixOpenError.NotDir,
posix.EPERM => return PosixOpenError.AccessDenied,
posix.EEXIST => return PosixOpenError.PathAlreadyExists,
posix.EBUSY => return PosixOpenError.DeviceBusy,
else => return unexpectedErrorPosix(err),
}
}
@ -687,7 +691,7 @@ pub fn getBaseAddress() usize {
};
return phdr - @sizeOf(ElfHeader);
},
builtin.Os.macosx => return @ptrToInt(&std.c._mh_execute_header),
builtin.Os.macosx, builtin.Os.freebsd => return @ptrToInt(&std.c._mh_execute_header),
builtin.Os.windows => return @ptrToInt(windows.GetModuleHandleW(null)),
else => @compileError("Unsupported OS"),
}
@ -700,8 +704,8 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
errdefer result.deinit();
if (is_windows) {
const ptr = windows.GetEnvironmentStringsA() orelse return error.OutOfMemory;
defer assert(windows.FreeEnvironmentStringsA(ptr) != 0);
const ptr = windows.GetEnvironmentStringsW() orelse return error.OutOfMemory;
defer assert(windows.FreeEnvironmentStringsW(ptr) != 0);
var i: usize = 0;
while (true) {
@ -710,17 +714,21 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
const key_start = i;
while (ptr[i] != 0 and ptr[i] != '=') : (i += 1) {}
const key = ptr[key_start..i];
const key_w = ptr[key_start..i];
const key = try std.unicode.utf16leToUtf8Alloc(allocator, key_w);
errdefer allocator.free(key);
if (ptr[i] == '=') i += 1;
const value_start = i;
while (ptr[i] != 0) : (i += 1) {}
const value = ptr[value_start..i];
const value_w = ptr[value_start..i];
const value = try std.unicode.utf16leToUtf8Alloc(allocator, value_w);
errdefer allocator.free(value);
i += 1; // skip over null byte
try result.set(key, value);
try result.setMove(key, value);
}
} else {
for (posix_environ_raw) |ptr| {
@ -738,6 +746,11 @@ pub fn getEnvMap(allocator: *Allocator) !BufMap {
}
}
test "os.getEnvMap" {
var env = try getEnvMap(std.debug.global_allocator);
defer env.deinit();
}
/// TODO make this go through libc when we have it
pub fn getEnvPosix(key: []const u8) ?[]const u8 {
for (posix_environ_raw) |ptr| {
@ -758,21 +771,24 @@ pub fn getEnvPosix(key: []const u8) ?[]const u8 {
pub const GetEnvVarOwnedError = error{
OutOfMemory,
EnvironmentVariableNotFound,
/// See https://github.com/ziglang/zig/issues/1774
InvalidUtf8,
};
/// Caller must free returned memory.
/// TODO make this go through libc when we have it
pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwnedError![]u8 {
if (is_windows) {
const key_with_null = try cstr.addNullByte(allocator, key);
const key_with_null = try std.unicode.utf8ToUtf16LeWithNull(allocator, key);
defer allocator.free(key_with_null);
var buf = try allocator.alloc(u8, 256);
errdefer allocator.free(buf);
var buf = try allocator.alloc(u16, 256);
defer allocator.free(buf);
while (true) {
const windows_buf_len = math.cast(windows.DWORD, buf.len) catch return error.OutOfMemory;
const result = windows.GetEnvironmentVariableA(key_with_null.ptr, buf.ptr, windows_buf_len);
const result = windows.GetEnvironmentVariableW(key_with_null.ptr, buf.ptr, windows_buf_len);
if (result == 0) {
const err = windows.GetLastError();
@ -786,11 +802,16 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
}
if (result > buf.len) {
buf = try allocator.realloc(u8, buf, result);
buf = try allocator.realloc(u16, buf, result);
continue;
}
return allocator.shrink(u8, buf, result);
return std.unicode.utf16leToUtf8Alloc(allocator, buf) catch |err| switch (err) {
error.DanglingSurrogateHalf => return error.InvalidUtf8,
error.ExpectedSecondSurrogateHalf => return error.InvalidUtf8,
error.UnexpectedSecondSurrogateHalf => return error.InvalidUtf8,
error.OutOfMemory => return error.OutOfMemory,
};
}
} else {
const result = getEnvPosix(key) orelse return error.EnvironmentVariableNotFound;
@ -798,6 +819,11 @@ pub fn getEnvVarOwned(allocator: *mem.Allocator, key: []const u8) GetEnvVarOwned
}
}
test "os.getEnvVarOwned" {
var ga = debug.global_allocator;
debug.assertError(getEnvVarOwned(ga, "BADENV"), error.EnvironmentVariableNotFound);
}
/// Caller must free the returned memory.
pub fn getCwdAlloc(allocator: *Allocator) ![]u8 {
var buf: [MAX_PATH_BYTES]u8 = undefined;
@ -1305,7 +1331,7 @@ pub fn deleteDirC(dir_path: [*]const u8) DeleteDirError!void {
const dir_path_w = try windows_util.cStrToPrefixedFileW(dir_path);
return deleteDirW(&dir_path_w);
},
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const err = posix.getErrno(posix.rmdir(dir_path));
switch (err) {
0 => return,
@ -1348,7 +1374,7 @@ pub fn deleteDir(dir_path: []const u8) DeleteDirError!void {
const dir_path_w = try windows_util.sliceToPrefixedFileW(dir_path);
return deleteDirW(&dir_path_w);
},
Os.linux, Os.macosx, Os.ios => {
Os.linux, Os.macosx, Os.ios, Os.freebsd => {
const dir_path_c = try toPosixPath(dir_path);
return deleteDirC(&dir_path_c);
},
@ -1378,6 +1404,7 @@ const DeleteTreeError = error{
FileSystem,
FileBusy,
DirNotEmpty,
DeviceBusy,
/// On Windows, file paths must be valid Unicode.
InvalidUtf8,
@ -1439,6 +1466,7 @@ pub fn deleteTree(allocator: *Allocator, full_path: []const u8) DeleteTreeError!
error.Unexpected,
error.InvalidUtf8,
error.BadPathName,
error.DeviceBusy,
=> return err,
};
defer dir.close();
@ -1465,7 +1493,7 @@ pub const Dir = struct {
allocator: *Allocator,
pub const Handle = switch (builtin.os) {
Os.macosx, Os.ios => struct {
Os.macosx, Os.ios, Os.freebsd => struct {
fd: i32,
seek: i64,
buf: []u8,
@ -1521,6 +1549,7 @@ pub const Dir = struct {
OutOfMemory,
InvalidUtf8,
BadPathName,
DeviceBusy,
/// See https://github.com/ziglang/zig/issues/1396
Unexpected,
@ -1541,7 +1570,7 @@ pub const Dir = struct {
.name_data = undefined,
};
},
Os.macosx, Os.ios => Handle{
Os.macosx, Os.ios, Os.freebsd => Handle{
.fd = try posixOpen(
dir_path,
posix.O_RDONLY | posix.O_NONBLOCK | posix.O_DIRECTORY | posix.O_CLOEXEC,
@ -1572,7 +1601,7 @@ pub const Dir = struct {
Os.windows => {
_ = windows.FindClose(self.handle.handle);
},
Os.macosx, Os.ios, Os.linux => {
Os.macosx, Os.ios, Os.linux, Os.freebsd => {
self.allocator.free(self.handle.buf);
os.close(self.handle.fd);
},
@ -1587,6 +1616,7 @@ pub const Dir = struct {
Os.linux => return self.nextLinux(),
Os.macosx, Os.ios => return self.nextDarwin(),
Os.windows => return self.nextWindows(),
Os.freebsd => return self.nextFreebsd(),
else => @compileError("unimplemented"),
}
}
@ -1726,6 +1756,11 @@ pub const Dir = struct {
};
}
}
fn nextFreebsd(self: *Dir) !?Entry {
//self.handle.buf = try self.allocator.alloc(u8, page_size);
@compileError("TODO implement dirs for FreeBSD");
}
};
pub fn changeCurDir(allocator: *Allocator, dir_path: []const u8) !void {
@ -2164,7 +2199,7 @@ pub fn unexpectedErrorWindows(err: windows.DWORD) UnexpectedError {
pub fn openSelfExe() !os.File {
switch (builtin.os) {
Os.linux => return os.File.openReadC(c"/proc/self/exe"),
Os.macosx, Os.ios => {
Os.macosx, Os.ios, Os.freebsd => {
var buf: [MAX_PATH_BYTES]u8 = undefined;
const self_exe_path = try selfExePath(&buf);
buf[self_exe_path.len] = 0;
@ -2181,7 +2216,7 @@ pub fn openSelfExe() !os.File {
test "openSelfExe" {
switch (builtin.os) {
Os.linux, Os.macosx, Os.ios, Os.windows => (try openSelfExe()).close(),
Os.linux, Os.macosx, Os.ios, Os.windows, Os.freebsd => (try openSelfExe()).close(),
else => return error.SkipZigTest, // Unsupported OS.
}
}
@ -2212,6 +2247,7 @@ pub fn selfExePathW(out_buffer: *[windows_util.PATH_MAX_WIDE]u16) ![]u16 {
pub fn selfExePath(out_buffer: *[MAX_PATH_BYTES]u8) ![]u8 {
switch (builtin.os) {
Os.linux => return readLink(out_buffer, "/proc/self/exe"),
Os.freebsd => return readLink(out_buffer, "/proc/curproc/file"),
Os.windows => {
var utf16le_buf: [windows_util.PATH_MAX_WIDE]u16 = undefined;
const utf16le_slice = try selfExePathW(&utf16le_buf);
@ -2250,7 +2286,7 @@ pub fn selfExeDirPath(out_buffer: *[MAX_PATH_BYTES]u8) ![]const u8 {
// will not return null.
return path.dirname(full_exe_path).?;
},
Os.windows, Os.macosx, Os.ios => {
Os.windows, Os.macosx, Os.ios, Os.freebsd => {
const self_exe_path = try selfExePath(out_buffer);
// Assume that the OS APIs return absolute paths, and therefore dirname
// will not return null.
@ -3095,10 +3131,13 @@ pub const CpuCountError = error{
pub fn cpuCount(fallback_allocator: *mem.Allocator) CpuCountError!usize {
switch (builtin.os) {
builtin.Os.macosx => {
builtin.Os.macosx, builtin.Os.freebsd => {
var count: c_int = undefined;
var count_len: usize = @sizeOf(c_int);
const rc = posix.sysctlbyname(c"hw.logicalcpu", @ptrCast(*c_void, &count), &count_len, null, 0);
const rc = posix.sysctlbyname(switch (builtin.os) {
builtin.Os.macosx => c"hw.logicalcpu",
else => c"hw.ncpu",
}, @ptrCast(*c_void, &count), &count_len, null, 0);
const err = posix.getErrno(rc);
switch (err) {
0 => return @intCast(usize, count),

View File

@ -703,7 +703,7 @@ pub fn dup2(old: i32, new: i32) usize {
}
pub fn dup3(old: i32, new: i32, flags: u32) usize {
return syscall3(SYS_dup3, @intCast(usize, old), @intCast(usize, new), flags);
return syscall3(SYS_dup3, @bitCast(usize, isize(old)), @bitCast(usize, isize(new)), flags);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -747,7 +747,7 @@ pub fn getcwd(buf: [*]u8, size: usize) usize {
}
pub fn getdents64(fd: i32, dirp: [*]u8, count: usize) usize {
return syscall3(SYS_getdents64, @intCast(usize, fd), @ptrToInt(dirp), count);
return syscall3(SYS_getdents64, @bitCast(usize, isize(fd)), @ptrToInt(dirp), count);
}
pub fn inotify_init1(flags: u32) usize {
@ -755,16 +755,16 @@ pub fn inotify_init1(flags: u32) usize {
}
pub fn inotify_add_watch(fd: i32, pathname: [*]const u8, mask: u32) usize {
return syscall3(SYS_inotify_add_watch, @intCast(usize, fd), @ptrToInt(pathname), mask);
return syscall3(SYS_inotify_add_watch, @bitCast(usize, isize(fd)), @ptrToInt(pathname), mask);
}
pub fn inotify_rm_watch(fd: i32, wd: i32) usize {
return syscall2(SYS_inotify_rm_watch, @intCast(usize, fd), @intCast(usize, wd));
return syscall2(SYS_inotify_rm_watch, @bitCast(usize, isize(fd)), @bitCast(usize, isize(wd)));
}
pub fn isatty(fd: i32) bool {
var wsz: winsize = undefined;
return syscall3(SYS_ioctl, @intCast(usize, fd), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
return syscall3(SYS_ioctl, @bitCast(usize, isize(fd)), TIOCGWINSZ, @ptrToInt(&wsz)) == 0;
}
// TODO https://github.com/ziglang/zig/issues/265
@ -774,7 +774,7 @@ pub fn readlink(noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usiz
// TODO https://github.com/ziglang/zig/issues/265
pub fn readlinkat(dirfd: i32, noalias path: [*]const u8, noalias buf_ptr: [*]u8, buf_len: usize) usize {
return syscall4(SYS_readlinkat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
return syscall4(SYS_readlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(buf_ptr), buf_len);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -784,7 +784,7 @@ pub fn mkdir(path: [*]const u8, mode: u32) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn mkdirat(dirfd: i32, path: [*]const u8, mode: u32) usize {
return syscall3(SYS_mkdirat, @intCast(usize, dirfd), @ptrToInt(path), mode);
return syscall3(SYS_mkdirat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -803,7 +803,7 @@ pub fn umount2(special: [*]const u8, flags: u32) usize {
}
pub fn mmap(address: ?[*]u8, length: usize, prot: usize, flags: u32, fd: i32, offset: isize) usize {
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @intCast(usize, fd), @bitCast(usize, offset));
return syscall6(SYS_mmap, @ptrToInt(address), length, prot, flags, @bitCast(usize, isize(fd)), @bitCast(usize, offset));
}
pub fn munmap(address: usize, length: usize) usize {
@ -811,23 +811,23 @@ pub fn munmap(address: usize, length: usize) usize {
}
pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
return syscall3(SYS_read, @intCast(usize, fd), @ptrToInt(buf), count);
return syscall3(SYS_read, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
}
pub fn preadv(fd: i32, iov: [*]const iovec, count: usize, offset: u64) usize {
return syscall4(SYS_preadv, @intCast(usize, fd), @ptrToInt(iov), count, offset);
return syscall4(SYS_preadv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
}
pub fn readv(fd: i32, iov: [*]const iovec, count: usize) usize {
return syscall3(SYS_readv, @intCast(usize, fd), @ptrToInt(iov), count);
return syscall3(SYS_readv, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
}
pub fn writev(fd: i32, iov: [*]const iovec_const, count: usize) usize {
return syscall3(SYS_writev, @intCast(usize, fd), @ptrToInt(iov), count);
return syscall3(SYS_writev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count);
}
pub fn pwritev(fd: i32, iov: [*]const iovec_const, count: usize, offset: u64) usize {
return syscall4(SYS_pwritev, @intCast(usize, fd), @ptrToInt(iov), count, offset);
return syscall4(SYS_pwritev, @bitCast(usize, isize(fd)), @ptrToInt(iov), count, offset);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -842,12 +842,12 @@ pub fn symlink(existing: [*]const u8, new: [*]const u8) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn symlinkat(existing: [*]const u8, newfd: i32, newpath: [*]const u8) usize {
return syscall3(SYS_symlinkat, @ptrToInt(existing), @intCast(usize, newfd), @ptrToInt(newpath));
return syscall3(SYS_symlinkat, @ptrToInt(existing), @bitCast(usize, isize(newfd)), @ptrToInt(newpath));
}
// TODO https://github.com/ziglang/zig/issues/265
pub fn pread(fd: i32, buf: [*]u8, count: usize, offset: usize) usize {
return syscall4(SYS_pread, @intCast(usize, fd), @ptrToInt(buf), count, offset);
return syscall4(SYS_pread, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -856,7 +856,7 @@ pub fn access(path: [*]const u8, mode: u32) usize {
}
pub fn faccessat(dirfd: i32, path: [*]const u8, mode: u32) usize {
return syscall3(SYS_faccessat, @intCast(usize, dirfd), @ptrToInt(path), mode);
return syscall3(SYS_faccessat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), mode);
}
pub fn pipe(fd: *[2]i32) usize {
@ -868,11 +868,11 @@ pub fn pipe2(fd: *[2]i32, flags: u32) usize {
}
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
return syscall3(SYS_write, @intCast(usize, fd), @ptrToInt(buf), count);
return syscall3(SYS_write, @bitCast(usize, isize(fd)), @ptrToInt(buf), count);
}
pub fn pwrite(fd: i32, buf: [*]const u8, count: usize, offset: usize) usize {
return syscall4(SYS_pwrite, @intCast(usize, fd), @ptrToInt(buf), count, offset);
return syscall4(SYS_pwrite, @bitCast(usize, isize(fd)), @ptrToInt(buf), count, offset);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -882,7 +882,7 @@ pub fn rename(old: [*]const u8, new: [*]const u8) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn renameat2(oldfd: i32, oldpath: [*]const u8, newfd: i32, newpath: [*]const u8, flags: u32) usize {
return syscall5(SYS_renameat2, @intCast(usize, oldfd), @ptrToInt(oldpath), @intCast(usize, newfd), @ptrToInt(newpath), flags);
return syscall5(SYS_renameat2, @bitCast(usize, isize(oldfd)), @ptrToInt(oldpath), @bitCast(usize, isize(newfd)), @ptrToInt(newpath), flags);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -897,7 +897,8 @@ pub fn create(path: [*]const u8, perm: usize) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn openat(dirfd: i32, path: [*]const u8, flags: u32, mode: usize) usize {
return syscall4(SYS_openat, @intCast(usize, dirfd), @ptrToInt(path), flags, mode);
// dirfd could be negative, for example AT_FDCWD is -100
return syscall4(SYS_openat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags, mode);
}
/// See also `clone` (from the arch-specific include)
@ -911,11 +912,11 @@ pub fn clone2(flags: u32, child_stack_ptr: usize) usize {
}
pub fn close(fd: i32) usize {
return syscall1(SYS_close, @intCast(usize, fd));
return syscall1(SYS_close, @bitCast(usize, isize(fd)));
}
pub fn lseek(fd: i32, offset: isize, ref_pos: usize) usize {
return syscall3(SYS_lseek, @intCast(usize, fd), @bitCast(usize, offset), ref_pos);
return syscall3(SYS_lseek, @bitCast(usize, isize(fd)), @bitCast(usize, offset), ref_pos);
}
pub fn exit(status: i32) noreturn {
@ -933,7 +934,7 @@ pub fn getrandom(buf: [*]u8, count: usize, flags: u32) usize {
}
pub fn kill(pid: i32, sig: i32) usize {
return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @intCast(usize, sig));
return syscall2(SYS_kill, @bitCast(usize, isize(pid)), @bitCast(usize, isize(sig)));
}
// TODO https://github.com/ziglang/zig/issues/265
@ -943,7 +944,7 @@ pub fn unlink(path: [*]const u8) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn unlinkat(dirfd: i32, path: [*]const u8, flags: u32) usize {
return syscall3(SYS_unlinkat, @intCast(usize, dirfd), @ptrToInt(path), flags);
return syscall3(SYS_unlinkat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), flags);
}
pub fn waitpid(pid: i32, status: *i32, options: i32) usize {
@ -1120,8 +1121,8 @@ pub const empty_sigset = []usize{0} ** sigset_t.len;
pub fn raise(sig: i32) usize {
var set: sigset_t = undefined;
blockAppSignals(&set);
const tid = @intCast(i32, syscall0(SYS_gettid));
const ret = syscall2(SYS_tkill, @intCast(usize, tid), @intCast(usize, sig));
const tid = syscall0(SYS_gettid);
const ret = syscall2(SYS_tkill, tid, @bitCast(usize, isize(sig)));
restoreSignals(&set);
return ret;
}
@ -1189,11 +1190,11 @@ pub const iovec_const = extern struct {
};
pub fn getsockname(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
return syscall3(SYS_getsockname, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len));
return syscall3(SYS_getsockname, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
}
pub fn getpeername(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
return syscall3(SYS_getpeername, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len));
return syscall3(SYS_getpeername, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len));
}
pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
@ -1201,47 +1202,47 @@ pub fn socket(domain: u32, socket_type: u32, protocol: u32) usize {
}
pub fn setsockopt(fd: i32, level: u32, optname: u32, optval: [*]const u8, optlen: socklen_t) usize {
return syscall5(SYS_setsockopt, @intCast(usize, fd), level, optname, @intCast(usize, optval), @ptrToInt(optlen));
return syscall5(SYS_setsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @intCast(usize, optlen));
}
pub fn getsockopt(fd: i32, level: u32, optname: u32, noalias optval: [*]u8, noalias optlen: *socklen_t) usize {
return syscall5(SYS_getsockopt, @intCast(usize, fd), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
return syscall5(SYS_getsockopt, @bitCast(usize, isize(fd)), level, optname, @ptrToInt(optval), @ptrToInt(optlen));
}
pub fn sendmsg(fd: i32, msg: *const msghdr, flags: u32) usize {
return syscall3(SYS_sendmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
return syscall3(SYS_sendmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
}
pub fn connect(fd: i32, addr: *const c_void, len: socklen_t) usize {
return syscall3(SYS_connect, @intCast(usize, fd), @ptrToInt(addr), len);
return syscall3(SYS_connect, @bitCast(usize, isize(fd)), @ptrToInt(addr), len);
}
pub fn recvmsg(fd: i32, msg: *msghdr, flags: u32) usize {
return syscall3(SYS_recvmsg, @intCast(usize, fd), @ptrToInt(msg), flags);
return syscall3(SYS_recvmsg, @bitCast(usize, isize(fd)), @ptrToInt(msg), flags);
}
pub fn recvfrom(fd: i32, noalias buf: [*]u8, len: usize, flags: u32, noalias addr: ?*sockaddr, noalias alen: ?*socklen_t) usize {
return syscall6(SYS_recvfrom, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
return syscall6(SYS_recvfrom, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @ptrToInt(alen));
}
pub fn shutdown(fd: i32, how: i32) usize {
return syscall2(SYS_shutdown, @intCast(usize, fd), @intCast(usize, how));
return syscall2(SYS_shutdown, @bitCast(usize, isize(fd)), @bitCast(usize, isize(how)));
}
pub fn bind(fd: i32, addr: *const sockaddr, len: socklen_t) usize {
return syscall3(SYS_bind, @intCast(usize, fd), @ptrToInt(addr), @intCast(usize, len));
return syscall3(SYS_bind, @bitCast(usize, isize(fd)), @ptrToInt(addr), @intCast(usize, len));
}
pub fn listen(fd: i32, backlog: u32) usize {
return syscall2(SYS_listen, @intCast(usize, fd), backlog);
return syscall2(SYS_listen, @bitCast(usize, isize(fd)), backlog);
}
pub fn sendto(fd: i32, buf: [*]const u8, len: usize, flags: u32, addr: ?*const sockaddr, alen: socklen_t) usize {
return syscall6(SYS_sendto, @intCast(usize, fd), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
return syscall6(SYS_sendto, @bitCast(usize, isize(fd)), @ptrToInt(buf), len, flags, @ptrToInt(addr), @intCast(usize, alen));
}
pub fn socketpair(domain: i32, socket_type: i32, protocol: i32, fd: [2]i32) usize {
return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(*fd[0]));
return syscall4(SYS_socketpair, @intCast(usize, domain), @intCast(usize, socket_type), @intCast(usize, protocol), @ptrToInt(&fd[0]));
}
pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
@ -1249,11 +1250,11 @@ pub fn accept(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t) usize {
}
pub fn accept4(fd: i32, noalias addr: *sockaddr, noalias len: *socklen_t, flags: u32) usize {
return syscall4(SYS_accept4, @intCast(usize, fd), @ptrToInt(addr), @ptrToInt(len), flags);
return syscall4(SYS_accept4, @bitCast(usize, isize(fd)), @ptrToInt(addr), @ptrToInt(len), flags);
}
pub fn fstat(fd: i32, stat_buf: *Stat) usize {
return syscall2(SYS_fstat, @intCast(usize, fd), @ptrToInt(stat_buf));
return syscall2(SYS_fstat, @bitCast(usize, isize(fd)), @ptrToInt(stat_buf));
}
// TODO https://github.com/ziglang/zig/issues/265
@ -1268,7 +1269,7 @@ pub fn lstat(pathname: [*]const u8, statbuf: *Stat) usize {
// TODO https://github.com/ziglang/zig/issues/265
pub fn fstatat(dirfd: i32, path: [*]const u8, stat_buf: *Stat, flags: u32) usize {
return syscall4(SYS_fstatat, @intCast(usize, dirfd), @ptrToInt(path), @ptrToInt(stat_buf), flags);
return syscall4(SYS_fstatat, @bitCast(usize, isize(dirfd)), @ptrToInt(path), @ptrToInt(stat_buf), flags);
}
// TODO https://github.com/ziglang/zig/issues/265
@ -1355,7 +1356,7 @@ pub fn epoll_create1(flags: usize) usize {
}
pub fn epoll_ctl(epoll_fd: i32, op: u32, fd: i32, ev: *epoll_event) usize {
return syscall4(SYS_epoll_ctl, @intCast(usize, epoll_fd), @intCast(usize, op), @intCast(usize, fd), @ptrToInt(ev));
return syscall4(SYS_epoll_ctl, @bitCast(usize, isize(epoll_fd)), @intCast(usize, op), @bitCast(usize, isize(fd)), @ptrToInt(ev));
}
pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32) usize {
@ -1363,7 +1364,15 @@ pub fn epoll_wait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout
}
pub fn epoll_pwait(epoll_fd: i32, events: [*]epoll_event, maxevents: u32, timeout: i32, sigmask: ?*sigset_t) usize {
return syscall6(SYS_epoll_pwait, @intCast(usize, epoll_fd), @ptrToInt(events), @intCast(usize, maxevents), @intCast(usize, timeout), @ptrToInt(sigmask), @sizeOf(sigset_t));
return syscall6(
SYS_epoll_pwait,
@bitCast(usize, isize(epoll_fd)),
@ptrToInt(events),
@intCast(usize, maxevents),
@bitCast(usize, isize(timeout)),
@ptrToInt(sigmask),
@sizeOf(sigset_t),
);
}
pub fn eventfd(count: u32, flags: u32) usize {
@ -1371,7 +1380,7 @@ pub fn eventfd(count: u32, flags: u32) usize {
}
pub fn timerfd_create(clockid: i32, flags: u32) usize {
return syscall2(SYS_timerfd_create, @intCast(usize, clockid), flags);
return syscall2(SYS_timerfd_create, @bitCast(usize, isize(clockid)), flags);
}
pub const itimerspec = extern struct {
@ -1380,11 +1389,11 @@ pub const itimerspec = extern struct {
};
pub fn timerfd_gettime(fd: i32, curr_value: *itimerspec) usize {
return syscall2(SYS_timerfd_gettime, @intCast(usize, fd), @ptrToInt(curr_value));
return syscall2(SYS_timerfd_gettime, @bitCast(usize, isize(fd)), @ptrToInt(curr_value));
}
pub fn timerfd_settime(fd: i32, flags: u32, new_value: *const itimerspec, old_value: ?*itimerspec) usize {
return syscall4(SYS_timerfd_settime, @intCast(usize, fd), flags, @ptrToInt(new_value), @ptrToInt(old_value));
return syscall4(SYS_timerfd_settime, @bitCast(usize, isize(fd)), flags, @ptrToInt(new_value), @ptrToInt(old_value));
}
pub const _LINUX_CAPABILITY_VERSION_1 = 0x19980330;

View File

@ -1093,6 +1093,7 @@ pub const RealError = error{
NoSpaceLeft,
FileSystem,
BadPathName,
DeviceBusy,
/// On Windows, file paths must be valid Unicode.
InvalidUtf8,
@ -1183,11 +1184,20 @@ pub fn realC(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: [*]const u8) RealErro
const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0);
defer os.close(fd);
var buf: ["/proc/self/fd/-2147483648".len]u8 = undefined;
var buf: ["/proc/self/fd/-2147483648\x00".len]u8 = undefined;
const proc_path = fmt.bufPrint(buf[0..], "/proc/self/fd/{}\x00", fd) catch unreachable;
return os.readLinkC(out_buffer, proc_path.ptr);
},
Os.freebsd => { // XXX requires fdescfs
const fd = try os.posixOpenC(pathname, posix.O_PATH | posix.O_NONBLOCK | posix.O_CLOEXEC, 0);
defer os.close(fd);
var buf: ["/dev/fd/-2147483648\x00".len]u8 = undefined;
const proc_path = fmt.bufPrint(buf[0..], "/dev/fd/{}\x00", fd) catch unreachable;
return os.readLinkC(out_buffer, proc_path.ptr);
},
else => @compileError("TODO implement os.path.real for " ++ @tagName(builtin.os)),
}
}
@ -1202,7 +1212,7 @@ pub fn real(out_buffer: *[os.MAX_PATH_BYTES]u8, pathname: []const u8) RealError!
const pathname_w = try windows_util.sliceToPrefixedFileW(pathname);
return realW(out_buffer, &pathname_w);
},
Os.macosx, Os.ios, Os.linux => {
Os.macosx, Os.ios, Os.linux, Os.freebsd => {
const pathname_c = try os.toPosixPath(pathname);
return realC(out_buffer, &pathname_c);
},

View File

@ -50,7 +50,7 @@ pub extern "kernel32" stdcallcc fn FindFirstFileW(lpFileName: [*]const u16, lpFi
pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
pub extern "kernel32" stdcallcc fn FindNextFileW(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAW) BOOL;
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsW(penv: [*]u16) BOOL;
pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
@ -63,9 +63,9 @@ pub extern "kernel32" stdcallcc fn GetCurrentDirectoryW(nBufferLength: DWORD, lp
pub extern "kernel32" stdcallcc fn GetCurrentThread() HANDLE;
pub extern "kernel32" stdcallcc fn GetCurrentThreadId() DWORD;
pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
pub extern "kernel32" stdcallcc fn GetEnvironmentStringsW() ?[*]u16;
pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
pub extern "kernel32" stdcallcc fn GetEnvironmentVariableW(lpName: LPWSTR, lpBuffer: LPWSTR, nSize: DWORD) DWORD;
pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;

View File

@ -12,20 +12,20 @@ pub const Message = struct {
args: [5]usize,
payload: ?[]const u8,
pub fn from(mailbox_id: *const MailboxId) Message {
pub fn from(mailbox_id: MailboxId) Message {
return Message{
.sender = MailboxId.Undefined,
.receiver = mailbox_id.*,
.receiver = mailbox_id,
.code = undefined,
.args = undefined,
.payload = null,
};
}
pub fn to(mailbox_id: *const MailboxId, msg_code: usize, args: ...) Message {
pub fn to(mailbox_id: MailboxId, msg_code: usize, args: ...) Message {
var message = Message{
.sender = MailboxId.This,
.receiver = mailbox_id.*,
.receiver = mailbox_id,
.code = msg_code,
.args = undefined,
.payload = null,
@ -40,14 +40,14 @@ pub const Message = struct {
return message;
}
pub fn as(self: *const Message, sender: *const MailboxId) Message {
var message = self.*;
message.sender = sender.*;
pub fn as(self: Message, sender: MailboxId) Message {
var message = self;
message.sender = sender;
return message;
}
pub fn withPayload(self: *const Message, payload: []const u8) Message {
var message = self.*;
pub fn withPayload(self: Message, payload: []const u8) Message {
var message = self;
message.payload = payload;
return message;
}
@ -93,7 +93,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
STDIN_FILENO => {
var i: usize = 0;
while (i < count) : (i += 1) {
send(Message.to(Server.Keyboard, 0));
send(&Message.to(Server.Keyboard, 0));
// FIXME: we should be certain that we are receiving from Keyboard.
var message = Message.from(MailboxId.This);
@ -111,7 +111,7 @@ pub fn read(fd: i32, buf: [*]u8, count: usize) usize {
pub fn write(fd: i32, buf: [*]const u8, count: usize) usize {
switch (fd) {
STDOUT_FILENO, STDERR_FILENO => {
send(Message.to(Server.Terminal, 1).withPayload(buf[0..count]));
send(&Message.to(Server.Terminal, 1).withPayload(buf[0..count]));
},
else => unreachable,
}

View File

@ -34,6 +34,7 @@ pub const DbiStreamHeader = packed struct {
};
pub const SectionContribEntry = packed struct {
/// COFF Section index, 1-based
Section: u16,
Padding1: [2]u8,
Offset: u32,
@ -507,11 +508,11 @@ const Msf = struct {
allocator,
);
const stream_count = try self.directory.stream.readIntLe(u32);
const stream_count = try self.directory.stream.readIntLittle(u32);
const stream_sizes = try allocator.alloc(u32, stream_count);
for (stream_sizes) |*s| {
const size = try self.directory.stream.readIntLe(u32);
const size = try self.directory.stream.readIntLittle(u32);
s.* = blockCountFromSize(size, superblock.BlockSize);
}
@ -602,7 +603,7 @@ const MsfStream = struct {
var i: u32 = 0;
while (i < block_count) : (i += 1) {
stream.blocks[i] = try in.readIntLe(u32);
stream.blocks[i] = try in.readIntLittle(u32);
}
return stream;

View File

@ -5,7 +5,7 @@
// ```
// var buf: [8]u8 = undefined;
// try std.os.getRandomBytes(buf[0..]);
// const seed = mem.readIntLE(u64, buf[0..8]);
// const seed = mem.readIntSliceLittle(u64, buf[0..8]);
//
// var r = DefaultPrng.init(seed);
//
@ -52,11 +52,24 @@ pub const Random = struct {
// use LE instead of native endian for better portability maybe?
// TODO: endian portability is pointless if the underlying prng isn't endian portable.
// TODO: document the endian portability of this library.
const byte_aligned_result = mem.readIntLE(ByteAlignedT, rand_bytes);
const byte_aligned_result = mem.readIntSliceLittle(ByteAlignedT, rand_bytes);
const unsigned_result = @truncate(UnsignedT, byte_aligned_result);
return @bitCast(T, unsigned_result);
}
/// Constant-time implementation off ::uintLessThan.
/// The results of this function may be biased.
pub fn uintLessThanBiased(r: *Random, comptime T: type, less_than: T) T {
comptime assert(T.is_signed == false);
comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
assert(0 < less_than);
if (T.bit_count <= 32) {
return @intCast(T, limitRangeBiased(u32, r.int(u32), less_than));
} else {
return @intCast(T, limitRangeBiased(u64, r.int(u64), less_than));
}
}
/// Returns an evenly distributed random unsigned integer `0 <= i < less_than`.
/// This function assumes that the underlying ::fillFn produces evenly distributed values.
/// Within this assumption, the runtime of this function is exponentially distributed.
@ -64,27 +77,52 @@ pub const Random = struct {
/// the runtime of this function would technically be unbounded.
/// However, if ::fillFn is backed by any evenly distributed pseudo random number generator,
/// this function is guaranteed to return.
/// If you need deterministic runtime bounds, consider instead using `r.int(T) % less_than`,
/// which will usually be biased toward smaller values.
/// If you need deterministic runtime bounds, use `::uintLessThanBiased`.
pub fn uintLessThan(r: *Random, comptime T: type, less_than: T) T {
assert(T.is_signed == false);
comptime assert(T.is_signed == false);
comptime assert(T.bit_count <= 64); // TODO: workaround: LLVM ERROR: Unsupported library call operation!
assert(0 < less_than);
// Small is typically u32
const Small = @IntType(false, @divTrunc(T.bit_count + 31, 32) * 32);
// Large is typically u64
const Large = @IntType(false, Small.bit_count * 2);
const last_group_size_minus_one: T = maxInt(T) % less_than;
if (last_group_size_minus_one == less_than - 1) {
// less_than is a power of two.
assert(math.floorPowerOfTwo(T, less_than) == less_than);
// There is no retry zone. The optimal retry_zone_start would be maxInt(T) + 1.
return r.int(T) % less_than;
}
const retry_zone_start = maxInt(T) - last_group_size_minus_one;
// adapted from:
// http://www.pcg-random.org/posts/bounded-rands.html
// "Lemire's (with an extra tweak from me)"
var x: Small = r.int(Small);
var m: Large = Large(x) * Large(less_than);
var l: Small = @truncate(Small, m);
if (l < less_than) {
// TODO: workaround for https://github.com/ziglang/zig/issues/1770
// should be:
// var t: Small = -%less_than;
var t: Small = @bitCast(Small, -%@bitCast(@IntType(true, Small.bit_count), Small(less_than)));
while (true) {
const rand_val = r.int(T);
if (rand_val < retry_zone_start) {
return rand_val % less_than;
if (t >= less_than) {
t -= less_than;
if (t >= less_than) {
t %= less_than;
}
}
while (l < t) {
x = r.int(Small);
m = Large(x) * Large(less_than);
l = @truncate(Small, m);
}
}
return @intCast(T, m >> Small.bit_count);
}
/// Constant-time implementation off ::uintAtMost.
/// The results of this function may be biased.
pub fn uintAtMostBiased(r: *Random, comptime T: type, at_most: T) T {
assert(T.is_signed == false);
if (at_most == maxInt(T)) {
// have the full range
return r.int(T);
}
return r.uintLessThanBiased(T, at_most + 1);
}
/// Returns an evenly distributed random unsigned integer `0 <= i <= at_most`.
@ -99,6 +137,23 @@ pub const Random = struct {
return r.uintLessThan(T, at_most + 1);
}
/// Constant-time implementation off ::intRangeLessThan.
/// The results of this function may be biased.
pub fn intRangeLessThanBiased(r: *Random, comptime T: type, at_least: T, less_than: T) T {
assert(at_least < less_than);
if (T.is_signed) {
// Two's complement makes this math pretty easy.
const UnsignedT = @IntType(false, T.bit_count);
const lo = @bitCast(UnsignedT, at_least);
const hi = @bitCast(UnsignedT, less_than);
const result = lo +% r.uintLessThanBiased(UnsignedT, hi -% lo);
return @bitCast(T, result);
} else {
// The signed implementation would work fine, but we can use stricter arithmetic operators here.
return at_least + r.uintLessThanBiased(T, less_than - at_least);
}
}
/// Returns an evenly distributed random integer `at_least <= i < less_than`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@ -117,6 +172,23 @@ pub const Random = struct {
}
}
/// Constant-time implementation off ::intRangeAtMostBiased.
/// The results of this function may be biased.
pub fn intRangeAtMostBiased(r: *Random, comptime T: type, at_least: T, at_most: T) T {
assert(at_least <= at_most);
if (T.is_signed) {
// Two's complement makes this math pretty easy.
const UnsignedT = @IntType(false, T.bit_count);
const lo = @bitCast(UnsignedT, at_least);
const hi = @bitCast(UnsignedT, at_most);
const result = lo +% r.uintAtMostBiased(UnsignedT, hi -% lo);
return @bitCast(T, result);
} else {
// The signed implementation would work fine, but we can use stricter arithmetic operators here.
return at_least + r.uintAtMostBiased(T, at_most - at_least);
}
}
/// Returns an evenly distributed random integer `at_least <= i <= at_most`.
/// See ::uintLessThan, which this function uses in most cases,
/// for commentary on the runtime of this function.
@ -135,15 +207,11 @@ pub const Random = struct {
}
}
/// Return a random integer/boolean type.
/// TODO: deprecated. use ::boolean or ::int instead.
pub fn scalar(r: *Random, comptime T: type) T {
if (T == bool) return r.boolean();
return r.int(T);
return if (T == bool) r.boolean() else r.int(T);
}
/// Return a random integer with even distribution between `start`
/// inclusive and `end` exclusive. `start` must be less than `end`.
/// TODO: deprecated. renamed to ::intRangeLessThan
pub fn range(r: *Random, comptime T: type, start: T, end: T) T {
return r.intRangeLessThan(T, start, end);
@ -206,6 +274,20 @@ pub const Random = struct {
}
};
/// Convert a random integer 0 <= random_int <= maxValue(T),
/// into an integer 0 <= result < less_than.
/// This function introduces a minor bias.
pub fn limitRangeBiased(comptime T: type, random_int: T, less_than: T) T {
comptime assert(T.is_signed == false);
const T2 = @IntType(false, T.bit_count * 2);
// adapted from:
// http://www.pcg-random.org/posts/bounded-rands.html
// "Integer Multiplication (Biased)"
var m: T2 = T2(random_int) * T2(less_than);
return @intCast(T, m >> T.bit_count);
}
const SequentialPrng = struct {
const Self = @This();
random: Random,
@ -294,10 +376,19 @@ fn testRandomIntLessThan() void {
var r = SequentialPrng.init();
r.next_value = 0xff;
assert(r.random.uintLessThan(u8, 4) == 3);
r.next_value = 0xff;
assert(r.random.uintLessThan(u8, 3) == 0);
assert(r.next_value == 0);
assert(r.random.uintLessThan(u8, 4) == 0);
assert(r.next_value == 1);
r.next_value = 0;
assert(r.random.uintLessThan(u64, 32) == 0);
// trigger the bias rejection code path
r.next_value = 0;
assert(r.random.uintLessThan(u8, 3) == 0);
// verify we incremented twice
assert(r.next_value == 2);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(u8, 0, 0x80) == 0x7f);
r.next_value = 0xff;
@ -310,17 +401,10 @@ fn testRandomIntLessThan() void {
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i8, -0x80, 0) == -1);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i64, -0x8000000000000000, 0) == -1);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i3, -4, 0) == -1);
r.next_value = 0xff;
assert(r.random.intRangeLessThan(i3, -2, 2) == 1);
// test retrying and eventually getting a good value
// start just out of bounds
r.next_value = 0x81;
assert(r.random.uintLessThan(u8, 0x81) == 0);
}
test "Random intAtMost" {
@ -332,9 +416,14 @@ fn testRandomIntAtMost() void {
var r = SequentialPrng.init();
r.next_value = 0xff;
assert(r.random.uintAtMost(u8, 3) == 3);
r.next_value = 0xff;
assert(r.next_value == 0);
assert(r.random.uintAtMost(u8, 3) == 0);
// trigger the bias rejection code path
r.next_value = 0;
assert(r.random.uintAtMost(u8, 2) == 0);
assert(r.next_value == 1);
// verify we incremented twice
assert(r.next_value == 2);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(u8, 0, 0x7f) == 0x7f);
@ -348,17 +437,43 @@ fn testRandomIntAtMost() void {
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i8, -0x80, -1) == -1);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i64, -0x8000000000000000, -1) == -1);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i3, -4, -1) == -1);
r.next_value = 0xff;
assert(r.random.intRangeAtMost(i3, -2, 1) == 1);
// test retrying and eventually getting a good value
// start just out of bounds
r.next_value = 0x81;
assert(r.random.uintAtMost(u8, 0x80) == 0);
assert(r.random.uintAtMost(u0, 0) == 0);
}
test "Random Biased" {
var r = DefaultPrng.init(0);
// Not thoroughly checking the logic here.
// Just want to execute all the paths with different types.
assert(r.random.uintLessThanBiased(u1, 1) == 0);
assert(r.random.uintLessThanBiased(u32, 10) < 10);
assert(r.random.uintLessThanBiased(u64, 20) < 20);
assert(r.random.uintAtMostBiased(u0, 0) == 0);
assert(r.random.uintAtMostBiased(u1, 0) <= 0);
assert(r.random.uintAtMostBiased(u32, 10) <= 10);
assert(r.random.uintAtMostBiased(u64, 20) <= 20);
assert(r.random.intRangeLessThanBiased(u1, 0, 1) == 0);
assert(r.random.intRangeLessThanBiased(i1, -1, 0) == -1);
assert(r.random.intRangeLessThanBiased(u32, 10, 20) >= 10);
assert(r.random.intRangeLessThanBiased(i32, 10, 20) >= 10);
assert(r.random.intRangeLessThanBiased(u64, 20, 40) >= 20);
assert(r.random.intRangeLessThanBiased(i64, 20, 40) >= 20);
// uncomment for broken module error:
//assert(r.random.intRangeAtMostBiased(u0, 0, 0) == 0);
assert(r.random.intRangeAtMostBiased(u1, 0, 1) >= 0);
assert(r.random.intRangeAtMostBiased(i1, -1, 0) >= -1);
assert(r.random.intRangeAtMostBiased(u32, 10, 20) >= 10);
assert(r.random.intRangeAtMostBiased(i32, 10, 20) >= 10);
assert(r.random.intRangeAtMostBiased(u64, 20, 40) >= 20);
assert(r.random.intRangeAtMostBiased(i64, 20, 40) >= 20);
}
// Generator to extend 64-bit seed values into longer sequences.
@ -870,12 +985,16 @@ test "Random range" {
}
fn testRange(r: *Random, start: i8, end: i8) void {
testRangeBias(r, start, end, true);
testRangeBias(r, start, end, false);
}
fn testRangeBias(r: *Random, start: i8, end: i8, biased: bool) void {
const count = @intCast(usize, i32(end) - i32(start));
var values_buffer = []bool{false} ** 0x100;
const values = values_buffer[0..count];
var i: usize = 0;
while (i < count) {
const value: i32 = r.intRangeLessThan(i8, start, end);
const value: i32 = if (biased) r.intRangeLessThanBiased(i8, start, end) else r.intRangeLessThan(i8, start, end);
const index = @intCast(usize, value - start);
if (!values[index]) {
i += 1;

View File

@ -12,7 +12,7 @@ const std = @import("../index.zig");
const math = std.math;
const Random = std.rand.Random;
pub fn next_f64(random: *Random, comptime tables: *const ZigTable) f64 {
pub fn next_f64(random: *Random, comptime tables: ZigTable) f64 {
while (true) {
// We manually construct a float from parts as we can avoid an extra random lookup here by
// using the unused exponent for the lookup table entry.

View File

@ -201,6 +201,11 @@ pub fn SegmentedList(comptime T: type, comptime prealloc_item_count: usize) type
self.dynamic_segments = self.allocator.shrink([*]T, self.dynamic_segments, new_cap_shelf_count);
}
pub fn shrink(self: *Self, new_len: usize) void {
assert(new_len <= self.len);
self.len = new_len;
}
pub fn uncheckedAt(self: var, index: usize) AtType(@typeOf(self)) {
if (index < prealloc_item_count) {
return &self.prealloc_segment[index];

View File

@ -20,10 +20,17 @@ comptime {
nakedcc fn _start() noreturn {
switch (builtin.arch) {
builtin.Arch.x86_64 => {
argc_ptr = asm ("lea (%%rsp), %[argc]"
: [argc] "=r" (-> [*]usize)
);
builtin.Arch.x86_64 => switch (builtin.os) {
builtin.Os.freebsd => {
argc_ptr = asm ("lea (%%rdi), %[argc]"
: [argc] "=r" (-> [*]usize)
);
},
else => {
argc_ptr = asm ("lea (%%rsp), %[argc]"
: [argc] "=r" (-> [*]usize)
);
},
},
builtin.Arch.i386 => {
argc_ptr = asm ("lea (%%esp), %[argc]"
@ -50,6 +57,9 @@ extern fn WinMainCRTStartup() noreturn {
// TODO https://github.com/ziglang/zig/issues/265
fn posixCallMainAndExit() noreturn {
if (builtin.os == builtin.Os.freebsd) {
@setAlignStack(16);
}
const argc = argc_ptr[0];
const argv = @ptrCast([*][*]u8, argc_ptr + 1);

View File

@ -164,7 +164,6 @@ fn usage(builder: *Builder, already_ran_build: bool, out_stream: var) !void {
\\
\\General Options:
\\ --help Print this help and exit
\\ --init Generate a build.zig template
\\ --verbose Print commands before executing them
\\ --prefix [path] Override default install prefix
\\ --search-prefix [path] Add a path to look for binaries, libraries, headers

View File

@ -0,0 +1,11 @@
const fixint = @import("fixint.zig").fixint;
const builtin = @import("builtin");
pub extern fn __fixdfdi(a: f64) i64 {
@setRuntimeSafety(builtin.is_test);
return fixint(f64, i64, a);
}
test "import fixdfdi" {
_ = @import("fixdfdi_test.zig");
}

View File

@ -0,0 +1,66 @@
const __fixdfdi = @import("fixdfdi.zig").__fixdfdi;
const std = @import("std");
const math = std.math;
const assert = std.debug.assert;
const warn = std.debug.warn;
fn test__fixdfdi(a: f64, expected: i64) void {
const x = __fixdfdi(a);
//warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u64, expected));
assert(x == expected);
}
test "fixdfdi" {
//warn("\n");
test__fixdfdi(-math.f64_max, math.minInt(i64));
test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i64));
test__fixdfdi(-0x1.FFFFFFFFFFFFFp+1023, -0x8000000000000000);
test__fixdfdi(-0x1.0000000000000p+127, -0x8000000000000000);
test__fixdfdi(-0x1.FFFFFFFFFFFFFp+126, -0x8000000000000000);
test__fixdfdi(-0x1.FFFFFFFFFFFFEp+126, -0x8000000000000000);
test__fixdfdi(-0x1.0000000000001p+63, -0x8000000000000000);
test__fixdfdi(-0x1.0000000000000p+63, -0x8000000000000000);
test__fixdfdi(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
test__fixdfdi(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
test__fixdfdi(-0x1.FFFFFEp+62, -0x7fffff8000000000);
test__fixdfdi(-0x1.FFFFFCp+62, -0x7fffff0000000000);
test__fixdfdi(-2.01, -2);
test__fixdfdi(-2.0, -2);
test__fixdfdi(-1.99, -1);
test__fixdfdi(-1.0, -1);
test__fixdfdi(-0.99, 0);
test__fixdfdi(-0.5, 0);
test__fixdfdi(-math.f64_min, 0);
test__fixdfdi(0.0, 0);
test__fixdfdi(math.f64_min, 0);
test__fixdfdi(0.5, 0);
test__fixdfdi(0.99, 0);
test__fixdfdi(1.0, 1);
test__fixdfdi(1.5, 1);
test__fixdfdi(1.99, 1);
test__fixdfdi(2.0, 2);
test__fixdfdi(2.01, 2);
test__fixdfdi(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
test__fixdfdi(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
test__fixdfdi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
test__fixdfdi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
test__fixdfdi(0x1.0000000000000p+63, 0x7FFFFFFFFFFFFFFF);
test__fixdfdi(0x1.0000000000001p+63, 0x7FFFFFFFFFFFFFFF);
test__fixdfdi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFFFFF);
test__fixdfdi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFFFF);
test__fixdfdi(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFF);
test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFF);
test__fixdfdi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i64));
test__fixdfdi(math.f64_max, math.maxInt(i64));
}

View File

@ -0,0 +1,11 @@
const fixint = @import("fixint.zig").fixint;
const builtin = @import("builtin");
pub extern fn __fixdfsi(a: f64) i32 {
@setRuntimeSafety(builtin.is_test);
return fixint(f64, i32, a);
}
test "import fixdfsi" {
_ = @import("fixdfsi_test.zig");
}

View File

@ -0,0 +1,74 @@
const __fixdfsi = @import("fixdfsi.zig").__fixdfsi;
const std = @import("std");
const math = std.math;
const assert = std.debug.assert;
const warn = std.debug.warn;
fn test__fixdfsi(a: f64, expected: i32) void {
const x = __fixdfsi(a);
//warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u32, expected));
assert(x == expected);
}
test "fixdfsi" {
//warn("\n");
test__fixdfsi(-math.f64_max, math.minInt(i32));
test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i32));
test__fixdfsi(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000);
test__fixdfsi(-0x1.0000000000000p+127, -0x80000000);
test__fixdfsi(-0x1.FFFFFFFFFFFFFp+126, -0x80000000);
test__fixdfsi(-0x1.FFFFFFFFFFFFEp+126, -0x80000000);
test__fixdfsi(-0x1.0000000000001p+63, -0x80000000);
test__fixdfsi(-0x1.0000000000000p+63, -0x80000000);
test__fixdfsi(-0x1.FFFFFFFFFFFFFp+62, -0x80000000);
test__fixdfsi(-0x1.FFFFFFFFFFFFEp+62, -0x80000000);
test__fixdfsi(-0x1.FFFFFEp+62, -0x80000000);
test__fixdfsi(-0x1.FFFFFCp+62, -0x80000000);
test__fixdfsi(-0x1.000000p+31, -0x80000000);
test__fixdfsi(-0x1.FFFFFFp+30, -0x7FFFFFC0);
test__fixdfsi(-0x1.FFFFFEp+30, -0x7FFFFF80);
test__fixdfsi(-2.01, -2);
test__fixdfsi(-2.0, -2);
test__fixdfsi(-1.99, -1);
test__fixdfsi(-1.0, -1);
test__fixdfsi(-0.99, 0);
test__fixdfsi(-0.5, 0);
test__fixdfsi(-math.f64_min, 0);
test__fixdfsi(0.0, 0);
test__fixdfsi(math.f64_min, 0);
test__fixdfsi(0.5, 0);
test__fixdfsi(0.99, 0);
test__fixdfsi(1.0, 1);
test__fixdfsi(1.5, 1);
test__fixdfsi(1.99, 1);
test__fixdfsi(2.0, 2);
test__fixdfsi(2.01, 2);
test__fixdfsi(0x1.FFFFFEp+30, 0x7FFFFF80);
test__fixdfsi(0x1.FFFFFFp+30, 0x7FFFFFC0);
test__fixdfsi(0x1.000000p+31, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFCp+62, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFEp+62, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFF);
test__fixdfsi(0x1.0000000000000p+63, 0x7FFFFFFF);
test__fixdfsi(0x1.0000000000001p+63, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFF);
test__fixdfsi(0x1.0000000000000p+127, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFF);
test__fixdfsi(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i32));
test__fixdfsi(math.f64_max, math.maxInt(i32));
}

View File

@ -0,0 +1,11 @@
const fixint = @import("fixint.zig").fixint;
const builtin = @import("builtin");
pub extern fn __fixdfti(a: f64) i128 {
@setRuntimeSafety(builtin.is_test);
return fixint(f64, i128, a);
}
test "import fixdfti" {
_ = @import("fixdfti_test.zig");
}

View File

@ -0,0 +1,66 @@
const __fixdfti = @import("fixdfti.zig").__fixdfti;
const std = @import("std");
const math = std.math;
const assert = std.debug.assert;
const warn = std.debug.warn;
fn test__fixdfti(a: f64, expected: i128) void {
const x = __fixdfti(a);
//warn("a={}:{x} x={}:{x} expected={}:{x}:u64({x})\n", a, @bitCast(u64, a), x, x, expected, expected, @bitCast(u128, expected));
assert(x == expected);
}
test "fixdfti" {
//warn("\n");
test__fixdfti(-math.f64_max, math.minInt(i128));
test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, math.minInt(i128));
test__fixdfti(-0x1.FFFFFFFFFFFFFp+1023, -0x80000000000000000000000000000000);
test__fixdfti(-0x1.0000000000000p+127, -0x80000000000000000000000000000000);
test__fixdfti(-0x1.FFFFFFFFFFFFFp+126, -0x7FFFFFFFFFFFFC000000000000000000);
test__fixdfti(-0x1.FFFFFFFFFFFFEp+126, -0x7FFFFFFFFFFFF8000000000000000000);
test__fixdfti(-0x1.0000000000001p+63, -0x8000000000000800);
test__fixdfti(-0x1.0000000000000p+63, -0x8000000000000000);
test__fixdfti(-0x1.FFFFFFFFFFFFFp+62, -0x7FFFFFFFFFFFFC00);
test__fixdfti(-0x1.FFFFFFFFFFFFEp+62, -0x7FFFFFFFFFFFF800);
test__fixdfti(-0x1.FFFFFEp+62, -0x7fffff8000000000);
test__fixdfti(-0x1.FFFFFCp+62, -0x7fffff0000000000);
test__fixdfti(-2.01, -2);
test__fixdfti(-2.0, -2);
test__fixdfti(-1.99, -1);
test__fixdfti(-1.0, -1);
test__fixdfti(-0.99, 0);
test__fixdfti(-0.5, 0);
test__fixdfti(-math.f64_min, 0);
test__fixdfti(0.0, 0);
test__fixdfti(math.f64_min, 0);
test__fixdfti(0.5, 0);
test__fixdfti(0.99, 0);
test__fixdfti(1.0, 1);
test__fixdfti(1.5, 1);
test__fixdfti(1.99, 1);
test__fixdfti(2.0, 2);
test__fixdfti(2.01, 2);
test__fixdfti(0x1.FFFFFCp+62, 0x7FFFFF0000000000);
test__fixdfti(0x1.FFFFFEp+62, 0x7FFFFF8000000000);
test__fixdfti(0x1.FFFFFFFFFFFFEp+62, 0x7FFFFFFFFFFFF800);
test__fixdfti(0x1.FFFFFFFFFFFFFp+62, 0x7FFFFFFFFFFFFC00);
test__fixdfti(0x1.0000000000000p+63, 0x8000000000000000);
test__fixdfti(0x1.0000000000001p+63, 0x8000000000000800);
test__fixdfti(0x1.FFFFFFFFFFFFEp+126, 0x7FFFFFFFFFFFF8000000000000000000);
test__fixdfti(0x1.FFFFFFFFFFFFFp+126, 0x7FFFFFFFFFFFFC000000000000000000);
test__fixdfti(0x1.0000000000000p+127, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF);
test__fixdfti(0x1.FFFFFFFFFFFFFp+1023, math.maxInt(i128));
test__fixdfti(math.f64_max, math.maxInt(i128));
}

View File

@ -0,0 +1,74 @@
const is_test = @import("builtin").is_test;
const std = @import("std");
const math = std.math;
const Log2Int = std.math.Log2Int;
const maxInt = std.math.maxInt;
const minInt = std.math.minInt;
const DBG = false;
pub fn fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t) fixint_t {
@setRuntimeSafety(is_test);
const rep_t = switch (fp_t) {
f32 => u32,
f64 => u64,
f128 => u128,
else => unreachable,
};
const significandBits = switch (fp_t) {
f32 => 23,
f64 => 52,
f128 => 112,
else => unreachable,
};
const typeWidth = rep_t.bit_count;
const exponentBits = (typeWidth - significandBits - 1);
const signBit = (rep_t(1) << (significandBits + exponentBits));
const maxExponent = ((1 << exponentBits) - 1);
const exponentBias = (maxExponent >> 1);
const implicitBit = (rep_t(1) << significandBits);
const significandMask = (implicitBit - 1);
// Break a into sign, exponent, significand
const aRep: rep_t = @bitCast(rep_t, a);
const absMask = signBit - 1;
const aAbs: rep_t = aRep & absMask;
const negative = (aRep & signBit) != 0;
const exponent = @intCast(i32, aAbs >> significandBits) - exponentBias;
const significand: rep_t = (aAbs & significandMask) | implicitBit;
// If exponent is negative, the uint_result is zero.
if (exponent < 0) return 0;
// The unsigned result needs to be large enough to handle an fixint_t or rep_t
const fixuint_t = @IntType(false, fixint_t.bit_count);
const UintResultType = if (fixint_t.bit_count > rep_t.bit_count) fixuint_t else rep_t;
var uint_result: UintResultType = undefined;
// If the value is too large for the integer type, saturate.
if (@intCast(usize, exponent) >= fixint_t.bit_count) {
return if (negative) fixint_t(minInt(fixint_t)) else fixint_t(maxInt(fixint_t));
}
// If 0 <= exponent < significandBits, right shift else left shift
if (exponent < significandBits) {
uint_result = @intCast(UintResultType, significand) >> @intCast(Log2Int(UintResultType), significandBits - exponent);
} else {
uint_result = @intCast(UintResultType, significand) << @intCast(Log2Int(UintResultType), exponent - significandBits);
}
// Cast to final signed result
if (negative) {
return if (uint_result >= -math.minInt(fixint_t)) math.minInt(fixint_t) else -@intCast(fixint_t, uint_result);
} else {
return if (uint_result >= math.maxInt(fixint_t)) math.maxInt(fixint_t) else @intCast(fixint_t, uint_result);
}
}
test "import fixint" {
_ = @import("fixint_test.zig");
}

View File

@ -0,0 +1,152 @@
const is_test = @import("builtin").is_test;
const std = @import("std");
const math = std.math;
const assert = std.debug.assert;
const warn = std.debug.warn;
const fixint = @import("fixint.zig").fixint;
fn test__fixint(comptime fp_t: type, comptime fixint_t: type, a: fp_t, expected: fixint_t) void {
const x = fixint(fp_t, fixint_t, a);
//warn("a={} x={}:{x} expected={}:{x})\n", a, x, x, expected, expected);
assert(x == expected);
}
test "fixint.i1" {
test__fixint(f32, i1, -math.inf_f32, -1);
test__fixint(f32, i1, -math.f32_max, -1);
test__fixint(f32, i1, -2.0, -1);
test__fixint(f32, i1, -1.1, -1);
test__fixint(f32, i1, -1.0, -1);
test__fixint(f32, i1, -0.9, 0);
test__fixint(f32, i1, -0.1, 0);
test__fixint(f32, i1, -math.f32_min, 0);
test__fixint(f32, i1, -0.0, 0);
test__fixint(f32, i1, 0.0, 0);
test__fixint(f32, i1, math.f32_min, 0);
test__fixint(f32, i1, 0.1, 0);
test__fixint(f32, i1, 0.9, 0);
test__fixint(f32, i1, 1.0, 0);
test__fixint(f32, i1, 2.0, 0);
test__fixint(f32, i1, math.f32_max, 0);
test__fixint(f32, i1, math.inf_f32, 0);
}
test "fixint.i2" {
test__fixint(f32, i2, -math.inf_f32, -2);
test__fixint(f32, i2, -math.f32_max, -2);
test__fixint(f32, i2, -2.0, -2);
test__fixint(f32, i2, -1.9, -1);
test__fixint(f32, i2, -1.1, -1);
test__fixint(f32, i2, -1.0, -1);
test__fixint(f32, i2, -0.9, 0);
test__fixint(f32, i2, -0.1, 0);
test__fixint(f32, i2, -math.f32_min, 0);
test__fixint(f32, i2, -0.0, 0);
test__fixint(f32, i2, 0.0, 0);
test__fixint(f32, i2, math.f32_min, 0);
test__fixint(f32, i2, 0.1, 0);
test__fixint(f32, i2, 0.9, 0);
test__fixint(f32, i2, 1.0, 1);
test__fixint(f32, i2, 2.0, 1);
test__fixint(f32, i2, math.f32_max, 1);
test__fixint(f32, i2, math.inf_f32, 1);
}
test "fixint.i3" {
test__fixint(f32, i3, -math.inf_f32, -4);
test__fixint(f32, i3, -math.f32_max, -4);
test__fixint(f32, i3, -4.0, -4);
test__fixint(f32, i3, -3.0, -3);
test__fixint(f32, i3, -2.0, -2);
test__fixint(f32, i3, -1.9, -1);
test__fixint(f32, i3, -1.1, -1);
test__fixint(f32, i3, -1.0, -1);
test__fixint(f32, i3, -0.9, 0);
test__fixint(f32, i3, -0.1, 0);
test__fixint(f32, i3, -math.f32_min, 0);
test__fixint(f32, i3, -0.0, 0);
test__fixint(f32, i3, 0.0, 0);
test__fixint(f32, i3, math.f32_min, 0);
test__fixint(f32, i3, 0.1, 0);
test__fixint(f32, i3, 0.9, 0);
test__fixint(f32, i3, 1.0, 1);
test__fixint(f32, i3, 2.0, 2);
test__fixint(f32, i3, 3.0, 3);
test__fixint(f32, i3, 4.0, 3);
test__fixint(f32, i3, math.f32_max, 3);
test__fixint(f32, i3, math.inf_f32, 3);
}
test "fixint.i32" {
test__fixint(f64, i32, -math.inf_f64, math.minInt(i32));
test__fixint(f64, i32, -math.f64_max, math.minInt(i32));
test__fixint(f64, i32, f64(math.minInt(i32)), math.minInt(i32));
test__fixint(f64, i32, f64(math.minInt(i32))+1, math.minInt(i32)+1);
test__fixint(f64, i32, -2.0, -2);
test__fixint(f64, i32, -1.9, -1);
test__fixint(f64, i32, -1.1, -1);
test__fixint(f64, i32, -1.0, -1);
test__fixint(f64, i32, -0.9, 0);
test__fixint(f64, i32, -0.1, 0);
test__fixint(f64, i32, -math.f32_min, 0);
test__fixint(f64, i32, -0.0, 0);
test__fixint(f64, i32, 0.0, 0);
test__fixint(f64, i32, math.f32_min, 0);
test__fixint(f64, i32, 0.1, 0);
test__fixint(f64, i32, 0.9, 0);
test__fixint(f64, i32, 1.0, 1);
test__fixint(f64, i32, f64(math.maxInt(i32))-1, math.maxInt(i32)-1);
test__fixint(f64, i32, f64(math.maxInt(i32)), math.maxInt(i32));
test__fixint(f64, i32, math.f64_max, math.maxInt(i32));
test__fixint(f64, i32, math.inf_f64, math.maxInt(i32));
}
test "fixint.i64" {
test__fixint(f64, i64, -math.inf_f64, math.minInt(i64));
test__fixint(f64, i64, -math.f64_max, math.minInt(i64));
test__fixint(f64, i64, f64(math.minInt(i64)), math.minInt(i64));
test__fixint(f64, i64, f64(math.minInt(i64))+1, math.minInt(i64));
test__fixint(f64, i64, f64(math.minInt(i64)/2), math.minInt(i64)/2);
test__fixint(f64, i64, -2.0, -2);
test__fixint(f64, i64, -1.9, -1);
test__fixint(f64, i64, -1.1, -1);
test__fixint(f64, i64, -1.0, -1);
test__fixint(f64, i64, -0.9, 0);
test__fixint(f64, i64, -0.1, 0);
test__fixint(f64, i64, -math.f32_min, 0);
test__fixint(f64, i64, -0.0, 0);
test__fixint(f64, i64, 0.0, 0);
test__fixint(f64, i64, math.f32_min, 0);
test__fixint(f64, i64, 0.1, 0);
test__fixint(f64, i64, 0.9, 0);
test__fixint(f64, i64, 1.0, 1);
test__fixint(f64, i64, f64(math.maxInt(i64))-1, math.maxInt(i64));
test__fixint(f64, i64, f64(math.maxInt(i64)), math.maxInt(i64));
test__fixint(f64, i64, math.f64_max, math.maxInt(i64));
test__fixint(f64, i64, math.inf_f64, math.maxInt(i64));
}
test "fixint.i128" {
test__fixint(f64, i128, -math.inf_f64, math.minInt(i128));
test__fixint(f64, i128, -math.f64_max, math.minInt(i128));
test__fixint(f64, i128, f64(math.minInt(i128)), math.minInt(i128));
test__fixint(f64, i128, f64(math.minInt(i128))+1, math.minInt(i128));
test__fixint(f64, i128, -2.0, -2);
test__fixint(f64, i128, -1.9, -1);
test__fixint(f64, i128, -1.1, -1);
test__fixint(f64, i128, -1.0, -1);
test__fixint(f64, i128, -0.9, 0);
test__fixint(f64, i128, -0.1, 0);
test__fixint(f64, i128, -math.f32_min, 0);
test__fixint(f64, i128, -0.0, 0);
test__fixint(f64, i128, 0.0, 0);
test__fixint(f64, i128, math.f32_min, 0);
test__fixint(f64, i128, 0.1, 0);
test__fixint(f64, i128, 0.9, 0);
test__fixint(f64, i128, 1.0, 1);
test__fixint(f64, i128, f64(math.maxInt(i128))-1, math.maxInt(i128));
test__fixint(f64, i128, f64(math.maxInt(i128)), math.maxInt(i128));
test__fixint(f64, i128, math.f64_max, math.maxInt(i128));
test__fixint(f64, i128, math.inf_f64, math.maxInt(i128));
}

Some files were not shown because too many files have changed in this diff Show More