authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-11 20:22:49-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2019-09-12 01:40:58-04:00
logcf4bccf76566ac112f9142863c3e4dbf81e71d08
tree8c0f3565b3a2f233b0b90ac79b752730de7c9774
parent68b49f74c45f9d46ceca0196ad5b2edeee30e26f
signaturelock-open Commit is signed but in an unrecognized format.

improvements targeted at improving async functions

* Reuse bytes of async function frames when non-async functions make `noasync` calls. This prevents explosive stack growth. * Zig now passes a stack size argument to the linker when linking ELF binaries. Linux ignores this value, but it is available as a program header called GNU_STACK. I prototyped some code that memory maps extra space to the stack using this program header, but there was still a problem when accessing stack memory very far down. Stack probing is needed or not working or something. I also prototyped using `@newStackCall` to call main and that does work around the issue but it also brings its own issues. That code is commented out for now in std/special/start.zig. I'm on a plane with no Internet, but I plan to consult with the musl community for advice when I get a chance. * Added `noasync` to a bunch of function calls in std.debug. It's very messy but it's a workaround that makes stack traces functional with evented I/O enabled. Eventually these will be cleaned up as the root bugs are found and fixed. Programs built in blocking mode are unaffected. * Lowered the default stack size of std.io.InStream (for the async version) to 1 MiB instead of 4. Until we figure out how to get choosing a stack size working (see 2nd bullet point above), 4 MiB tends to cause segfaults due to stack size running out, or usage of stack memory too far apart, or something like that. * Default thread stack size is bumped from 8 MiB to 16 to match the size we give for the main thread. It's planned to eventually remove this hard coded value and have Zig able to determine this value during semantic analysis, with call graph analysis and function pointer annotations and extern function annotations.

7 files changed, 90 insertions(+), 32 deletions(-)

src/codegen.cpp+12-2
...@@ -7184,6 +7184,9 @@ static void do_code_gen(CodeGen *g) {...@@ -7184,6 +7184,9 @@ static void do_code_gen(CodeGen *g) {
71847184
7185 if (!is_async) {7185 if (!is_async) {
7186 // allocate async frames for noasync calls & awaits to async functions7186 // allocate async frames for noasync calls & awaits to async functions
7187 ZigType *largest_call_frame_type = nullptr;
7188 IrInstruction *all_calls_alloca = ir_create_alloca(g, &fn_table_entry->fndef_scope->base,
7189 fn_table_entry->body_node, fn_table_entry, g->builtin_types.entry_void, "@async_call_frame");
7187 for (size_t i = 0; i < fn_table_entry->call_list.length; i += 1) {7190 for (size_t i = 0; i < fn_table_entry->call_list.length; i += 1) {
7188 IrInstructionCallGen *call = fn_table_entry->call_list.at(i);7191 IrInstructionCallGen *call = fn_table_entry->call_list.at(i);
7189 if (call->fn_entry == nullptr)7192 if (call->fn_entry == nullptr)
...@@ -7195,8 +7198,15 @@ static void do_code_gen(CodeGen *g) {...@@ -7195,8 +7198,15 @@ static void do_code_gen(CodeGen *g) {
7195 if (call->frame_result_loc != nullptr)7198 if (call->frame_result_loc != nullptr)
7196 continue;7199 continue;
7197 ZigType *callee_frame_type = get_fn_frame_type(g, call->fn_entry);7200 ZigType *callee_frame_type = get_fn_frame_type(g, call->fn_entry);
7198 call->frame_result_loc = ir_create_alloca(g, call->base.scope, call->base.source_node,7201 if (largest_call_frame_type == nullptr ||
7199 fn_table_entry, callee_frame_type, "");7202 callee_frame_type->abi_size > largest_call_frame_type->abi_size)
7203 {
7204 largest_call_frame_type = callee_frame_type;
7205 }
7206 call->frame_result_loc = all_calls_alloca;
7207 }
7208 if (largest_call_frame_type != nullptr) {
7209 all_calls_alloca->value.type = get_pointer_to_type(g, largest_call_frame_type, false);
7200 }7210 }
7201 // allocate temporary stack data7211 // allocate temporary stack data
7202 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {7212 for (size_t alloca_i = 0; alloca_i < fn_table_entry->alloca_gen_list.length; alloca_i += 1) {
src/link.cpp+5
...@@ -1615,6 +1615,11 @@ static void construct_linker_job_elf(LinkJob *lj) {...@@ -1615,6 +1615,11 @@ static void construct_linker_job_elf(LinkJob *lj) {
16151615
1616 lj->args.append("-error-limit=0");1616 lj->args.append("-error-limit=0");
16171617
1618 if (g->out_type == OutTypeExe) {
1619 lj->args.append("-z");
1620 lj->args.append("stack-size=16777216"); // default to 16 MiB
1621 }
1622
1618 if (g->linker_script) {1623 if (g->linker_script) {
1619 lj->args.append("-T");1624 lj->args.append("-T");
1620 lj->args.append(g->linker_script);1625 lj->args.append(g->linker_script);
std/debug.zig+34-15
...@@ -1478,10 +1478,11 @@ const LineNumberProgram = struct {...@@ -1478,10 +1478,11 @@ const LineNumberProgram = struct {
1478 }1478 }
1479};1479};
14801480
1481// TODO the noasyncs here are workarounds
1481fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {1482fn readStringRaw(allocator: *mem.Allocator, in_stream: var) ![]u8 {
1482 var buf = ArrayList(u8).init(allocator);1483 var buf = ArrayList(u8).init(allocator);
1483 while (true) {1484 while (true) {
1484 const byte = try in_stream.readByte();1485 const byte = try noasync in_stream.readByte();
1485 if (byte == 0) break;1486 if (byte == 0) break;
1486 try buf.append(byte);1487 try buf.append(byte);
1487 }1488 }
...@@ -1494,10 +1495,11 @@ fn getString(di: *DwarfInfo, offset: u64) ![]u8 {...@@ -1494,10 +1495,11 @@ fn getString(di: *DwarfInfo, offset: u64) ![]u8 {
1494 return di.readString();1495 return di.readString();
1495}1496}
14961497
1498// TODO the noasyncs here are workarounds
1497fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {1499fn readAllocBytes(allocator: *mem.Allocator, in_stream: var, size: usize) ![]u8 {
1498 const buf = try allocator.alloc(u8, size);1500 const buf = try allocator.alloc(u8, size);
1499 errdefer allocator.free(buf);1501 errdefer allocator.free(buf);
1500 if ((try in_stream.read(buf)) < size) return error.EndOfFile;1502 if ((try noasync in_stream.read(buf)) < size) return error.EndOfFile;
1501 return buf;1503 return buf;
1502}1504}
15031505
...@@ -1506,8 +1508,9 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize...@@ -1506,8 +1508,9 @@ fn parseFormValueBlockLen(allocator: *mem.Allocator, in_stream: var, size: usize
1506 return FormValue{ .Block = buf };1508 return FormValue{ .Block = buf };
1507}1509}
15081510
1511// TODO the noasyncs here are workarounds
1509fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {1512fn parseFormValueBlock(allocator: *mem.Allocator, in_stream: var, size: usize) !FormValue {
1510 const block_len = try in_stream.readVarInt(usize, builtin.Endian.Little, size);1513 const block_len = try noasync in_stream.readVarInt(usize, builtin.Endian.Little, size);
1511 return parseFormValueBlockLen(allocator, in_stream, block_len);1514 return parseFormValueBlockLen(allocator, in_stream, block_len);
1512}1515}
15131516
...@@ -1537,27 +1540,37 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo...@@ -1537,27 +1540,37 @@ fn parseFormValueConstant(allocator: *mem.Allocator, in_stream: var, signed: boo
1537 };1540 };
1538}1541}
15391542
1543// TODO the noasyncs here are workarounds
1540fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {1544fn parseFormValueDwarfOffsetSize(in_stream: var, is_64: bool) !u64 {
1541 return if (is_64) try in_stream.readIntLittle(u64) else u64(try in_stream.readIntLittle(u32));1545 return if (is_64) try noasync in_stream.readIntLittle(u64) else u64(try noasync in_stream.readIntLittle(u32));
1542}1546}
15431547
1548// TODO the noasyncs here are workarounds
1544fn parseFormValueTargetAddrSize(in_stream: var) !u64 {1549fn parseFormValueTargetAddrSize(in_stream: var) !u64 {
1545 return if (@sizeOf(usize) == 4) u64(try in_stream.readIntLittle(u32)) else if (@sizeOf(usize) == 8) try in_stream.readIntLittle(u64) else unreachable;1550 if (@sizeOf(usize) == 4) {
1551 return u64(try noasync in_stream.readIntLittle(u32));
1552 } else if (@sizeOf(usize) == 8) {
1553 return noasync in_stream.readIntLittle(u64);
1554 } else {
1555 unreachable;
1556 }
1546}1557}
15471558
1559// TODO the noasyncs here are workarounds
1548fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {1560fn parseFormValueRef(allocator: *mem.Allocator, in_stream: var, size: i32) !FormValue {
1549 return FormValue{1561 return FormValue{
1550 .Ref = switch (size) {1562 .Ref = switch (size) {
1551 1 => try in_stream.readIntLittle(u8),1563 1 => try noasync in_stream.readIntLittle(u8),
1552 2 => try in_stream.readIntLittle(u16),1564 2 => try noasync in_stream.readIntLittle(u16),
1553 4 => try in_stream.readIntLittle(u32),1565 4 => try noasync in_stream.readIntLittle(u32),
1554 8 => try in_stream.readIntLittle(u64),1566 8 => try noasync in_stream.readIntLittle(u64),
1555 -1 => try leb.readULEB128(u64, in_stream),1567 -1 => try noasync leb.readULEB128(u64, in_stream),
1556 else => unreachable,1568 else => unreachable,
1557 },1569 },
1558 };1570 };
1559}1571}
15601572
1573// TODO the noasyncs here are workarounds
1561fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {1574fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64: bool) anyerror!FormValue {
1562 return switch (form_id) {1575 return switch (form_id) {
1563 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },1576 DW.FORM_addr => FormValue{ .Address = try parseFormValueTargetAddrSize(in_stream) },
...@@ -1565,7 +1578,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1565,7 +1578,7 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1565 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),1578 DW.FORM_block2 => parseFormValueBlock(allocator, in_stream, 2),
1566 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),1579 DW.FORM_block4 => parseFormValueBlock(allocator, in_stream, 4),
1567 DW.FORM_block => x: {1580 DW.FORM_block => x: {
1568 const block_len = try leb.readULEB128(usize, in_stream);1581 const block_len = try noasync leb.readULEB128(usize, in_stream);
1569 return parseFormValueBlockLen(allocator, in_stream, block_len);1582 return parseFormValueBlockLen(allocator, in_stream, block_len);
1570 },1583 },
1571 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),1584 DW.FORM_data1 => parseFormValueConstant(allocator, in_stream, false, 1),
...@@ -1577,11 +1590,11 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1577,11 +1590,11 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1577 return parseFormValueConstant(allocator, in_stream, signed, -1);1590 return parseFormValueConstant(allocator, in_stream, signed, -1);
1578 },1591 },
1579 DW.FORM_exprloc => {1592 DW.FORM_exprloc => {
1580 const size = try leb.readULEB128(usize, in_stream);1593 const size = try noasync leb.readULEB128(usize, in_stream);
1581 const buf = try readAllocBytes(allocator, in_stream, size);1594 const buf = try readAllocBytes(allocator, in_stream, size);
1582 return FormValue{ .ExprLoc = buf };1595 return FormValue{ .ExprLoc = buf };
1583 },1596 },
1584 DW.FORM_flag => FormValue{ .Flag = (try in_stream.readByte()) != 0 },1597 DW.FORM_flag => FormValue{ .Flag = (try noasync in_stream.readByte()) != 0 },
1585 DW.FORM_flag_present => FormValue{ .Flag = true },1598 DW.FORM_flag_present => FormValue{ .Flag = true },
1586 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },1599 DW.FORM_sec_offset => FormValue{ .SecOffset = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
15871600
...@@ -1592,12 +1605,12 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64...@@ -1592,12 +1605,12 @@ fn parseFormValue(allocator: *mem.Allocator, in_stream: var, form_id: u64, is_64
1592 DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),1605 DW.FORM_ref_udata => parseFormValueRef(allocator, in_stream, -1),
15931606
1594 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },1607 DW.FORM_ref_addr => FormValue{ .RefAddr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1595 DW.FORM_ref_sig8 => FormValue{ .Ref = try in_stream.readIntLittle(u64) },1608 DW.FORM_ref_sig8 => FormValue{ .Ref = try noasync in_stream.readIntLittle(u64) },
15961609
1597 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },1610 DW.FORM_string => FormValue{ .String = try readStringRaw(allocator, in_stream) },
1598 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },1611 DW.FORM_strp => FormValue{ .StrPtr = try parseFormValueDwarfOffsetSize(in_stream, is_64) },
1599 DW.FORM_indirect => {1612 DW.FORM_indirect => {
1600 const child_form_id = try leb.readULEB128(u64, in_stream);1613 const child_form_id = try noasync leb.readULEB128(u64, in_stream);
1601 const F = @typeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));1614 const F = @typeOf(async parseFormValue(allocator, in_stream, child_form_id, is_64));
1602 var frame = try allocator.create(F);1615 var frame = try allocator.create(F);
1603 defer allocator.destroy(frame);1616 defer allocator.destroy(frame);
...@@ -2400,3 +2413,9 @@ stdcallcc fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) c_long {...@@ -2400,3 +2413,9 @@ stdcallcc fn handleSegfaultWindows(info: *windows.EXCEPTION_POINTERS) c_long {
2400 else => return windows.EXCEPTION_CONTINUE_SEARCH,2413 else => return windows.EXCEPTION_CONTINUE_SEARCH,
2401 }2414 }
2402}2415}
2416
2417pub fn dumpStackPointerAddr(prefix: []const u8) void {
2418 const sp = asm ("" : [argc] "={rsp}" (-> usize));
2419 std.debug.warn("{} sp = 0x{x}\n", prefix, sp);
2420}
2421
std/io/in_stream.zig+1-1
...@@ -6,7 +6,7 @@ const assert = std.debug.assert;...@@ -6,7 +6,7 @@ const assert = std.debug.assert;
6const mem = std.mem;6const mem = std.mem;
7const Buffer = std.Buffer;7const Buffer = std.Buffer;
88
9pub const default_stack_size = 4 * 1024 * 1024;9pub const default_stack_size = 1 * 1024 * 1024;
10pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream"))10pub const stack_size: usize = if (@hasDecl(root, "stack_size_std_io_InStream"))
11 root.stack_size_std_io_InStream11 root.stack_size_std_io_InStream
12else12else
std/os/linux/tls.zig+6-1
...@@ -125,7 +125,7 @@ pub fn setThreadPointer(addr: usize) void {...@@ -125,7 +125,7 @@ pub fn setThreadPointer(addr: usize) void {
125 }125 }
126}126}
127127
128pub fn initTLS() void {128pub fn initTLS() ?*elf.Phdr {
129 var tls_phdr: ?*elf.Phdr = null;129 var tls_phdr: ?*elf.Phdr = null;
130 var img_base: usize = 0;130 var img_base: usize = 0;
131131
...@@ -152,10 +152,13 @@ pub fn initTLS() void {...@@ -152,10 +152,13 @@ pub fn initTLS() void {
152 // Search the TLS section152 // Search the TLS section
153 const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum];153 const phdrs = (@intToPtr([*]elf.Phdr, at_phdr))[0..at_phnum];
154154
155 var gnu_stack: ?*elf.Phdr = null;
156
155 for (phdrs) |*phdr| {157 for (phdrs) |*phdr| {
156 switch (phdr.p_type) {158 switch (phdr.p_type) {
157 elf.PT_PHDR => img_base = at_phdr - phdr.p_vaddr,159 elf.PT_PHDR => img_base = at_phdr - phdr.p_vaddr,
158 elf.PT_TLS => tls_phdr = phdr,160 elf.PT_TLS => tls_phdr = phdr,
161 elf.PT_GNU_STACK => gnu_stack = phdr,
159 else => continue,162 else => continue,
160 }163 }
161 }164 }
...@@ -217,6 +220,8 @@ pub fn initTLS() void {...@@ -217,6 +220,8 @@ pub fn initTLS() void {
217 .data_offset = data_offset,220 .data_offset = data_offset,
218 };221 };
219 }222 }
223
224 return gnu_stack;
220}225}
221226
222pub fn copyTLS(addr: usize) usize {227pub fn copyTLS(addr: usize) usize {
std/special/start.zig+31-12
...@@ -5,7 +5,7 @@ const std = @import("std");...@@ -5,7 +5,7 @@ const std = @import("std");
5const builtin = @import("builtin");5const builtin = @import("builtin");
6const assert = std.debug.assert;6const assert = std.debug.assert;
77
8var argc_ptr: [*]usize = undefined;8var starting_stack_ptr: [*]usize = undefined;
99
10const is_wasm = switch (builtin.arch) {10const is_wasm = switch (builtin.arch) {
11 .wasm32, .wasm64 => true,11 .wasm32, .wasm64 => true,
...@@ -35,17 +35,17 @@ nakedcc fn _start() noreturn {...@@ -35,17 +35,17 @@ nakedcc fn _start() noreturn {
3535
36 switch (builtin.arch) {36 switch (builtin.arch) {
37 .x86_64 => {37 .x86_64 => {
38 argc_ptr = asm (""38 starting_stack_ptr = asm (""
39 : [argc] "={rsp}" (-> [*]usize)39 : [argc] "={rsp}" (-> [*]usize)
40 );40 );
41 },41 },
42 .i386 => {42 .i386 => {
43 argc_ptr = asm (""43 starting_stack_ptr = asm (""
44 : [argc] "={esp}" (-> [*]usize)44 : [argc] "={esp}" (-> [*]usize)
45 );45 );
46 },46 },
47 .aarch64, .aarch64_be, .arm => {47 .aarch64, .aarch64_be, .arm => {
48 argc_ptr = asm ("mov %[argc], sp"48 starting_stack_ptr = asm ("mov %[argc], sp"
49 : [argc] "=r" (-> [*]usize)49 : [argc] "=r" (-> [*]usize)
50 );50 );
51 },51 },
...@@ -72,8 +72,8 @@ fn posixCallMainAndExit() noreturn {...@@ -72,8 +72,8 @@ fn posixCallMainAndExit() noreturn {
72 if (builtin.os == builtin.Os.freebsd) {72 if (builtin.os == builtin.Os.freebsd) {
73 @setAlignStack(16);73 @setAlignStack(16);
74 }74 }
75 const argc = argc_ptr[0];75 const argc = starting_stack_ptr[0];
76 const argv = @ptrCast([*][*]u8, argc_ptr + 1);76 const argv = @ptrCast([*][*]u8, starting_stack_ptr + 1);
7777
78 const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1);78 const envp_optional = @ptrCast([*]?[*]u8, argv + argc + 1);
79 var envp_count: usize = 0;79 var envp_count: usize = 0;
...@@ -85,21 +85,40 @@ fn posixCallMainAndExit() noreturn {...@@ -85,21 +85,40 @@ fn posixCallMainAndExit() noreturn {
85 const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);85 const auxv = @ptrCast([*]std.elf.Auxv, envp.ptr + envp_count + 1);
86 std.os.linux.elf_aux_maybe = auxv;86 std.os.linux.elf_aux_maybe = auxv;
87 // Initialize the TLS area87 // Initialize the TLS area
88 std.os.linux.tls.initTLS();88 const gnu_stack_phdr = std.os.linux.tls.initTLS() orelse @panic("ELF missing stack size");
8989
90 if (std.os.linux.tls.tls_image) |tls_img| {90 if (std.os.linux.tls.tls_image) |tls_img| {
91 const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size);91 const tls_addr = std.os.linux.tls.allocateTLS(tls_img.alloc_size);
92 const tp = std.os.linux.tls.copyTLS(tls_addr);92 const tp = std.os.linux.tls.copyTLS(tls_addr);
93 std.os.linux.tls.setThreadPointer(tp);93 std.os.linux.tls.setThreadPointer(tp);
94 }94 }
95
96 // TODO This is disabled because what should we do when linking libc and this code
97 // does not execute? And also it's causing a test failure in stack traces in release modes.
98
99 //// Linux ignores the stack size from the ELF file, and instead always does 8 MiB. A further
100 //// problem is that it uses PROT_GROWSDOWN which prevents stores to addresses too far down
101 //// the stack and requires "probing". So here we allocate our own stack.
102 //const wanted_stack_size = gnu_stack_phdr.p_memsz;
103 //assert(wanted_stack_size % std.mem.page_size == 0);
104 //// Allocate an extra page as the guard page.
105 //const total_size = wanted_stack_size + std.mem.page_size;
106 //const new_stack = std.os.mmap(
107 // null,
108 // total_size,
109 // std.os.PROT_READ | std.os.PROT_WRITE,
110 // std.os.MAP_PRIVATE | std.os.MAP_ANONYMOUS,
111 // -1,
112 // 0,
113 //) catch @panic("out of memory");
114 //std.os.mprotect(new_stack[0..std.mem.page_size], std.os.PROT_NONE) catch {};
115 //std.os.exit(@newStackCall(new_stack, callMainWithArgs, argc, argv, envp));
95 }116 }
96117
97 std.os.exit(callMainWithArgs(argc, argv, envp));118 std.os.exit(@inlineCall(callMainWithArgs, argc, argv, envp));
98}119}
99120
100// This is marked inline because for some reason LLVM in release mode fails to inline it,121fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
101// and we want fewer call frames in stack traces.
102inline fn callMainWithArgs(argc: usize, argv: [*][*]u8, envp: [][*]u8) u8 {
103 std.os.argv = argv[0..argc];122 std.os.argv = argv[0..argc];
104 std.os.environ = envp;123 std.os.environ = envp;
105124
...@@ -112,7 +131,7 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 {...@@ -112,7 +131,7 @@ extern fn main(c_argc: i32, c_argv: [*][*]u8, c_envp: [*]?[*]u8) i32 {
112 var env_count: usize = 0;131 var env_count: usize = 0;
113 while (c_envp[env_count] != null) : (env_count += 1) {}132 while (c_envp[env_count] != null) : (env_count += 1) {}
114 const envp = @ptrCast([*][*]u8, c_envp)[0..env_count];133 const envp = @ptrCast([*][*]u8, c_envp)[0..env_count];
115 return callMainWithArgs(@intCast(usize, c_argc), c_argv, envp);134 return @inlineCall(callMainWithArgs, @intCast(usize, c_argc), c_argv, envp);
116}135}
117136
118// General error message for a malformed return type137// General error message for a malformed return type
std/thread.zig+1-1
...@@ -145,7 +145,7 @@ pub const Thread = struct {...@@ -145,7 +145,7 @@ pub const Thread = struct {
145 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");145 if (builtin.single_threaded) @compileError("cannot spawn thread when building in single-threaded mode");
146 // TODO compile-time call graph analysis to determine stack upper bound146 // TODO compile-time call graph analysis to determine stack upper bound
147 // https://github.com/ziglang/zig/issues/157147 // https://github.com/ziglang/zig/issues/157
148 const default_stack_size = 8 * 1024 * 1024;148 const default_stack_size = 16 * 1024 * 1024;
149149
150 const Context = @typeOf(context);150 const Context = @typeOf(context);
151 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);151 comptime assert(@ArgType(@typeOf(startFn), 0) == Context);