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....@@ -295,19 +295,6 @@ has a terminating null byte.
295Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on295Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on
296a parameter means that the parameter must be known at compile time.296a 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
311### @typeOf(expression) -> type298### @typeOf(expression) -> type
312299
313This function returns a compile-time constant, which is the type of the300This function returns a compile-time constant, which is the type of the
src/all_types.hpp-10
...@@ -1190,7 +1190,6 @@ enum BuiltinFnId {...@@ -1190,7 +1190,6 @@ enum BuiltinFnId {
1190 BuiltinFnIdTruncate,1190 BuiltinFnIdTruncate,
1191 BuiltinFnIdIntType,1191 BuiltinFnIdIntType,
1192 BuiltinFnIdSetDebugSafety,1192 BuiltinFnIdSetDebugSafety,
1193 BuiltinFnIdAlloca,
1194 BuiltinFnIdTypeName,1193 BuiltinFnIdTypeName,
1195 BuiltinFnIdIsInteger,1194 BuiltinFnIdIsInteger,
1196 BuiltinFnIdIsFloat,1195 BuiltinFnIdIsFloat,
...@@ -1706,7 +1705,6 @@ enum IrInstructionId {...@@ -1706,7 +1705,6 @@ enum IrInstructionId {
1706 IrInstructionIdTruncate,1705 IrInstructionIdTruncate,
1707 IrInstructionIdIntType,1706 IrInstructionIdIntType,
1708 IrInstructionIdBoolNot,1707 IrInstructionIdBoolNot,
1709 IrInstructionIdAlloca,
1710 IrInstructionIdMemset,1708 IrInstructionIdMemset,
1711 IrInstructionIdMemcpy,1709 IrInstructionIdMemcpy,
1712 IrInstructionIdSlice,1710 IrInstructionIdSlice,
...@@ -2234,14 +2232,6 @@ struct IrInstructionBoolNot {...@@ -2234,14 +2232,6 @@ struct IrInstructionBoolNot {
2234 IrInstruction *value;2232 IrInstruction *value;
2235};2233};
22362234
2237struct IrInstructionAlloca {
2238 IrInstruction base;
2239
2240 IrInstruction *type_value;
2241 IrInstruction *count;
2242 LLVMValueRef tmp_ptr;
2243};
2244
2245struct IrInstructionMemset {2235struct IrInstructionMemset {
2246 IrInstruction base;2236 IrInstruction base;
22472237
src/codegen.cpp+1-27
...@@ -2190,26 +2190,6 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI...@@ -2190,26 +2190,6 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI
2190 }2190 }
2191}2191}
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
2213static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) {2193static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) {
2214 LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);2194 LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr);
2215 LLVMValueRef char_val = ir_llvm_value(g, instruction->byte);2195 LLVMValueRef char_val = ir_llvm_value(g, instruction->byte);
...@@ -2548,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I...@@ -2548,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I
2548 assert(instruction->tmp_ptr);2528 assert(instruction->tmp_ptr);
25492529
2550 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, "");2530 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
2552 gen_assign_raw(g, val_ptr, payload_val, child_type);2532 gen_assign_raw(g, val_ptr, payload_val, child_type);
2553 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");2533 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, "");
2554 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);2534 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
...@@ -2796,8 +2776,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2796,8 +2776,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2796 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);2776 return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction);
2797 case IrInstructionIdBoolNot:2777 case IrInstructionIdBoolNot:
2798 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);2778 return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction);
2799 case IrInstructionIdAlloca:
2800 return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction);
2801 case IrInstructionIdMemset:2779 case IrInstructionIdMemset:
2802 return ir_render_memset(g, executable, (IrInstructionMemset *)instruction);2780 return ir_render_memset(g, executable, (IrInstructionMemset *)instruction);
2803 case IrInstructionIdMemcpy:2781 case IrInstructionIdMemcpy:
...@@ -3648,9 +3626,6 @@ static void do_code_gen(CodeGen *g) {...@@ -3648,9 +3626,6 @@ static void do_code_gen(CodeGen *g) {
3648 } else if (instruction->id == IrInstructionIdCall) {3626 } else if (instruction->id == IrInstructionIdCall) {
3649 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;3627 IrInstructionCall *call_instruction = (IrInstructionCall *)instruction;
3650 slot = &call_instruction->tmp_ptr;3628 slot = &call_instruction->tmp_ptr;
3651 } else if (instruction->id == IrInstructionIdAlloca) {
3652 IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction;
3653 slot = &alloca_instruction->tmp_ptr;
3654 } else if (instruction->id == IrInstructionIdSlice) {3629 } else if (instruction->id == IrInstructionIdSlice) {
3655 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;3630 IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction;
3656 slot = &slice_instruction->tmp_ptr;3631 slot = &slice_instruction->tmp_ptr;
...@@ -4326,7 +4301,6 @@ static void define_builtin_fns(CodeGen *g) {...@@ -4326,7 +4301,6 @@ static void define_builtin_fns(CodeGen *g) {
4326 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);4301 create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX);
4327 create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);4302 create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2);
4328 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);4303 create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2);
4329 create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2);
4330 create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);4304 create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2);
4331 create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);4305 create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2);
4332 create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);4306 create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2);
src/ir.cpp-77
...@@ -404,10 +404,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {...@@ -404,10 +404,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) {
404 return IrInstructionIdBoolNot;404 return IrInstructionIdBoolNot;
405}405}
406406
407static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) {
408 return IrInstructionIdAlloca;
409}
410
411static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) {407static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) {
412 return IrInstructionIdMemset;408 return IrInstructionIdMemset;
413}409}
...@@ -1668,27 +1664,6 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_...@@ -1668,27 +1664,6 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_
1668 return new_instruction;1664 return new_instruction;
1669}1665}
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
1692static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node,1667static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node,
1693 IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count)1668 IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count)
1694{1669{
...@@ -2567,14 +2542,6 @@ static IrInstruction *ir_instruction_boolnot_get_dep(IrInstructionBoolNot *instr...@@ -2567,14 +2542,6 @@ static IrInstruction *ir_instruction_boolnot_get_dep(IrInstructionBoolNot *instr
2567 }2542 }
2568}2543}
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
2578static IrInstruction *ir_instruction_memset_get_dep(IrInstructionMemset *instruction, size_t index) {2545static IrInstruction *ir_instruction_memset_get_dep(IrInstructionMemset *instruction, size_t index) {
2579 switch (index) {2546 switch (index) {
2580 case 0: return instruction->dest_ptr;2547 case 0: return instruction->dest_ptr;
...@@ -2938,8 +2905,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t...@@ -2938,8 +2905,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t
2938 return ir_instruction_inttype_get_dep((IrInstructionIntType *) instruction, index);2905 return ir_instruction_inttype_get_dep((IrInstructionIntType *) instruction, index);
2939 case IrInstructionIdBoolNot:2906 case IrInstructionIdBoolNot:
2940 return ir_instruction_boolnot_get_dep((IrInstructionBoolNot *) instruction, index);2907 return ir_instruction_boolnot_get_dep((IrInstructionBoolNot *) instruction, index);
2941 case IrInstructionIdAlloca:
2942 return ir_instruction_alloca_get_dep((IrInstructionAlloca *) instruction, index);
2943 case IrInstructionIdMemset:2908 case IrInstructionIdMemset:
2944 return ir_instruction_memset_get_dep((IrInstructionMemset *) instruction, index);2909 return ir_instruction_memset_get_dep((IrInstructionMemset *) instruction, index);
2945 case IrInstructionIdMemcpy:2910 case IrInstructionIdMemcpy:
...@@ -4100,20 +4065,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo...@@ -4100,20 +4065,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo
41004065
4101 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);4066 return ir_build_int_type(irb, scope, node, arg0_value, arg1_value);
4102 }4067 }
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 }
4117 case BuiltinFnIdMemcpy:4068 case BuiltinFnIdMemcpy:
4118 {4069 {
4119 AstNode *arg0_node = node->data.fn_call_expr.params.at(0);4070 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...@@ -11461,31 +11412,6 @@ static TypeTableEntry *ir_analyze_instruction_bool_not(IrAnalyze *ira, IrInstruc
11461 return bool_type;11412 return bool_type;
11462}11413}
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
11489static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {11415static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) {
11490 IrInstruction *dest_ptr = instruction->dest_ptr->other;11416 IrInstruction *dest_ptr = instruction->dest_ptr->other;
11491 if (type_is_invalid(dest_ptr->value.type))11417 if (type_is_invalid(dest_ptr->value.type))
...@@ -12550,8 +12476,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -12550,8 +12476,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
12550 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);12476 return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction);
12551 case IrInstructionIdBoolNot:12477 case IrInstructionIdBoolNot:
12552 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);12478 return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction);
12553 case IrInstructionIdAlloca:
12554 return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction);
12555 case IrInstructionIdMemset:12479 case IrInstructionIdMemset:
12556 return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction);12480 return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction);
12557 case IrInstructionIdMemcpy:12481 case IrInstructionIdMemcpy:
...@@ -12749,7 +12673,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -12749,7 +12673,6 @@ bool ir_has_side_effects(IrInstruction *instruction) {
12749 case IrInstructionIdTruncate:12673 case IrInstructionIdTruncate:
12750 case IrInstructionIdIntType:12674 case IrInstructionIdIntType:
12751 case IrInstructionIdBoolNot:12675 case IrInstructionIdBoolNot:
12752 case IrInstructionIdAlloca:
12753 case IrInstructionIdSlice:12676 case IrInstructionIdSlice:
12754 case IrInstructionIdMemberCount:12677 case IrInstructionIdMemberCount:
12755 case IrInstructionIdAlignOf:12678 case IrInstructionIdAlignOf:
src/ir_print.cpp-11
...@@ -601,14 +601,6 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)...@@ -601,14 +601,6 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction)
601 fprintf(irp->f, ")");601 fprintf(irp->f, ")");
602}602}
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
612static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {604static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) {
613 fprintf(irp->f, "@intType(");605 fprintf(irp->f, "@intType(");
614 ir_print_other_instruction(irp, instruction->is_signed);606 ir_print_other_instruction(irp, instruction->is_signed);
...@@ -1049,9 +1041,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1049,9 +1041,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1049 case IrInstructionIdTruncate:1041 case IrInstructionIdTruncate:
1050 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);1042 ir_print_truncate(irp, (IrInstructionTruncate *)instruction);
1051 break;1043 break;
1052 case IrInstructionIdAlloca:
1053 ir_print_alloca(irp, (IrInstructionAlloca *)instruction);
1054 break;
1055 case IrInstructionIdIntType:1044 case IrInstructionIdIntType:
1056 ir_print_int_type(irp, (IrInstructionIntType *)instruction);1045 ir_print_int_type(irp, (IrInstructionIntType *)instruction);
1057 break;1046 break;
std/build.zig+3-1
...@@ -40,6 +40,8 @@ pub const Builder = struct {...@@ -40,6 +40,8 @@ pub const Builder = struct {
40 }40 }
4141
42 pub fn make(self: &Builder, cli_args: []const []const u8) -> %void {42 pub fn make(self: &Builder, cli_args: []const []const u8) -> %void {
43 var env_map = %return os.getEnvMap(self.allocator);
44
43 var verbose = false;45 var verbose = false;
44 for (cli_args) |arg| {46 for (cli_args) |arg| {
45 if (mem.eql(u8, arg, "--verbose")) {47 if (mem.eql(u8, arg, "--verbose")) {
...@@ -93,7 +95,7 @@ pub const Builder = struct {...@@ -93,7 +95,7 @@ pub const Builder = struct {
93 }95 }
9496
95 printInvocation(self.zig_exe, zig_args);97 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,
97 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);99 StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator);
98 const term = %return child.wait();100 const term = %return child.wait();
99 switch (term) {101 switch (term) {
std/hash_map.zig+12-7
...@@ -29,7 +29,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -29,7 +29,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
29 };29 };
3030
31 pub const Iterator = struct {31 pub const Iterator = struct {
32 hm: &Self,32 hm: &const Self,
33 // how many items have we returned33 // how many items have we returned
34 count: usize,34 count: usize,
35 // iterator through the entry array35 // iterator through the entry array
...@@ -99,17 +99,21 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -99,17 +99,21 @@ pub fn HashMap(comptime K: type, comptime V: type,
99 }99 }
100100
101 pub fn get(hm: &Self, key: K) -> ?&Entry {101 pub fn get(hm: &Self, key: K) -> ?&Entry {
102 if (hm.entries.len == 0) {
103 return null;
104 }
102 return hm.internalGet(key);105 return hm.internalGet(key);
103 }106 }
104107
105 pub fn remove(hm: &Self, key: K) {108 pub fn remove(hm: &Self, key: K) -> ?&Entry {
106 hm.incrementModificationCount();109 hm.incrementModificationCount();
107 const start_index = hm.keyToIndex(key);110 const start_index = hm.keyToIndex(key);
108 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {111 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {
109 const index = (start_index + roll_over) % hm.entries.len;112 const index = (start_index + roll_over) % hm.entries.len;
110 var entry = &hm.entries[index];113 var entry = &hm.entries[index];
111114
112 assert(entry.used); // key not found115 if (!entry.used)
116 return null;
113117
114 if (!eql(entry.key, key)) continue;118 if (!eql(entry.key, key)) continue;
115119
...@@ -119,7 +123,7 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -119,7 +123,7 @@ pub fn HashMap(comptime K: type, comptime V: type,
119 if (!next_entry.used or next_entry.distance_from_start_index == 0) {123 if (!next_entry.used or next_entry.distance_from_start_index == 0) {
120 entry.used = false;124 entry.used = false;
121 hm.size -= 1;125 hm.size -= 1;
122 return;126 return entry;
123 }127 }
124 *entry = *next_entry;128 *entry = *next_entry;
125 entry.distance_from_start_index -= 1;129 entry.distance_from_start_index -= 1;
...@@ -127,10 +131,10 @@ pub fn HashMap(comptime K: type, comptime V: type,...@@ -127,10 +131,10 @@ pub fn HashMap(comptime K: type, comptime V: type,
127 }131 }
128 unreachable // shifting everything in the table132 unreachable // shifting everything in the table
129 }}133 }}
130 unreachable // key not found134 return null;
131 }135 }
132136
133 pub fn entryIterator(hm: &Self) -> Iterator {137 pub fn entryIterator(hm: &const Self) -> Iterator {
134 return Iterator {138 return Iterator {
135 .hm = hm,139 .hm = hm,
136 .count = 0,140 .count = 0,
...@@ -231,7 +235,8 @@ test "basicHashMapTest" {...@@ -231,7 +235,8 @@ test "basicHashMapTest" {
231 %%map.put(5, 55);235 %%map.put(5, 55);
232236
233 assert((??map.get(2)).value == 22);237 assert((??map.get(2)).value == 22);
234 map.remove(2);238 _ = map.remove(2);
239 assert(map.remove(2) == null);
235 assert(if (const entry ?= map.get(2)) false else true);240 assert(if (const entry ?= map.get(2)) false else true);
236}241}
237242
std/os/index.zig+135-23
...@@ -21,6 +21,8 @@ const mem = @import("../mem.zig");...@@ -21,6 +21,8 @@ const mem = @import("../mem.zig");
21const Allocator = mem.Allocator;21const Allocator = mem.Allocator;
2222
23const io = @import("../io.zig");23const io = @import("../io.zig");
24const HashMap = @import("../hash_map.zig").HashMap;
25const cstr = @import("../cstr.zig");
2426
25error Unexpected;27error Unexpected;
26error SysResources;28error SysResources;
...@@ -284,12 +286,12 @@ pub const ChildProcess = struct {...@@ -284,12 +286,12 @@ pub const ChildProcess = struct {
284 Close,286 Close,
285 };287 };
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,
288 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess290 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
289 {291 {
290 switch (@compileVar("os")) {292 switch (@compileVar("os")) {
291 Os.linux, Os.macosx, Os.ios, Os.darwin => {293 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);
293 },295 },
294 else => @compileError("Unsupported OS"),296 else => @compileError("Unsupported OS"),
295 }297 }
...@@ -351,7 +353,7 @@ pub const ChildProcess = struct {...@@ -351,7 +353,7 @@ pub const ChildProcess = struct {
351 };353 };
352 }354 }
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,
355 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess357 stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess
356 {358 {
357 // TODO issue #295359 // TODO issue #295
...@@ -408,7 +410,7 @@ pub const ChildProcess = struct {...@@ -408,7 +410,7 @@ pub const ChildProcess = struct {
408 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%410 setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %%
409 |err| forkChildErrReport(err_pipe[1], err);411 |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));
412 assert(err > 0);414 assert(err > 0);
413 forkChildErrReport(err_pipe[1], switch (err) {415 forkChildErrReport(err_pipe[1], switch (err) {
414 errno.EFAULT => unreachable,416 errno.EFAULT => unreachable,
...@@ -473,7 +475,7 @@ pub const ChildProcess = struct {...@@ -473,7 +475,7 @@ pub const ChildProcess = struct {
473/// It must also convert to KEY=VALUE\0 format for environment variables, and include null475/// It must also convert to KEY=VALUE\0 format for environment variables, and include null
474/// pointers after the args and after the environment variables.476/// pointers after the args and after the environment variables.
475/// Also make the first arg equal to path.477/// 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 {
477 const path_buf = %return allocator.alloc(u8, path.len + 1);479 const path_buf = %return allocator.alloc(u8, path.len + 1);
478 defer allocator.free(path_buf);480 defer allocator.free(path_buf);
479 @memcpy(&path_buf[0], &path[0], path.len);481 @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...@@ -505,39 +507,149 @@ fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, all
505 }507 }
506 argv_buf[argv.len + 1] = null;508 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);
509 mem.set(?&const u8, envp_buf, null);512 mem.set(?&const u8, envp_buf, null);
510 defer {513 defer {
511 for (envp_buf) |env, i| {514 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;
513 allocator.free(env_buf);516 allocator.free(env_buf);
514 }517 }
515 allocator.free(envp_buf);518 allocator.free(envp_buf);
516 }519 }
517 for (envp) |pair, i| {520 {
518 const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);521 var it = env_map.iterator();
519 @memcpy(&env_buf[0], pair.key.ptr, pair.key.len);522 var i: usize = 0;
520 env_buf[pair.key.len] = '=';523 while (true; i += 1) {
521 @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len);524 const pair = it.next() ?? break;
522 env_buf[env_buf.len - 1] = 0;525
523526 const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2);
524 envp_buf[i] = env_buf.ptr;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);
525 }535 }
526 envp_buf[envp.len] = null;536 envp_buf[envp_count] = null;
527537
528 return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);538 return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr);
529}539}
530540
531pub const EnvPair = struct {541pub var environ_raw: []&u8 = undefined;
532 key: []const u8,542
533 value: []const u8,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 }
534};607};
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
537pub fn getEnv(key: []const u8) -> ?[]const u8 {627pub fn getEnv(key: []const u8) -> ?[]const u8 {
538 for (environ) |pair| {628 for (environ_raw) |ptr| {
539 if (mem.eql(u8, pair.key, key))629 var line_i: usize = 0;
540 return pair.value;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;
541 }640 }
542 return null;641 return null;
543}642}
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;...@@ -9,8 +9,7 @@ const want_start_symbol = !want_main_symbol;
99
10const exit = std.os.posix.exit;10const exit = std.os.posix.exit;
1111
12var argc: usize = undefined;12var argc_ptr: &usize = undefined;
13var argv: &&u8 = undefined;
1413
15export nakedcc fn _start() -> noreturn {14export nakedcc fn _start() -> noreturn {
16 @setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);15 @setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
...@@ -20,21 +19,28 @@ export nakedcc fn _start() -> noreturn {...@@ -20,21 +19,28 @@ export nakedcc fn _start() -> noreturn {
2019
21 switch (@compileVar("arch")) {20 switch (@compileVar("arch")) {
22 Arch.x86_64 => {21 Arch.x86_64 => {
23 argc = asm("mov %[argc], [rsp]": [argc] "=r" (-> usize));22 argc_ptr = asm("lea %[argc], [rsp]": [argc] "=r" (-> &usize));
24 argv = asm("lea %[argv], [rsp + 8h]": [argv] "=r" (-> &&u8));
25 },23 },
26 Arch.i386 => {24 Arch.i386 => {
27 argc = asm("mov %[argc], [esp]": [argc] "=r" (-> usize));25 argc_ptr = asm("lea %[argc], [esp]": [argc] "=r" (-> &usize));
28 argv = asm("lea %[argv], [esp + 4h]": [argv] "=r" (-> &&u8));
29 },26 },
30 else => @compileError("unsupported arch"),27 else => @compileError("unsupported arch"),
31 }28 }
32 callMainAndExit()29 callMainAndExit()
33}30}
3431
35fn callMain(envp: &?&u8) -> %void {32fn callMainAndExit() -> noreturn {
36 // TODO issue #22533 const argc = *argc_ptr;
37 const args = @alloca([]u8, argc);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];
38 for (args) |_, i| {44 for (args) |_, i| {
39 const ptr = argv[i];45 const ptr = argv[i];
40 args[i] = ptr[0...std.cstr.len(ptr)];46 args[i] = ptr[0...std.cstr.len(ptr)];
...@@ -42,41 +48,17 @@ fn callMain(envp: &?&u8) -> %void {...@@ -42,41 +48,17 @@ fn callMain(envp: &?&u8) -> %void {
4248
43 var env_count: usize = 0;49 var env_count: usize = 0;
44 while (envp[env_count] != null; env_count += 1) {}50 while (envp[env_count] != null; env_count += 1) {}
45 // TODO issue #22551 std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count];
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;
6252
63 return root.main(args);53 return root.main(args);
64}54}
6555
66fn callMainAndExit() -> noreturn {
67 const envp = @ptrcast(&?&u8, &argv[argc + 1]);
68 callMain(envp) %% exit(1);
69 exit(0);
70}
71
72export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {56export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 {
73 @setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);57 @setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal);
74 if (!want_main_symbol) {58 if (!want_main_symbol) {
75 unreachable;59 unreachable;
76 }60 }
7761
78 argc = usize(c_argc);62 callMain(usize(c_argc), c_argv, c_envp) %% return 1;
79 argv = c_argv;
80 callMain(c_envp) %% return 1;
81 return 0;63 return 0;
82}64}
test/cases/const_slice_child.zig+3-2
...@@ -1,4 +1,5 @@...@@ -1,4 +1,5 @@
1const assert = @import("std").debug.assert;1const debug = @import("std").debug;
2const assert = debug.assert;
23
3var argv: &const &const u8 = undefined;4var argv: &const &const u8 = undefined;
45
...@@ -20,7 +21,7 @@ fn foo(args: [][]const u8) {...@@ -20,7 +21,7 @@ fn foo(args: [][]const u8) {
20}21}
2122
22fn bar(argc: usize) {23fn bar(argc: usize) {
23 const args = @alloca([]u8, argc);24 const args = %%debug.global_allocator.alloc([]u8, argc);
24 for (args) |_, i| {25 for (args) |_, i| {
25 const ptr = argv[i];26 const ptr = argv[i];
26 args[i] = ptr[0...strlen(ptr)];27 args[i] = ptr[0...strlen(ptr)];