authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-03 18:11:57-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2017-04-03 18:11:57-04:00
logc9ae30d27e123f87fc9c10b6af2e380eab57d6df
tree97c8144f1f77a37f12ad8582cd56778d596d3181
parentc400cb429abf2980962739731f5b64861a54ab61

delete alloca builtin function

See #225 introduce os.EnvMap

10 files changed, 171 insertions(+), 206 deletions(-)

doc/langref.md-13
......@@ -295,19 +295,6 @@ has a terminating null byte.
295295Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on
296296a parameter means that the parameter must be known at compile time.
297297
298### @alloca(comptime T: type, count: usize) -> []T
299
300Allocates memory in the stack frame of the caller. This temporary space is
301automatically freed when the function that called alloca returns to its caller,
302just like other stack variables.
303
304When using this function to allocate memory, you should know the upper bound
305of `count`. Consider putting a constant array on the stack with the upper bound
306instead of using alloca. If you do use alloca it is to save a few bytes off
307the memory size given that you didn't actually hit your upper bound.
308
309The allocated memory contents are undefined.
310
311298### @typeOf(expression) -> type
312299
313300This function returns a compile-time constant, which is the type of the
src/all_types.hpp-10
......@@ -1190,7 +1190,6 @@ enum BuiltinFnId {
11901190 BuiltinFnIdTruncate,
11911191 BuiltinFnIdIntType,
11921192 BuiltinFnIdSetDebugSafety,
1193 BuiltinFnIdAlloca,
11941193 BuiltinFnIdTypeName,
11951194 BuiltinFnIdIsInteger,
11961195 BuiltinFnIdIsFloat,
......@@ -1706,7 +1705,6 @@ enum IrInstructionId {
17061705 IrInstructionIdTruncate,
17071706 IrInstructionIdIntType,
17081707 IrInstructionIdBoolNot,
1709 IrInstructionIdAlloca,
17101708 IrInstructionIdMemset,
17111709 IrInstructionIdMemcpy,
17121710 IrInstructionIdSlice,
......@@ -2234,14 +2232,6 @@ struct IrInstructionBoolNot {
22342232 IrInstruction *value;
22352233};
22362234
2237struct IrInstructionAlloca {
2238 IrInstruction base;
2239
2240 IrInstruction *type_value;
2241 IrInstruction *count;
2242 LLVMValueRef tmp_ptr;
2243};
2244
22452235struct IrInstructionMemset {
22462236 IrInstruction base;
22472237
src/codegen.cpp+1-27
......@@ -2190,26 +2190,6 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI
21902190 }
21912191}
21922192
2193static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) {
2194 TypeTableEntry *slice_type = get_underlying_type(instruction->base.value.type);
2195 TypeTableEntry *ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry;
2196 TypeTableEntry *child_type = ptr_type->data.pointer.child_type;
2197 LLVMValueRef size_val = ir_llvm_value(g, instruction->count);
2198 LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, size_val, "");
2199
2200 // TODO in debug mode, initialize all the bytes to 0xaa
2201
2202 // store the freshly allocated pointer in the slice
2203 LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_ptr_index, "");
2204 LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr);
2205
2206 // store the size in the len field
2207 LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_len_index, "");
2208 LLVMBuildStore(g->builder, size_val, len_field_ptr);
2209
2210 return instruction->tmp_ptr;
2211}
2212
22132193static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) {
22142194 LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);
22152195 LLVMValueRef char_val = ir_llvm_value(g, instruction->byte);
......@@ -2548,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
25482528 assert(instruction->tmp_ptr);
25492529
25502530 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");
2551 assert(child_type == instruction->value->value.type);
2531 // child_type and instruction->value->value.type may differ by constness
25522532 gen_assign_raw(g, val_ptr, payload_val, child_type);
25532533 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
25542534 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
......@@ -2796,8 +2776,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
27962776 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
27972777 case IrInstructionIdBoolNot:
27982778 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
2799 case IrInstructionIdAlloca:
2800 return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction);
28012779 case IrInstructionIdMemset:
28022780 return ir_render_memset(g, executable, (IrInstructionMemset *)instruction);
28032781 case IrInstructionIdMemcpy:
......@@ -3648,9 +3626,6 @@ static void do_code_gen(CodeGen *g) {
36483626 } else if (instruction->id == IrInstructionIdCall) {
36493627 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
36503628 slot = &call_instruction->tmp_ptr;
3651 } else if (instruction->id == IrInstructionIdAlloca) {
3652 IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;
3653 slot = &alloca_instruction->tmp_ptr;
36543629 } else if (instruction->id == IrInstructionIdSlice) {
36553630 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
36563631 slot = &slice_instruction->tmp_ptr;
......@@ -4326,7 +4301,6 @@ static void define_builtin_fns(CodeGen *g) {
43264301 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
43274302 create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);
43284303 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
4329 create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
43304304 create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
43314305 create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
43324306 create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
src/ir.cpp-77
......@@ -404,10 +404,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
404404 return IrInstructionIdBoolNot;
405405}
406406
407static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
408 return IrInstructionIdAlloca;
409}
410
411407static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) {
412408 return IrInstructionIdMemset;
413409}
......@@ -1668,27 +1664,6 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_
16681664 return new_instruction;
16691665}
16701666
1671static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node,
1672 IrInstruction *type_value, IrInstruction *count)
1673{
1674 IrInstructionAlloca *instruction = ir_build_instruction<IrInstructionAlloca>(irb, scope, source_node);
1675 instruction->type_value = type_value;
1676 instruction->count = count;
1677
1678 ir_ref_instruction(type_value, irb->current_basic_block);
1679 ir_ref_instruction(count, irb->current_basic_block);
1680
1681 return &instruction->base;
1682}
1683
1684static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_instruction,
1685 IrInstruction *type_value, IrInstruction *count)
1686{
1687 IrInstruction *new_instruction = ir_build_alloca(irb, old_instruction->scope, old_instruction->source_node, type_value, count);
1688 ir_link_new_instruction(new_instruction, old_instruction);
1689 return new_instruction;
1690}
1691
16921667static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node,
16931668 IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count)
16941669{
......@@ -2567,14 +2542,6 @@ static IrInstruction *ir_instruction_boolnot_get_dep(IrInstructionBoolNot *instr
25672542 }
25682543}
25692544
2570static IrInstruction *ir_instruction_alloca_get_dep(IrInstructionAlloca *instruction, size_t index) {
2571 switch (index) {
2572 case 0: return instruction->type_value;
2573 case 1: return instruction->count;
2574 default: return nullptr;
2575 }
2576}
2577
25782545static IrInstruction *ir_instruction_memset_get_dep(IrInstructionMemset *instruction, size_t index) {
25792546 switch (index) {
25802547 case 0: return instruction->dest_ptr;
......@@ -2938,8 +2905,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
29382905 return ir_instruction_inttype_get_dep((IrInstructionIntType *) instruction, index);
29392906 case IrInstructionIdBoolNot:
29402907 return ir_instruction_boolnot_get_dep((IrInstructionBoolNot *) instruction, index);
2941 case IrInstructionIdAlloca:
2942 return ir_instruction_alloca_get_dep((IrInstructionAlloca *) instruction, index);
29432908 case IrInstructionIdMemset:
29442909 return ir_instruction_memset_get_dep((IrInstructionMemset *) instruction, index);
29452910 case IrInstructionIdMemcpy:
......@@ -4100,20 +4065,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41004065
41014066 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
41024067 }
4103 case BuiltinFnIdAlloca:
4104 {
4105 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
4106 IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope);
4107 if (arg0_value == irb->codegen->invalid_instruction)
4108 return arg0_value;
4109
4110 AstNode *arg1_node = node->data.fn_call_expr.params.at(1);
4111 IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope);
4112 if (arg1_value == irb->codegen->invalid_instruction)
4113 return arg1_value;
4114
4115 return ir_build_alloca(irb, scope, node, arg0_value, arg1_value);
4116 }
41174068 case BuiltinFnIdMemcpy:
41184069 {
41194070 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);
......@@ -11461,31 +11412,6 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
1146111412 return bool_type;
1146211413}
1146311414
11464static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) {
11465 IrInstruction *type_value = instruction->type_value->other;
11466 if (type_is_invalid(type_value->value.type))
11467 return ira->codegen->builtin_types.entry_invalid;
11468
11469 IrInstruction *count_value = instruction->count->other;
11470 if (type_is_invalid(count_value->value.type))
11471 return ira->codegen->builtin_types.entry_invalid;
11472
11473 TypeTableEntry *child_type = ir_resolve_type(ira, type_value);
11474
11475 if (type_requires_comptime(child_type)) {
11476 ir_add_error(ira, type_value,
11477 buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name)));
11478 // TODO if this is a typedecl, add error note showing the declaration of the type decl
11479 return ira->codegen->builtin_types.entry_invalid;
11480 } else {
11481 TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false);
11482 IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value);
11483 ir_add_alloca(ira, new_instruction, slice_type);
11484 return slice_type;
11485 }
11486 zig_unreachable();
11487}
11488
1148911415static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {
1149011416 IrInstruction *dest_ptr = instruction->dest_ptr->other;
1149111417 if (type_is_invalid(dest_ptr->value.type))
......@@ -12550,8 +12476,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
1255012476 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
1255112477 case IrInstructionIdBoolNot:
1255212478 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
12553 case IrInstructionIdAlloca:
12554 return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
1255512479 case IrInstructionIdMemset:
1255612480 return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction);
1255712481 case IrInstructionIdMemcpy:
......@@ -12749,7 +12673,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
1274912673 case IrInstructionIdTruncate:
1275012674 case IrInstructionIdIntType:
1275112675 case IrInstructionIdBoolNot:
12752 case IrInstructionIdAlloca:
1275312676 case IrInstructionIdSlice:
1275412677 case IrInstructionIdMemberCount:
1275512678 case IrInstructionIdAlignOf:
src/ir_print.cpp-11
......@@ -601,14 +601,6 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)
601601 fprintf(irp->f, ")");
602602}
603603
604static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) {
605 fprintf(irp->f, "@alloca(");
606 ir_print_other_instruction(irp, instruction->type_value);
607 fprintf(irp->f, ", ");
608 ir_print_other_instruction(irp, instruction->count);
609 fprintf(irp->f, ")");
610}
611
612604static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
613605 fprintf(irp->f, "@intType(");
614606 ir_print_other_instruction(irp, instruction->is_signed);
......@@ -1049,9 +1041,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
10491041 case IrInstructionIdTruncate:
10501042 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
10511043 break;
1052 case IrInstructionIdAlloca:
1053 ir_print_alloca(irp, (IrInstructionAlloca *)instruction);
1054 break;
10551044 case IrInstructionIdIntType:
10561045 ir_print_int_type(irp, (IrInstructionIntType *)instruction);
10571046 break;
std/build.zig+3-1
......@@ -40,6 +40,8 @@ pub const Builder = struct {
4040 }
4141
4242 pub fn make(self: &Builder, cli_args: []const []const u8) -> %void {
43 var env_map = %return os.getEnvMap(self.allocator);
44
4345 var verbose = false;
4446 for (cli_args) |arg| {
4547 if (mem.eql(u8, arg, "--verbose")) {
......@@ -93,7 +95,7 @@ pub const Builder = struct {
9395 }
9496
9597 printInvocation(self.zig_exe, zig_args);
96 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), os.environ,
98 var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), env_map,
9799 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
98100 const term = %return child.wait();
99101 switch (term) {
std/hash_map.zig+12-7
......@@ -29,7 +29,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
2929 };
3030
3131 pub const Iterator = struct {
32 hm: &Self,
32 hm: &const Self,
3333 // how many items have we returned
3434 count: usize,
3535 // iterator through the entry array
......@@ -99,17 +99,21 @@ pub fn HashMap(comptime K: type, comptime V: type,
9999 }
100100
101101 pub fn get(hm: &Self, key: K) -> ?&Entry {
102 if (hm.entries.len == 0) {
103 return null;
104 }
102105 return hm.internalGet(key);
103106 }
104107
105 pub fn remove(hm: &Self, key: K) {
108 pub fn remove(hm: &Self, key: K) -> ?&Entry {
106109 hm.incrementModificationCount();
107110 const start_index = hm.keyToIndex(key);
108111 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {
109112 const index = (start_index + roll_over) % hm.entries.len;
110113 var entry = &hm.entries[index];
111114
112 assert(entry.used); // key not found
115 if (!entry.used)
116 return null;
113117
114118 if (!eql(entry.key, key)) continue;
115119
......@@ -119,7 +123,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
119123 if (!next_entry.used or next_entry.distance_from_start_index == 0) {
120124 entry.used = false;
121125 hm.size -= 1;
122 return;
126 return entry;
123127 }
124128 *entry = *next_entry;
125129 entry.distance_from_start_index -= 1;
......@@ -127,10 +131,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
127131 }
128132 unreachable // shifting everything in the table
129133 }}
130 unreachable // key not found
134 return null;
131135 }
132136
133 pub fn entryIterator(hm: &Self) -> Iterator {
137 pub fn entryIterator(hm: &const Self) -> Iterator {
134138 return Iterator {
135139 .hm = hm,
136140 .count = 0,
......@@ -231,7 +235,8 @@ test "basicHashMapTest" {
231235 %%map.put(5, 55);
232236
233237 assert((??map.get(2)).value == 22);
234 map.remove(2);
238 _ = map.remove(2);
239 assert(map.remove(2) == null);
235240 assert(if (const entry ?= map.get(2)) false else true);
236241}
237242
std/os/index.zig+135-23
......@@ -21,6 +21,8 @@ const mem = @import("../mem.zig");
2121const Allocator = mem.Allocator;
2222
2323const io = @import("../io.zig");
24const HashMap = @import("../hash_map.zig").HashMap;
25const cstr = @import("../cstr.zig");
2426
2527error Unexpected;
2628error SysResources;
......@@ -284,12 +286,12 @@ pub const ChildProcess = struct {
284286 Close,
285287 };
286288
287 pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
289 pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap,
288290 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
289291 {
290292 switch (@compileVar("os")) {
291293 Os.linux, Os.macosx, Os.ios, Os.darwin => {
292 return spawnPosix(exe_path, args, env, stdin, stdout, stderr, allocator);
294 return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator);
293295 },
294296 else => @compileError("Unsupported OS"),
295297 }
......@@ -351,7 +353,7 @@ pub const ChildProcess = struct {
351353 };
352354 }
353355
354 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const EnvPair,
356 fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap,
355357 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
356358 {
357359 // TODO issue #295
......@@ -408,7 +410,7 @@ pub const ChildProcess = struct {
408410 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
409411 |err| forkChildErrReport(err_pipe[1], err);
410412
411 const err = posix.getErrno(%return execve(exe_path, args, env, allocator));
413 const err = posix.getErrno(%return execve(exe_path, args, env_map, allocator));
412414 assert(err > 0);
413415 forkChildErrReport(err_pipe[1], switch (err) {
414416 errno.EFAULT => unreachable,
......@@ -473,7 +475,7 @@ pub const ChildProcess = struct {
473475/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
474476/// pointers after the args and after the environment variables.
475477/// Also make the first arg equal to path.
476fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, allocator: &Allocator) -> %usize {
478fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize {
477479 const path_buf = %return allocator.alloc(u8, path.len + 1);
478480 defer allocator.free(path_buf);
479481 @memcpy(&path_buf[0], &path[0], path.len);
......@@ -505,39 +507,149 @@ fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, all
505507 }
506508 argv_buf[argv.len + 1] = null;
507509
508 const envp_buf = %return allocator.alloc(?&const u8, envp.len + 1);
510 const envp_count = env_map.count();
511 const envp_buf = %return allocator.alloc(?&const u8, envp_count + 1);
509512 mem.set(?&const u8, envp_buf, null);
510513 defer {
511514 for (envp_buf) |env, i| {
512 const env_buf = if (const ptr ?= env) ptr[0...envp[i].key.len + envp[i].value.len + 2] else break;
515 const env_buf = if (const ptr ?= env) ptr[0...cstr.len(ptr)] else break;
513516 allocator.free(env_buf);
514517 }
515518 allocator.free(envp_buf);
516519 }
517 for (envp) |pair, i| {
518 const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);
519 @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);
520 env_buf[pair.key.len] = '=';
521 @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);
522 env_buf[env_buf.len - 1] = 0;
523
524 envp_buf[i] = env_buf.ptr;
520 {
521 var it = env_map.iterator();
522 var i: usize = 0;
523 while (true; i += 1) {
524 const pair = it.next() ?? break;
525
526 const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);
527 @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);
528 env_buf[pair.key.len] = '=';
529 @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);
530 env_buf[env_buf.len - 1] = 0;
531
532 envp_buf[i] = env_buf.ptr;
533 }
534 assert(i == envp_count);
525535 }
526 envp_buf[envp.len] = null;
536 envp_buf[envp_count] = null;
527537
528538 return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
529539}
530540
531pub const EnvPair = struct {
532 key: []const u8,
533 value: []const u8,
541pub var environ_raw: []&u8 = undefined;
542
543pub const EnvMap = struct {
544 hash_map: EnvHashMap,
545
546 const EnvHashMap = HashMap([]const u8, []const u8, hash_slice_u8, eql_slice_u8);
547
548 pub fn init(allocator: &Allocator) -> EnvMap {
549 var self = EnvMap {
550 .hash_map = undefined,
551 };
552 self.hash_map.init(allocator);
553 return self;
554 }
555
556 pub fn deinit(self: &EnvMap) {
557 var it = self.hash_map.entryIterator();
558 while (true) {
559 const entry = it.next() ?? break;
560 self.free(entry.key);
561 self.free(entry.value);
562 }
563
564 self.hash_map.deinit();
565 }
566
567 pub fn set(self: &EnvMap, key: []const u8, value: []const u8) -> %void {
568 if (const entry ?= self.hash_map.get(key)) {
569 const value_copy = %return self.copy(value);
570 %defer self.free(value_copy);
571 %return self.hash_map.put(key, value_copy);
572 self.free(entry.value);
573 } else {
574 const key_copy = %return self.copy(key);
575 %defer self.free(key_copy);
576 const value_copy = %return self.copy(value);
577 %defer self.free(value_copy);
578 %return self.hash_map.put(key_copy, value_copy);
579 }
580 }
581
582 pub fn delete(self: &EnvMap, key: []const u8) {
583 const entry = self.hash_map.remove(key) ?? return;
584 self.free(entry.key);
585 self.free(entry.value);
586 }
587
588 pub fn count(self: &const EnvMap) -> usize {
589 return self.hash_map.size;
590 }
591
592 pub fn iterator(self: &const EnvMap) -> EnvHashMap.Iterator {
593 return self.hash_map.entryIterator();
594 }
595
596 fn free(self: &EnvMap, value: []const u8) {
597 // remove the const
598 const mut_value = @ptrcast(&u8, value.ptr)[0...value.len];
599 self.hash_map.allocator.free(mut_value);
600 }
601
602 fn copy(self: &EnvMap, value: []const u8) -> %[]const u8 {
603 const result = %return self.hash_map.allocator.alloc(u8, value.len);
604 mem.copy(u8, result, value);
605 return result;
606 }
534607};
535pub var environ: []const EnvPair = undefined;
608
609pub fn getEnvMap(allocator: &Allocator) -> %EnvMap {
610 var result = EnvMap.init(allocator);
611 %defer result.deinit();
612
613 for (environ_raw) |ptr| {
614 var line_i: usize = 0;
615 while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {}
616 const key = ptr[0...line_i];
617
618 var end_i: usize = line_i;
619 while (ptr[end_i] != 0; end_i += 1) {}
620 const value = ptr[line_i + 1...end_i];
621
622 %return result.set(key, value);
623 }
624 return result;
625}
536626
537627pub fn getEnv(key: []const u8) -> ?[]const u8 {
538 for (environ) |pair| {
539 if (mem.eql(u8, pair.key, key))
540 return pair.value;
628 for (environ_raw) |ptr| {
629 var line_i: usize = 0;
630 while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {}
631 const this_key = ptr[0...line_i];
632 if (!mem.eql(u8, key, this_key))
633 continue;
634
635 var end_i: usize = line_i;
636 while (ptr[end_i] != 0; end_i += 1) {}
637 const this_value = ptr[line_i + 1...end_i];
638
639 return this_value;
541640 }
542641 return null;
543642}
643
644fn hash_slice_u8(k: []const u8) -> u32 {
645 // FNV 32-bit hash
646 var h: u32 = 2166136261;
647 for (k) |b| {
648 h = (h ^ b) *% 16777619;
649 }
650 return h;
651}
652
653fn eql_slice_u8(a: []const u8, b: []const u8) -> bool {
654 return mem.eql(u8, a, b);
655}
std/special/bootstrap.zig+17-35
......@@ -9,8 +9,7 @@ const want_start_symbol = !want_main_symbol;
99
1010const exit = std.os.posix.exit;
1111
12var argc: usize = undefined;
13var argv: &&u8 = undefined;
12var argc_ptr: &usize = undefined;
1413
1514export nakedcc fn _start() -> noreturn {
1615 @setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
......@@ -20,21 +19,28 @@ export nakedcc fn _start() -> noreturn {
2019
2120 switch (@compileVar("arch")) {
2221 Arch.x86_64 => {
23 argc = asm("mov %[argc], [rsp]": [argc] "=r" (-> usize));
24 argv = asm("lea %[argv], [rsp + 8h]": [argv] "=r" (-> &&u8));
22 argc_ptr = asm("lea %[argc], [rsp]": [argc] "=r" (-> &usize));
2523 },
2624 Arch.i386 => {
27 argc = asm("mov %[argc], [esp]": [argc] "=r" (-> usize));
28 argv = asm("lea %[argv], [esp + 4h]": [argv] "=r" (-> &&u8));
25 argc_ptr = asm("lea %[argc], [esp]": [argc] "=r" (-> &usize));
2926 },
3027 else => @compileError("unsupported arch"),
3128 }
3229 callMainAndExit()
3330}
3431
35fn callMain(envp: &?&u8) -> %void {
36 // TODO issue #225
37 const args = @alloca([]u8, argc);
32fn callMainAndExit() -> noreturn {
33 const argc = *argc_ptr;
34 const argv = @ptrcast(&&u8, &argc_ptr[1]);
35 const envp = @ptrcast(&?&u8, &argv[argc + 1]);
36 callMain(argc, argv, envp) %% exit(1);
37 exit(0);
38}
39
40var args_data: [32][]u8 = undefined;
41fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void {
42 // TODO create args API to make it work with > 32 args
43 const args = args_data[0...argc];
3844 for (args) |_, i| {
3945 const ptr = argv[i];
4046 args[i] = ptr[0...std.cstr.len(ptr)];
......@@ -42,41 +48,17 @@ fn callMain(envp: &?&u8) -> %void {
4248
4349 var env_count: usize = 0;
4450 while (envp[env_count] != null; env_count += 1) {}
45 // TODO issue #225
46 const environ = @alloca(std.os.EnvPair, env_count);
47 for (environ) |_, env_i| {
48 const ptr = ??envp[env_i];
49
50 var line_i: usize = 0;
51 while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {}
52
53 var end_i: usize = line_i;
54 while (ptr[end_i] != 0; end_i += 1) {}
55
56 environ[env_i] = std.os.EnvPair {
57 .key = ptr[0...line_i],
58 .value = ptr[line_i + 1...end_i],
59 };
60 }
61 std.os.environ = environ;
51 std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count];
6252
6353 return root.main(args);
6454}
6555
66fn callMainAndExit() -> noreturn {
67 const envp = @ptrcast(&?&u8, &argv[argc + 1]);
68 callMain(envp) %% exit(1);
69 exit(0);
70}
71
7256export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
7357 @setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
7458 if (!want_main_symbol) {
7559 unreachable;
7660 }
7761
78 argc = usize(c_argc);
79 argv = c_argv;
80 callMain(c_envp) %% return 1;
62 callMain(usize(c_argc), c_argv, c_envp) %% return 1;
8163 return 0;
8264}
test/cases/const_slice_child.zig+3-2
......@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;
1const debug = @import("std").debug;
2const assert = debug.assert;
23
34var argv: &const &const u8 = undefined;
45
......@@ -20,7 +21,7 @@ fn foo(args: [][]const u8) {
2021}
2122
2223fn bar(argc: usize) {
23 const args = @alloca([]u8, argc);
24 const args = %%debug.global_allocator.alloc([]u8, argc);
2425 for (args) |_, i| {
2526 const ptr = argv[i];
2627 args[i] = ptr[0...strlen(ptr)];