diff --git a/doc/langref.md b/doc/langref.md index 8388d321d8..9a06672c6d 100644 --- a/doc/langref.md +++ b/doc/langref.md @@ -295,19 +295,6 @@ has a terminating null byte. Built-in functions are prefixed with `@`. Remember that the `comptime` keyword on a parameter means that the parameter must be known at compile time. -### @alloca(comptime T: type, count: usize) -> []T - -Allocates memory in the stack frame of the caller. This temporary space is -automatically freed when the function that called alloca returns to its caller, -just like other stack variables. - -When using this function to allocate memory, you should know the upper bound -of `count`. Consider putting a constant array on the stack with the upper bound -instead of using alloca. If you do use alloca it is to save a few bytes off -the memory size given that you didn't actually hit your upper bound. - -The allocated memory contents are undefined. - ### @typeOf(expression) -> type This function returns a compile-time constant, which is the type of the diff --git a/src/all_types.hpp b/src/all_types.hpp index da05a32d11..c92ab364c5 100644 --- a/src/all_types.hpp +++ b/src/all_types.hpp @@ -1190,7 +1190,6 @@ enum BuiltinFnId { BuiltinFnIdTruncate, BuiltinFnIdIntType, BuiltinFnIdSetDebugSafety, - BuiltinFnIdAlloca, BuiltinFnIdTypeName, BuiltinFnIdIsInteger, BuiltinFnIdIsFloat, @@ -1706,7 +1705,6 @@ enum IrInstructionId { IrInstructionIdTruncate, IrInstructionIdIntType, IrInstructionIdBoolNot, - IrInstructionIdAlloca, IrInstructionIdMemset, IrInstructionIdMemcpy, IrInstructionIdSlice, @@ -2234,14 +2232,6 @@ struct IrInstructionBoolNot { IrInstruction *value; }; -struct IrInstructionAlloca { - IrInstruction base; - - IrInstruction *type_value; - IrInstruction *count; - LLVMValueRef tmp_ptr; -}; - struct IrInstructionMemset { IrInstruction base; diff --git a/src/codegen.cpp b/src/codegen.cpp index 4a26b538c9..5e803795f1 100644 --- a/src/codegen.cpp +++ b/src/codegen.cpp @@ -2190,26 +2190,6 @@ static LLVMValueRef ir_render_truncate(CodeGen *g, IrExecutable *executable, IrI } } -static LLVMValueRef ir_render_alloca(CodeGen *g, IrExecutable *executable, IrInstructionAlloca *instruction) { - TypeTableEntry *slice_type = get_underlying_type(instruction->base.value.type); - TypeTableEntry *ptr_type = slice_type->data.structure.fields[slice_ptr_index].type_entry; - TypeTableEntry *child_type = ptr_type->data.pointer.child_type; - LLVMValueRef size_val = ir_llvm_value(g, instruction->count); - LLVMValueRef ptr_val = LLVMBuildArrayAlloca(g->builder, child_type->type_ref, size_val, ""); - - // TODO in debug mode, initialize all the bytes to 0xaa - - // store the freshly allocated pointer in the slice - LLVMValueRef ptr_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_ptr_index, ""); - LLVMBuildStore(g->builder, ptr_val, ptr_field_ptr); - - // store the size in the len field - LLVMValueRef len_field_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, slice_len_index, ""); - LLVMBuildStore(g->builder, size_val, len_field_ptr); - - return instruction->tmp_ptr; -} - static LLVMValueRef ir_render_memset(CodeGen *g, IrExecutable *executable, IrInstructionMemset *instruction) { LLVMValueRef dest_ptr = ir_llvm_value(g, instruction->dest_ptr); LLVMValueRef char_val = ir_llvm_value(g, instruction->byte); @@ -2548,7 +2528,7 @@ static LLVMValueRef ir_render_maybe_wrap(CodeGen *g, IrExecutable *executable, I assert(instruction->tmp_ptr); LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_child_index, ""); - assert(child_type == instruction->value->value.type); + // child_type and instruction->value->value.type may differ by constness gen_assign_raw(g, val_ptr, payload_val, child_type); LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, instruction->tmp_ptr, maybe_null_index, ""); LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr); @@ -2796,8 +2776,6 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable, return ir_render_truncate(g, executable, (IrInstructionTruncate *)instruction); case IrInstructionIdBoolNot: return ir_render_bool_not(g, executable, (IrInstructionBoolNot *)instruction); - case IrInstructionIdAlloca: - return ir_render_alloca(g, executable, (IrInstructionAlloca *)instruction); case IrInstructionIdMemset: return ir_render_memset(g, executable, (IrInstructionMemset *)instruction); case IrInstructionIdMemcpy: @@ -3648,9 +3626,6 @@ static void do_code_gen(CodeGen *g) { } else if (instruction->id == IrInstructionIdCall) { IrInstructionCall *call_instruction = (IrInstructionCall *)instruction; slot = &call_instruction->tmp_ptr; - } else if (instruction->id == IrInstructionIdAlloca) { - IrInstructionAlloca *alloca_instruction = (IrInstructionAlloca *)instruction; - slot = &alloca_instruction->tmp_ptr; } else if (instruction->id == IrInstructionIdSlice) { IrInstructionSlice *slice_instruction = (IrInstructionSlice *)instruction; slot = &slice_instruction->tmp_ptr; @@ -4326,7 +4301,6 @@ static void define_builtin_fns(CodeGen *g) { create_builtin_fn(g, BuiltinFnIdCompileLog, "compileLog", SIZE_MAX); create_builtin_fn(g, BuiltinFnIdIntType, "intType", 2); create_builtin_fn(g, BuiltinFnIdSetDebugSafety, "setDebugSafety", 2); - create_builtin_fn(g, BuiltinFnIdAlloca, "alloca", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalAlign, "setGlobalAlign", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalSection, "setGlobalSection", 2); create_builtin_fn(g, BuiltinFnIdSetGlobalLinkage, "setGlobalLinkage", 2); diff --git a/src/ir.cpp b/src/ir.cpp index a33fb3cd22..4f3f756d49 100644 --- a/src/ir.cpp +++ b/src/ir.cpp @@ -404,10 +404,6 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionBoolNot *) { return IrInstructionIdBoolNot; } -static constexpr IrInstructionId ir_instruction_id(IrInstructionAlloca *) { - return IrInstructionIdAlloca; -} - static constexpr IrInstructionId ir_instruction_id(IrInstructionMemset *) { return IrInstructionIdMemset; } @@ -1668,27 +1664,6 @@ static IrInstruction *ir_build_bool_not_from(IrBuilder *irb, IrInstruction *old_ return new_instruction; } -static IrInstruction *ir_build_alloca(IrBuilder *irb, Scope *scope, AstNode *source_node, - IrInstruction *type_value, IrInstruction *count) -{ - IrInstructionAlloca *instruction = ir_build_instruction(irb, scope, source_node); - instruction->type_value = type_value; - instruction->count = count; - - ir_ref_instruction(type_value, irb->current_basic_block); - ir_ref_instruction(count, irb->current_basic_block); - - return &instruction->base; -} - -static IrInstruction *ir_build_alloca_from(IrBuilder *irb, IrInstruction *old_instruction, - IrInstruction *type_value, IrInstruction *count) -{ - IrInstruction *new_instruction = ir_build_alloca(irb, old_instruction->scope, old_instruction->source_node, type_value, count); - ir_link_new_instruction(new_instruction, old_instruction); - return new_instruction; -} - static IrInstruction *ir_build_memset(IrBuilder *irb, Scope *scope, AstNode *source_node, IrInstruction *dest_ptr, IrInstruction *byte, IrInstruction *count) { @@ -2567,14 +2542,6 @@ static IrInstruction *ir_instruction_boolnot_get_dep(IrInstructionBoolNot *instr } } -static IrInstruction *ir_instruction_alloca_get_dep(IrInstructionAlloca *instruction, size_t index) { - switch (index) { - case 0: return instruction->type_value; - case 1: return instruction->count; - default: return nullptr; - } -} - static IrInstruction *ir_instruction_memset_get_dep(IrInstructionMemset *instruction, size_t index) { switch (index) { case 0: return instruction->dest_ptr; @@ -2938,8 +2905,6 @@ static IrInstruction *ir_instruction_get_dep(IrInstruction *instruction, size_t return ir_instruction_inttype_get_dep((IrInstructionIntType *) instruction, index); case IrInstructionIdBoolNot: return ir_instruction_boolnot_get_dep((IrInstructionBoolNot *) instruction, index); - case IrInstructionIdAlloca: - return ir_instruction_alloca_get_dep((IrInstructionAlloca *) instruction, index); case IrInstructionIdMemset: return ir_instruction_memset_get_dep((IrInstructionMemset *) instruction, index); case IrInstructionIdMemcpy: @@ -4100,20 +4065,6 @@ static IrInstruction *ir_gen_builtin_fn_call(IrBuilder *irb, Scope *scope, AstNo return ir_build_int_type(irb, scope, node, arg0_value, arg1_value); } - case BuiltinFnIdAlloca: - { - AstNode *arg0_node = node->data.fn_call_expr.params.at(0); - IrInstruction *arg0_value = ir_gen_node(irb, arg0_node, scope); - if (arg0_value == irb->codegen->invalid_instruction) - return arg0_value; - - AstNode *arg1_node = node->data.fn_call_expr.params.at(1); - IrInstruction *arg1_value = ir_gen_node(irb, arg1_node, scope); - if (arg1_value == irb->codegen->invalid_instruction) - return arg1_value; - - return ir_build_alloca(irb, scope, node, arg0_value, arg1_value); - } case BuiltinFnIdMemcpy: { 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 return bool_type; } -static TypeTableEntry *ir_analyze_instruction_alloca(IrAnalyze *ira, IrInstructionAlloca *instruction) { - IrInstruction *type_value = instruction->type_value->other; - if (type_is_invalid(type_value->value.type)) - return ira->codegen->builtin_types.entry_invalid; - - IrInstruction *count_value = instruction->count->other; - if (type_is_invalid(count_value->value.type)) - return ira->codegen->builtin_types.entry_invalid; - - TypeTableEntry *child_type = ir_resolve_type(ira, type_value); - - if (type_requires_comptime(child_type)) { - ir_add_error(ira, type_value, - buf_sprintf("invalid alloca type '%s'", buf_ptr(&child_type->name))); - // TODO if this is a typedecl, add error note showing the declaration of the type decl - return ira->codegen->builtin_types.entry_invalid; - } else { - TypeTableEntry *slice_type = get_slice_type(ira->codegen, child_type, false); - IrInstruction *new_instruction = ir_build_alloca_from(&ira->new_irb, &instruction->base, type_value, count_value); - ir_add_alloca(ira, new_instruction, slice_type); - return slice_type; - } - zig_unreachable(); -} - static TypeTableEntry *ir_analyze_instruction_memset(IrAnalyze *ira, IrInstructionMemset *instruction) { IrInstruction *dest_ptr = instruction->dest_ptr->other; if (type_is_invalid(dest_ptr->value.type)) @@ -12550,8 +12476,6 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi return ir_analyze_instruction_int_type(ira, (IrInstructionIntType *)instruction); case IrInstructionIdBoolNot: return ir_analyze_instruction_bool_not(ira, (IrInstructionBoolNot *)instruction); - case IrInstructionIdAlloca: - return ir_analyze_instruction_alloca(ira, (IrInstructionAlloca *)instruction); case IrInstructionIdMemset: return ir_analyze_instruction_memset(ira, (IrInstructionMemset *)instruction); case IrInstructionIdMemcpy: @@ -12749,7 +12673,6 @@ bool ir_has_side_effects(IrInstruction *instruction) { case IrInstructionIdTruncate: case IrInstructionIdIntType: case IrInstructionIdBoolNot: - case IrInstructionIdAlloca: case IrInstructionIdSlice: case IrInstructionIdMemberCount: case IrInstructionIdAlignOf: diff --git a/src/ir_print.cpp b/src/ir_print.cpp index fd912d6919..1a839cd20f 100644 --- a/src/ir_print.cpp +++ b/src/ir_print.cpp @@ -601,14 +601,6 @@ static void ir_print_truncate(IrPrint *irp, IrInstructionTruncate *instruction) fprintf(irp->f, ")"); } -static void ir_print_alloca(IrPrint *irp, IrInstructionAlloca *instruction) { - fprintf(irp->f, "@alloca("); - ir_print_other_instruction(irp, instruction->type_value); - fprintf(irp->f, ", "); - ir_print_other_instruction(irp, instruction->count); - fprintf(irp->f, ")"); -} - static void ir_print_int_type(IrPrint *irp, IrInstructionIntType *instruction) { fprintf(irp->f, "@intType("); ir_print_other_instruction(irp, instruction->is_signed); @@ -1049,9 +1041,6 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) { case IrInstructionIdTruncate: ir_print_truncate(irp, (IrInstructionTruncate *)instruction); break; - case IrInstructionIdAlloca: - ir_print_alloca(irp, (IrInstructionAlloca *)instruction); - break; case IrInstructionIdIntType: ir_print_int_type(irp, (IrInstructionIntType *)instruction); break; diff --git a/std/build.zig b/std/build.zig index be07e9ebec..9ddc89797b 100644 --- a/std/build.zig +++ b/std/build.zig @@ -40,6 +40,8 @@ pub const Builder = struct { } pub fn make(self: &Builder, cli_args: []const []const u8) -> %void { + var env_map = %return os.getEnvMap(self.allocator); + var verbose = false; for (cli_args) |arg| { if (mem.eql(u8, arg, "--verbose")) { @@ -93,7 +95,7 @@ pub const Builder = struct { } printInvocation(self.zig_exe, zig_args); - var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), os.environ, + var child = %return os.ChildProcess.spawn(self.zig_exe, zig_args.toSliceConst(), env_map, StdIo.Ignore, StdIo.Inherit, StdIo.Inherit, self.allocator); const term = %return child.wait(); switch (term) { diff --git a/std/hash_map.zig b/std/hash_map.zig index f7245ba107..60f4062583 100644 --- a/std/hash_map.zig +++ b/std/hash_map.zig @@ -29,7 +29,7 @@ pub fn HashMap(comptime K: type, comptime V: type, }; pub const Iterator = struct { - hm: &Self, + hm: &const Self, // how many items have we returned count: usize, // iterator through the entry array @@ -99,17 +99,21 @@ pub fn HashMap(comptime K: type, comptime V: type, } pub fn get(hm: &Self, key: K) -> ?&Entry { + if (hm.entries.len == 0) { + return null; + } return hm.internalGet(key); } - pub fn remove(hm: &Self, key: K) { + pub fn remove(hm: &Self, key: K) -> ?&Entry { hm.incrementModificationCount(); const start_index = hm.keyToIndex(key); {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) { const index = (start_index + roll_over) % hm.entries.len; var entry = &hm.entries[index]; - assert(entry.used); // key not found + if (!entry.used) + return null; if (!eql(entry.key, key)) continue; @@ -119,7 +123,7 @@ pub fn HashMap(comptime K: type, comptime V: type, if (!next_entry.used or next_entry.distance_from_start_index == 0) { entry.used = false; hm.size -= 1; - return; + return entry; } *entry = *next_entry; entry.distance_from_start_index -= 1; @@ -127,10 +131,10 @@ pub fn HashMap(comptime K: type, comptime V: type, } unreachable // shifting everything in the table }} - unreachable // key not found + return null; } - pub fn entryIterator(hm: &Self) -> Iterator { + pub fn entryIterator(hm: &const Self) -> Iterator { return Iterator { .hm = hm, .count = 0, @@ -231,7 +235,8 @@ test "basicHashMapTest" { %%map.put(5, 55); assert((??map.get(2)).value == 22); - map.remove(2); + _ = map.remove(2); + assert(map.remove(2) == null); assert(if (const entry ?= map.get(2)) false else true); } diff --git a/std/os/index.zig b/std/os/index.zig index ba991e958b..7e9ec2b4f0 100644 --- a/std/os/index.zig +++ b/std/os/index.zig @@ -21,6 +21,8 @@ const mem = @import("../mem.zig"); const Allocator = mem.Allocator; const io = @import("../io.zig"); +const HashMap = @import("../hash_map.zig").HashMap; +const cstr = @import("../cstr.zig"); error Unexpected; error SysResources; @@ -284,12 +286,12 @@ pub const ChildProcess = struct { Close, }; - pub fn spawn(exe_path: []const u8, args: []const []const u8, env: []const EnvPair, + pub fn spawn(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap, stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess { switch (@compileVar("os")) { Os.linux, Os.macosx, Os.ios, Os.darwin => { - return spawnPosix(exe_path, args, env, stdin, stdout, stderr, allocator); + return spawnPosix(exe_path, args, env_map, stdin, stdout, stderr, allocator); }, else => @compileError("Unsupported OS"), } @@ -351,7 +353,7 @@ pub const ChildProcess = struct { }; } - fn spawnPosix(exe_path: []const u8, args: []const []const u8, env: []const EnvPair, + fn spawnPosix(exe_path: []const u8, args: []const []const u8, env_map: &const EnvMap, stdin: StdIo, stdout: StdIo, stderr: StdIo, allocator: &Allocator) -> %ChildProcess { // TODO issue #295 @@ -408,7 +410,7 @@ pub const ChildProcess = struct { setUpChildIo(stderr, stderr_pipe[1], posix.STDERR_FILENO, dev_null_fd) %% |err| forkChildErrReport(err_pipe[1], err); - const err = posix.getErrno(%return execve(exe_path, args, env, allocator)); + const err = posix.getErrno(%return execve(exe_path, args, env_map, allocator)); assert(err > 0); forkChildErrReport(err_pipe[1], switch (err) { errno.EFAULT => unreachable, @@ -473,7 +475,7 @@ pub const ChildProcess = struct { /// It must also convert to KEY=VALUE\0 format for environment variables, and include null /// pointers after the args and after the environment variables. /// Also make the first arg equal to path. -fn execve(path: []const u8, argv: []const []const u8, envp: []const EnvPair, allocator: &Allocator) -> %usize { +fn execve(path: []const u8, argv: []const []const u8, env_map: &const EnvMap, allocator: &Allocator) -> %usize { const path_buf = %return allocator.alloc(u8, path.len + 1); defer allocator.free(path_buf); @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 } argv_buf[argv.len + 1] = null; - const envp_buf = %return allocator.alloc(?&const u8, envp.len + 1); + const envp_count = env_map.count(); + const envp_buf = %return allocator.alloc(?&const u8, envp_count + 1); mem.set(?&const u8, envp_buf, null); defer { for (envp_buf) |env, i| { - const env_buf = if (const ptr ?= env) ptr[0...envp[i].key.len + envp[i].value.len + 2] else break; + const env_buf = if (const ptr ?= env) ptr[0...cstr.len(ptr)] else break; allocator.free(env_buf); } allocator.free(envp_buf); } - for (envp) |pair, i| { - const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2); - @memcpy(&env_buf[0], pair.key.ptr, pair.key.len); - env_buf[pair.key.len] = '='; - @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len); - env_buf[env_buf.len - 1] = 0; + { + var it = env_map.iterator(); + var i: usize = 0; + while (true; i += 1) { + const pair = it.next() ?? break; - envp_buf[i] = env_buf.ptr; + const env_buf = %return allocator.alloc(u8, pair.key.len + pair.value.len + 2); + @memcpy(&env_buf[0], pair.key.ptr, pair.key.len); + env_buf[pair.key.len] = '='; + @memcpy(&env_buf[pair.key.len + 1], pair.value.ptr, pair.value.len); + env_buf[env_buf.len - 1] = 0; + + envp_buf[i] = env_buf.ptr; + } + assert(i == envp_count); } - envp_buf[envp.len] = null; + envp_buf[envp_count] = null; return posix.execve(path_buf.ptr, argv_buf.ptr, envp_buf.ptr); } -pub const EnvPair = struct { - key: []const u8, - value: []const u8, +pub var environ_raw: []&u8 = undefined; + +pub const EnvMap = struct { + hash_map: EnvHashMap, + + const EnvHashMap = HashMap([]const u8, []const u8, hash_slice_u8, eql_slice_u8); + + pub fn init(allocator: &Allocator) -> EnvMap { + var self = EnvMap { + .hash_map = undefined, + }; + self.hash_map.init(allocator); + return self; + } + + pub fn deinit(self: &EnvMap) { + var it = self.hash_map.entryIterator(); + while (true) { + const entry = it.next() ?? break; + self.free(entry.key); + self.free(entry.value); + } + + self.hash_map.deinit(); + } + + pub fn set(self: &EnvMap, key: []const u8, value: []const u8) -> %void { + if (const entry ?= self.hash_map.get(key)) { + const value_copy = %return self.copy(value); + %defer self.free(value_copy); + %return self.hash_map.put(key, value_copy); + self.free(entry.value); + } else { + const key_copy = %return self.copy(key); + %defer self.free(key_copy); + const value_copy = %return self.copy(value); + %defer self.free(value_copy); + %return self.hash_map.put(key_copy, value_copy); + } + } + + pub fn delete(self: &EnvMap, key: []const u8) { + const entry = self.hash_map.remove(key) ?? return; + self.free(entry.key); + self.free(entry.value); + } + + pub fn count(self: &const EnvMap) -> usize { + return self.hash_map.size; + } + + pub fn iterator(self: &const EnvMap) -> EnvHashMap.Iterator { + return self.hash_map.entryIterator(); + } + + fn free(self: &EnvMap, value: []const u8) { + // remove the const + const mut_value = @ptrcast(&u8, value.ptr)[0...value.len]; + self.hash_map.allocator.free(mut_value); + } + + fn copy(self: &EnvMap, value: []const u8) -> %[]const u8 { + const result = %return self.hash_map.allocator.alloc(u8, value.len); + mem.copy(u8, result, value); + return result; + } }; -pub var environ: []const EnvPair = undefined; + +pub fn getEnvMap(allocator: &Allocator) -> %EnvMap { + var result = EnvMap.init(allocator); + %defer result.deinit(); + + for (environ_raw) |ptr| { + var line_i: usize = 0; + while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {} + const key = ptr[0...line_i]; + + var end_i: usize = line_i; + while (ptr[end_i] != 0; end_i += 1) {} + const value = ptr[line_i + 1...end_i]; + + %return result.set(key, value); + } + return result; +} pub fn getEnv(key: []const u8) -> ?[]const u8 { - for (environ) |pair| { - if (mem.eql(u8, pair.key, key)) - return pair.value; + for (environ_raw) |ptr| { + var line_i: usize = 0; + while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {} + const this_key = ptr[0...line_i]; + if (!mem.eql(u8, key, this_key)) + continue; + + var end_i: usize = line_i; + while (ptr[end_i] != 0; end_i += 1) {} + const this_value = ptr[line_i + 1...end_i]; + + return this_value; } return null; } + +fn hash_slice_u8(k: []const u8) -> u32 { + // FNV 32-bit hash + var h: u32 = 2166136261; + for (k) |b| { + h = (h ^ b) *% 16777619; + } + return h; +} + +fn eql_slice_u8(a: []const u8, b: []const u8) -> bool { + return mem.eql(u8, a, b); +} diff --git a/std/special/bootstrap.zig b/std/special/bootstrap.zig index eea04ba393..3a210987d8 100644 --- a/std/special/bootstrap.zig +++ b/std/special/bootstrap.zig @@ -9,8 +9,7 @@ const want_start_symbol = !want_main_symbol; const exit = std.os.posix.exit; -var argc: usize = undefined; -var argv: &&u8 = undefined; +var argc_ptr: &usize = undefined; export nakedcc fn _start() -> noreturn { @setGlobalLinkage(_start, if (want_start_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal); @@ -20,21 +19,28 @@ export nakedcc fn _start() -> noreturn { switch (@compileVar("arch")) { Arch.x86_64 => { - argc = asm("mov %[argc], [rsp]": [argc] "=r" (-> usize)); - argv = asm("lea %[argv], [rsp + 8h]": [argv] "=r" (-> &&u8)); + argc_ptr = asm("lea %[argc], [rsp]": [argc] "=r" (-> &usize)); }, Arch.i386 => { - argc = asm("mov %[argc], [esp]": [argc] "=r" (-> usize)); - argv = asm("lea %[argv], [esp + 4h]": [argv] "=r" (-> &&u8)); + argc_ptr = asm("lea %[argc], [esp]": [argc] "=r" (-> &usize)); }, else => @compileError("unsupported arch"), } callMainAndExit() } -fn callMain(envp: &?&u8) -> %void { - // TODO issue #225 - const args = @alloca([]u8, argc); +fn callMainAndExit() -> noreturn { + const argc = *argc_ptr; + const argv = @ptrcast(&&u8, &argc_ptr[1]); + const envp = @ptrcast(&?&u8, &argv[argc + 1]); + callMain(argc, argv, envp) %% exit(1); + exit(0); +} + +var args_data: [32][]u8 = undefined; +fn callMain(argc: usize, argv: &&u8, envp: &?&u8) -> %void { + // TODO create args API to make it work with > 32 args + const args = args_data[0...argc]; for (args) |_, i| { const ptr = argv[i]; args[i] = ptr[0...std.cstr.len(ptr)]; @@ -42,41 +48,17 @@ fn callMain(envp: &?&u8) -> %void { var env_count: usize = 0; while (envp[env_count] != null; env_count += 1) {} - // TODO issue #225 - const environ = @alloca(std.os.EnvPair, env_count); - for (environ) |_, env_i| { - const ptr = ??envp[env_i]; - - var line_i: usize = 0; - while (ptr[line_i] != 0 and ptr[line_i] != '='; line_i += 1) {} - - var end_i: usize = line_i; - while (ptr[end_i] != 0; end_i += 1) {} - - environ[env_i] = std.os.EnvPair { - .key = ptr[0...line_i], - .value = ptr[line_i + 1...end_i], - }; - } - std.os.environ = environ; + std.os.environ_raw = @ptrcast(&&u8, envp)[0...env_count]; return root.main(args); } -fn callMainAndExit() -> noreturn { - const envp = @ptrcast(&?&u8, &argv[argc + 1]); - callMain(envp) %% exit(1); - exit(0); -} - export fn main(c_argc: i32, c_argv: &&u8, c_envp: &?&u8) -> i32 { @setGlobalLinkage(main, if (want_main_symbol) GlobalLinkage.Strong else GlobalLinkage.Internal); if (!want_main_symbol) { unreachable; } - argc = usize(c_argc); - argv = c_argv; - callMain(c_envp) %% return 1; + callMain(usize(c_argc), c_argv, c_envp) %% return 1; return 0; } diff --git a/test/cases/const_slice_child.zig b/test/cases/const_slice_child.zig index 8a022307c3..aa1531edac 100644 --- a/test/cases/const_slice_child.zig +++ b/test/cases/const_slice_child.zig @@ -1,4 +1,5 @@ -const assert = @import("std").debug.assert; +const debug = @import("std").debug; +const assert = debug.assert; var argv: &const &const u8 = undefined; @@ -20,7 +21,7 @@ fn foo(args: [][]const u8) { } fn bar(argc: usize) { - const args = @alloca([]u8, argc); + const args = %%debug.global_allocator.alloc([]u8, argc); for (args) |_, i| { const ptr = argv[i]; args[i] = ptr[0...strlen(ptr)];