authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-18 19:40:26-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-12-18 19:40:26-05:00
loga71fbe49cbbf068e00300533d5f3874efadb8c18
tree57c6c4150b910efce96251b14003d46f00cf6afa
parentf12fbce0f51d58b429afd8a359aeb8a3b27a4eb0

IR: add FnProto instruction


12 files changed, 416 insertions(+), 300 deletions(-)

CMakeLists.txt+1-1
...@@ -52,11 +52,11 @@ set(ZIG_SOURCES...@@ -52,11 +52,11 @@ set(ZIG_SOURCES
52 "${CMAKE_SOURCE_DIR}/src/link.cpp"52 "${CMAKE_SOURCE_DIR}/src/link.cpp"
53 "${CMAKE_SOURCE_DIR}/src/main.cpp"53 "${CMAKE_SOURCE_DIR}/src/main.cpp"
54 "${CMAKE_SOURCE_DIR}/src/os.cpp"54 "${CMAKE_SOURCE_DIR}/src/os.cpp"
55 "${CMAKE_SOURCE_DIR}/src/parseh.cpp"
56 "${CMAKE_SOURCE_DIR}/src/parser.cpp"55 "${CMAKE_SOURCE_DIR}/src/parser.cpp"
57 "${CMAKE_SOURCE_DIR}/src/target.cpp"56 "${CMAKE_SOURCE_DIR}/src/target.cpp"
58 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"57 "${CMAKE_SOURCE_DIR}/src/tokenizer.cpp"
59 "${CMAKE_SOURCE_DIR}/src/util.cpp"58 "${CMAKE_SOURCE_DIR}/src/util.cpp"
59 "${CMAKE_SOURCE_DIR}/src/parseh.cpp"
60 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"60 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
61)61)
6262
src/all_types.hpp+8
...@@ -1448,6 +1448,7 @@ enum IrInstructionId {...@@ -1448,6 +1448,7 @@ enum IrInstructionId {
1448 IrInstructionIdUnwrapErrPayload,1448 IrInstructionIdUnwrapErrPayload,
1449 IrInstructionIdErrWrapCode,1449 IrInstructionIdErrWrapCode,
1450 IrInstructionIdErrWrapPayload,1450 IrInstructionIdErrWrapPayload,
1451 IrInstructionIdFnProto,
1451};1452};
14521453
1453struct IrInstruction {1454struct IrInstruction {
...@@ -2060,6 +2061,13 @@ struct IrInstructionErrWrapCode {...@@ -2060,6 +2061,13 @@ struct IrInstructionErrWrapCode {
2060 LLVMValueRef tmp_ptr;2061 LLVMValueRef tmp_ptr;
2061};2062};
20622063
2064struct IrInstructionFnProto {
2065 IrInstruction base;
2066
2067 IrInstruction **param_types;
2068 IrInstruction *return_type;
2069};
2070
2063enum LValPurpose {2071enum LValPurpose {
2064 LValPurposeNone,2072 LValPurposeNone,
2065 LValPurposeAssign,2073 LValPurposeAssign,
src/codegen.cpp+1
...@@ -2196,6 +2196,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,...@@ -2196,6 +2196,7 @@ static LLVMValueRef ir_render_instruction(CodeGen *g, IrExecutable *executable,
2196 case IrInstructionIdIntType:2196 case IrInstructionIdIntType:
2197 case IrInstructionIdMemberCount:2197 case IrInstructionIdMemberCount:
2198 case IrInstructionIdAlignOf:2198 case IrInstructionIdAlignOf:
2199 case IrInstructionIdFnProto:
2199 zig_unreachable();2200 zig_unreachable();
2200 case IrInstructionIdReturn:2201 case IrInstructionIdReturn:
2201 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);2202 return ir_render_return(g, executable, (IrInstructionReturn *)instruction);
src/ir.cpp+85-1
...@@ -439,6 +439,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapCode *) {...@@ -439,6 +439,10 @@ static constexpr IrInstructionId ir_instruction_id(IrInstructionErrWrapCode *) {
439 return IrInstructionIdErrWrapCode;439 return IrInstructionIdErrWrapCode;
440}440}
441441
442static constexpr IrInstructionId ir_instruction_id(IrInstructionFnProto *) {
443 return IrInstructionIdFnProto;
444}
445
442template<typename T>446template<typename T>
443static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {447static T *ir_create_instruction(IrExecutable *exec, Scope *scope, AstNode *source_node) {
444 T *special_instruction = allocate<T>(1);448 T *special_instruction = allocate<T>(1);
...@@ -1826,6 +1830,22 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc...@@ -1826,6 +1830,22 @@ static IrInstruction *ir_build_unwrap_err_payload_from(IrBuilder *irb, IrInstruc
1826 return new_instruction;1830 return new_instruction;
1827}1831}
18281832
1833static IrInstruction *ir_build_fn_proto(IrBuilder *irb, Scope *scope, AstNode *source_node,
1834 IrInstruction **param_types, IrInstruction *return_type)
1835{
1836 IrInstructionFnProto *instruction = ir_build_instruction<IrInstructionFnProto>(irb, scope, source_node);
1837 instruction->param_types = param_types;
1838 instruction->return_type = return_type;
1839
1840 assert(source_node->type == NodeTypeFnProto);
1841 for (size_t i = 0; i < source_node->data.fn_proto.params.length; i += 1) {
1842 ir_ref_instruction(param_types[i]);
1843 }
1844 ir_ref_instruction(return_type);
1845
1846 return &instruction->base;
1847}
1848
1829static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {1849static void ir_count_defers(IrBuilder *irb, Scope *inner_scope, Scope *outer_scope, size_t *results) {
1830 results[ReturnKindUnconditional] = 0;1850 results[ReturnKindUnconditional] = 0;
1831 results[ReturnKindError] = 0;1851 results[ReturnKindError] = 0;
...@@ -3894,6 +3914,28 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,...@@ -3894,6 +3914,28 @@ static IrInstruction *ir_gen_container_decl(IrBuilder *irb, Scope *parent_scope,
3894 return ir_build_const_type(irb, parent_scope, node, container_type);3914 return ir_build_const_type(irb, parent_scope, node, container_type);
3895}3915}
38963916
3917static IrInstruction *ir_gen_fn_proto(IrBuilder *irb, Scope *parent_scope, AstNode *node) {
3918 assert(node->type == NodeTypeFnProto);
3919
3920 size_t param_count = node->data.fn_proto.params.length;
3921 IrInstruction **param_types = allocate<IrInstruction*>(param_count);
3922
3923 for (size_t i = 0; i < param_count; i += 1) {
3924 AstNode *param_node = node->data.fn_proto.params.at(i);
3925 AstNode *type_node = param_node->data.param_decl.type;
3926 IrInstruction *type_value = ir_gen_node(irb, type_node, parent_scope);
3927 if (type_value == irb->codegen->invalid_instruction)
3928 return irb->codegen->invalid_instruction;
3929 param_types[i] = type_value;
3930 }
3931
3932 IrInstruction *return_type = ir_gen_node(irb, node->data.fn_proto.return_type, parent_scope);
3933 if (return_type == irb->codegen->invalid_instruction)
3934 return irb->codegen->invalid_instruction;
3935
3936 return ir_build_fn_proto(irb, parent_scope, node, param_types, return_type);
3937}
3938
3897static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,3939static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scope,
3898 LValPurpose lval)3940 LValPurpose lval)
3899{3941{
...@@ -3978,11 +4020,15 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop...@@ -3978,11 +4020,15 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
3978 case NodeTypeContainerDecl:4020 case NodeTypeContainerDecl:
3979 return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);4021 return ir_lval_wrap(irb, scope, ir_gen_container_decl(irb, scope, node), lval);
3980 case NodeTypeFnProto:4022 case NodeTypeFnProto:
4023 return ir_lval_wrap(irb, scope, ir_gen_fn_proto(irb, scope, node), lval);
3981 case NodeTypeFnDef:4024 case NodeTypeFnDef:
4025 zig_panic("TODO IR gen NodeTypeFnDef");
3982 case NodeTypeFnDecl:4026 case NodeTypeFnDecl:
4027 zig_panic("TODO IR gen NodeTypeFnDecl");
3983 case NodeTypeErrorValueDecl:4028 case NodeTypeErrorValueDecl:
4029 zig_panic("TODO IR gen NodeTypeErrorValueDecl");
3984 case NodeTypeTypeDecl:4030 case NodeTypeTypeDecl:
3985 zig_panic("TODO more IR gen for node types");4031 zig_panic("TODO IR gen NodeTypeTypeDecl");
3986 case NodeTypeZeroesLiteral:4032 case NodeTypeZeroesLiteral:
3987 zig_panic("TODO zeroes is deprecated");4033 zig_panic("TODO zeroes is deprecated");
3988 }4034 }
...@@ -9377,6 +9423,41 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,...@@ -9377,6 +9423,41 @@ static TypeTableEntry *ir_analyze_instruction_unwrap_err_payload(IrAnalyze *ira,
93779423
9378}9424}
93799425
9426static TypeTableEntry *ir_analyze_instruction_fn_proto(IrAnalyze *ira, IrInstructionFnProto *instruction) {
9427 AstNode *proto_node = instruction->base.source_node;
9428 assert(proto_node->type == NodeTypeFnProto);
9429
9430 FnTypeId fn_type_id = {0};
9431 init_fn_type_id(&fn_type_id, proto_node);
9432
9433 bool depends_on_compile_var = false;
9434
9435 for (; fn_type_id.next_param_index < fn_type_id.param_count; fn_type_id.next_param_index += 1) {
9436 AstNode *param_node = proto_node->data.fn_proto.params.at(fn_type_id.next_param_index);
9437 assert(param_node->type == NodeTypeParamDecl);
9438
9439 IrInstruction *param_type_value = instruction->param_types[fn_type_id.next_param_index]->other;
9440
9441 FnTypeParamInfo *param_info = &fn_type_id.param_info[fn_type_id.next_param_index];
9442 param_info->is_noalias = param_node->data.param_decl.is_noalias;
9443 param_info->type = ir_resolve_type(ira, param_type_value);
9444 if (param_info->type->id == TypeTableEntryIdInvalid)
9445 return ira->codegen->builtin_types.entry_invalid;
9446
9447 depends_on_compile_var = depends_on_compile_var || param_type_value->static_value.depends_on_compile_var;
9448 }
9449
9450 IrInstruction *return_type_value = instruction->return_type->other;
9451 fn_type_id.return_type = ir_resolve_type(ira, return_type_value);
9452 if (fn_type_id.return_type->id == TypeTableEntryIdInvalid)
9453 return ira->codegen->builtin_types.entry_invalid;
9454 depends_on_compile_var = depends_on_compile_var || return_type_value->static_value.depends_on_compile_var;
9455
9456 ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base, depends_on_compile_var);
9457 out_val->data.x_type = get_fn_type(ira->codegen, &fn_type_id);
9458 return ira->codegen->builtin_types.entry_type;
9459}
9460
9380static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {9461static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstruction *instruction) {
9381 switch (instruction->id) {9462 switch (instruction->id) {
9382 case IrInstructionIdInvalid:9463 case IrInstructionIdInvalid:
...@@ -9517,6 +9598,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi...@@ -9517,6 +9598,8 @@ static TypeTableEntry *ir_analyze_instruction_nocast(IrAnalyze *ira, IrInstructi
9517 return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction);9598 return ir_analyze_instruction_unwrap_err_code(ira, (IrInstructionUnwrapErrCode *)instruction);
9518 case IrInstructionIdUnwrapErrPayload:9599 case IrInstructionIdUnwrapErrPayload:
9519 return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction);9600 return ir_analyze_instruction_unwrap_err_payload(ira, (IrInstructionUnwrapErrPayload *)instruction);
9601 case IrInstructionIdFnProto:
9602 return ir_analyze_instruction_fn_proto(ira, (IrInstructionFnProto *)instruction);
9520 case IrInstructionIdMaybeWrap:9603 case IrInstructionIdMaybeWrap:
9521 case IrInstructionIdErrWrapCode:9604 case IrInstructionIdErrWrapCode:
9522 case IrInstructionIdErrWrapPayload:9605 case IrInstructionIdErrWrapPayload:
...@@ -9677,6 +9760,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {...@@ -9677,6 +9760,7 @@ bool ir_has_side_effects(IrInstruction *instruction) {
9677 case IrInstructionIdMaybeWrap:9760 case IrInstructionIdMaybeWrap:
9678 case IrInstructionIdErrWrapCode:9761 case IrInstructionIdErrWrapCode:
9679 case IrInstructionIdErrWrapPayload:9762 case IrInstructionIdErrWrapPayload:
9763 case IrInstructionIdFnProto:
9680 return false;9764 return false;
9681 case IrInstructionIdAsm:9765 case IrInstructionIdAsm:
9682 {9766 {
src/ir_print.cpp+14
...@@ -882,6 +882,17 @@ static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload...@@ -882,6 +882,17 @@ static void ir_print_err_wrap_payload(IrPrint *irp, IrInstructionErrWrapPayload
882 fprintf(irp->f, ")");882 fprintf(irp->f, ")");
883}883}
884884
885static void ir_print_fn_proto(IrPrint *irp, IrInstructionFnProto *instruction) {
886 fprintf(irp->f, "fn(");
887 for (size_t i = 0; i < instruction->base.source_node->data.fn_proto.params.length; i += 1) {
888 if (i != 0)
889 fprintf(irp->f, ",");
890 ir_print_other_instruction(irp, instruction->param_types[i]);
891 }
892 fprintf(irp->f, ")->");
893 ir_print_other_instruction(irp, instruction->return_type);
894}
895
885static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {896static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
886 ir_print_prefix(irp, instruction);897 ir_print_prefix(irp, instruction);
887 switch (instruction->id) {898 switch (instruction->id) {
...@@ -1112,6 +1123,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {...@@ -1112,6 +1123,9 @@ static void ir_print_instruction(IrPrint *irp, IrInstruction *instruction) {
1112 case IrInstructionIdErrWrapPayload:1123 case IrInstructionIdErrWrapPayload:
1113 ir_print_err_wrap_payload(irp, (IrInstructionErrWrapPayload *)instruction);1124 ir_print_err_wrap_payload(irp, (IrInstructionErrWrapPayload *)instruction);
1114 break;1125 break;
1126 case IrInstructionIdFnProto:
1127 ir_print_fn_proto(irp, (IrInstructionFnProto *)instruction);
1128 break;
1115 }1129 }
1116 fprintf(irp->f, "\n");1130 fprintf(irp->f, "\n");
1117}1131}
std/debug.zig+18-18
...@@ -69,7 +69,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {...@@ -69,7 +69,7 @@ pub fn writeStackTrace(out_stream: &io.OutStream) -> %void {
69 }69 }
70}70}
7171
72struct ElfStackTrace {72const ElfStackTrace = struct {
73 self_exe_stream: io.InStream,73 self_exe_stream: io.InStream,
74 elf: elf.Elf,74 elf: elf.Elf,
75 debug_info: &elf.SectionHeader,75 debug_info: &elf.SectionHeader,
...@@ -77,36 +77,36 @@ struct ElfStackTrace {...@@ -77,36 +77,36 @@ struct ElfStackTrace {
77 debug_str: &elf.SectionHeader,77 debug_str: &elf.SectionHeader,
78 abbrev_table_list: List(AbbrevTableHeader),78 abbrev_table_list: List(AbbrevTableHeader),
79 compile_unit_list: List(CompileUnit),79 compile_unit_list: List(CompileUnit),
80}80};
8181
82struct CompileUnit {82const CompileUnit = struct {
83 is_64: bool,83 is_64: bool,
84 die: &Die,84 die: &Die,
85 pc_start: u64,85 pc_start: u64,
86 pc_end: u64,86 pc_end: u64,
87}87};
8888
89const AbbrevTable = List(AbbrevTableEntry);89const AbbrevTable = List(AbbrevTableEntry);
9090
91struct AbbrevTableHeader {91const AbbrevTableHeader = struct {
92 // offset from .debug_abbrev92 // offset from .debug_abbrev
93 offset: u64,93 offset: u64,
94 table: AbbrevTable,94 table: AbbrevTable,
95}95};
9696
97struct AbbrevTableEntry {97const AbbrevTableEntry = struct {
98 has_children: bool,98 has_children: bool,
99 abbrev_code: u64,99 abbrev_code: u64,
100 tag_id: u64,100 tag_id: u64,
101 attrs: List(AbbrevAttr),101 attrs: List(AbbrevAttr),
102}102};
103103
104struct AbbrevAttr {104const AbbrevAttr = struct {
105 attr_id: u64,105 attr_id: u64,
106 form_id: u64,106 form_id: u64,
107}107};
108108
109enum FormValue {109const FormValue = enum {
110 Address: u64,110 Address: u64,
111 Block: []u8,111 Block: []u8,
112 Const: Constant,112 Const: Constant,
...@@ -118,9 +118,9 @@ enum FormValue {...@@ -118,9 +118,9 @@ enum FormValue {
118 RefSig8: u64,118 RefSig8: u64,
119 String: []u8,119 String: []u8,
120 StrPtr: u64,120 StrPtr: u64,
121}121};
122122
123struct Constant {123const Constant = struct {
124 payload: []u8,124 payload: []u8,
125 signed: bool,125 signed: bool,
126126
...@@ -131,17 +131,17 @@ struct Constant {...@@ -131,17 +131,17 @@ struct Constant {
131 return error.InvalidDebugInfo;131 return error.InvalidDebugInfo;
132 return mem.sliceAsInt(self.payload, false, u64);132 return mem.sliceAsInt(self.payload, false, u64);
133 }133 }
134}134};
135135
136struct Die {136const Die = struct {
137 tag_id: u64,137 tag_id: u64,
138 has_children: bool,138 has_children: bool,
139 attrs: List(Attr),139 attrs: List(Attr),
140140
141 struct Attr {141 const Attr = struct {
142 id: u64,142 id: u64,
143 value: FormValue,143 value: FormValue,
144 }144 };
145145
146 fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {146 fn getAttr(self: &const Die, id: u64) -> ?&const FormValue {
147 for (self.attrs.toSlice()) |*attr| {147 for (self.attrs.toSlice()) |*attr| {
...@@ -175,7 +175,7 @@ struct Die {...@@ -175,7 +175,7 @@ struct Die {
175 else => error.InvalidDebugInfo,175 else => error.InvalidDebugInfo,
176 }176 }
177 }177 }
178}178};
179179
180fn readString(in_stream: &io.InStream) -> %[]u8 {180fn readString(in_stream: &io.InStream) -> %[]u8 {
181 var buf = List(u8).init(&global_allocator);181 var buf = List(u8).init(&global_allocator);
std/elf.zig+8-8
...@@ -30,14 +30,14 @@ pub const SHT_HIPROC = 0x7fffffff;...@@ -30,14 +30,14 @@ pub const SHT_HIPROC = 0x7fffffff;
30pub const SHT_LOUSER = 0x80000000;30pub const SHT_LOUSER = 0x80000000;
31pub const SHT_HIUSER = 0xffffffff;31pub const SHT_HIUSER = 0xffffffff;
3232
33pub enum FileType {33pub const FileType = enum {
34 Relocatable,34 Relocatable,
35 Executable,35 Executable,
36 Shared,36 Shared,
37 Core,37 Core,
38}38};
3939
40pub enum Arch {40pub const Arch = enum {
41 Sparc,41 Sparc,
42 x86,42 x86,
43 Mips,43 Mips,
...@@ -47,9 +47,9 @@ pub enum Arch {...@@ -47,9 +47,9 @@ pub enum Arch {
47 IA_64,47 IA_64,
48 x86_64,48 x86_64,
49 AArch64,49 AArch64,
50}50};
5151
52pub struct SectionHeader {52pub const SectionHeader = struct {
53 name: u32,53 name: u32,
54 sh_type: u32,54 sh_type: u32,
55 flags: u64,55 flags: u64,
...@@ -60,9 +60,9 @@ pub struct SectionHeader {...@@ -60,9 +60,9 @@ pub struct SectionHeader {
60 info: u32,60 info: u32,
61 addr_align: u64,61 addr_align: u64,
62 ent_size: u64,62 ent_size: u64,
63}63};
6464
65pub struct Elf {65pub const Elf = struct {
66 in_stream: &io.InStream,66 in_stream: &io.InStream,
67 auto_close_stream: bool,67 auto_close_stream: bool,
68 is_64: bool,68 is_64: bool,
...@@ -258,4 +258,4 @@ pub struct Elf {...@@ -258,4 +258,4 @@ pub struct Elf {
258 pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void {258 pub fn seekToSection(elf: &Elf, section: &SectionHeader) -> %void {
259 %return elf.in_stream.seekTo(section.offset);259 %return elf.in_stream.seekTo(section.offset);
260 }260 }
261}261};
std/hash_map.zig+190-185
...@@ -13,220 +13,225 @@ pub fn HashMap(inline K: type, inline V: type, inline hash: fn(key: K)->u32,...@@ -13,220 +13,225 @@ pub fn HashMap(inline K: type, inline V: type, inline hash: fn(key: K)->u32,
13 SmallHashMap(K, V, hash, eql, @sizeOf(usize))13 SmallHashMap(K, V, hash, eql, @sizeOf(usize))
14}14}
1515
16pub struct SmallHashMap(K: type, V: type, hash: fn(key: K)->u32, eql: fn(a: K, b: K)->bool, static_size: usize) {16pub fn SmallHashMap(inline K: type, inline V: type,
17 entries: []Entry,17 inline hash: fn(key: K)->u32, inline eql: fn(a: K, b: K)->bool,
18 size: usize,18 inline static_size: usize) -> type
19 max_distance_from_start_index: usize,19{
20 allocator: &Allocator,20 struct {
21 // if the hash map is small enough, we use linear search through these21 entries: []Entry,
22 // entries instead of allocating memory22 size: usize,
23 prealloc_entries: [static_size]Entry,23 max_distance_from_start_index: usize,
24 // this is used to detect bugs where a hashtable is edited while an iterator is running.24 allocator: &Allocator,
25 modification_count: debug_u32,25 // if the hash map is small enough, we use linear search through these
2626 // entries instead of allocating memory
27 const Self = this;27 prealloc_entries: [static_size]Entry,
2828 // this is used to detect bugs where a hashtable is edited while an iterator is running.
29 pub struct Entry {29 modification_count: debug_u32,
30 used: bool,30
31 distance_from_start_index: usize,31 const Self = this;
32 key: K,32
33 value: V,33 pub const Entry = struct {
34 }34 used: bool,
3535 distance_from_start_index: usize,
36 pub struct Iterator {36 key: K,
37 hm: &Self,37 value: V,
38 // how many items have we returned38 };
39 count: usize,
40 // iterator through the entry array
41 index: usize,
42 // used to detect concurrent modification
43 initial_modification_count: debug_u32,
4439
45 pub fn next(it: &Iterator) -> ?&Entry {40 pub const Iterator = struct {
46 if (want_modification_safety) {41 hm: &Self,
47 assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification42 // how many items have we returned
48 }43 count: usize,
49 if (it.count >= it.hm.size) return null;44 // iterator through the entry array
50 while (it.index < it.hm.entries.len; it.index += 1) {45 index: usize,
51 const entry = &it.hm.entries[it.index];46 // used to detect concurrent modification
52 if (entry.used) {47 initial_modification_count: debug_u32,
53 it.index += 1;48
54 it.count += 1;49 pub fn next(it: &Iterator) -> ?&Entry {
55 return entry;50 if (want_modification_safety) {
51 assert(it.initial_modification_count == it.hm.modification_count); // concurrent modification
56 }52 }
53 if (it.count >= it.hm.size) return null;
54 while (it.index < it.hm.entries.len; it.index += 1) {
55 const entry = &it.hm.entries[it.index];
56 if (entry.used) {
57 it.index += 1;
58 it.count += 1;
59 return entry;
60 }
61 }
62 @unreachable() // no next item
57 }63 }
58 @unreachable() // no next item64 };
59 }
60 }
61
62 pub fn init(hm: &Self, allocator: &Allocator) {
63 hm.entries = hm.prealloc_entries[0...];
64 hm.allocator = allocator;
65 hm.size = 0;
66 hm.max_distance_from_start_index = 0;
67 hm.prealloc_entries = zeroes; // sets used to false for all entries
68 hm.modification_count = zeroes;
69 }
7065
71 pub fn deinit(hm: &Self) {66 pub fn init(hm: &Self, allocator: &Allocator) {
72 if (hm.entries.ptr != &hm.prealloc_entries[0]) {67 hm.entries = hm.prealloc_entries[0...];
73 hm.allocator.free(Entry, hm.entries);68 hm.allocator = allocator;
69 hm.size = 0;
70 hm.max_distance_from_start_index = 0;
71 hm.prealloc_entries = zeroes; // sets used to false for all entries
72 hm.modification_count = zeroes;
74 }73 }
75 }
7674
77 pub fn clear(hm: &Self) {75 pub fn deinit(hm: &Self) {
78 for (hm.entries) |*entry| {76 if (hm.entries.ptr != &hm.prealloc_entries[0]) {
79 entry.used = false;77 hm.allocator.free(Entry, hm.entries);
78 }
80 }79 }
81 hm.size = 0;
82 hm.max_distance_from_start_index = 0;
83 hm.incrementModificationCount();
84 }
85
86 pub fn put(hm: &Self, key: K, value: V) -> %void {
87 hm.incrementModificationCount();
8880
89 const resize = if (hm.entries.ptr == &hm.prealloc_entries[0]) {81 pub fn clear(hm: &Self) {
90 // preallocated entries table is full82 for (hm.entries) |*entry| {
91 hm.size == hm.entries.len83 entry.used = false;
92 } else {
93 // if we get too full (60%), double the capacity
94 hm.size * 5 >= hm.entries.len * 3
95 };
96 if (resize) {
97 const old_entries = hm.entries;
98 %return hm.initCapacity(hm.entries.len * 2);
99 // dump all of the old elements into the new table
100 for (old_entries) |*old_entry| {
101 if (old_entry.used) {
102 hm.internalPut(old_entry.key, old_entry.value);
103 }
104 }
105 if (old_entries.ptr != &hm.prealloc_entries[0]) {
106 hm.allocator.free(Entry, old_entries);
107 }84 }
85 hm.size = 0;
86 hm.max_distance_from_start_index = 0;
87 hm.incrementModificationCount();
108 }88 }
10989
110 hm.internalPut(key, value);90 pub fn put(hm: &Self, key: K, value: V) -> %void {
111 }91 hm.incrementModificationCount();
112
113 pub fn get(hm: &Self, key: K) -> ?&Entry {
114 return hm.internalGet(key);
115 }
11692
117 pub fn remove(hm: &Self, key: K) {93 const resize = if (hm.entries.ptr == &hm.prealloc_entries[0]) {
118 hm.incrementModificationCount();94 // preallocated entries table is full
119 const start_index = hm.keyToIndex(key);95 hm.size == hm.entries.len
120 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {96 } else {
121 const index = (start_index + roll_over) % hm.entries.len;97 // if we get too full (60%), double the capacity
122 var entry = &hm.entries[index];98 hm.size * 5 >= hm.entries.len * 3
99 };
100 if (resize) {
101 const old_entries = hm.entries;
102 %return hm.initCapacity(hm.entries.len * 2);
103 // dump all of the old elements into the new table
104 for (old_entries) |*old_entry| {
105 if (old_entry.used) {
106 hm.internalPut(old_entry.key, old_entry.value);
107 }
108 }
109 if (old_entries.ptr != &hm.prealloc_entries[0]) {
110 hm.allocator.free(Entry, old_entries);
111 }
112 }
123113
124 assert(entry.used); // key not found114 hm.internalPut(key, value);
115 }
125116
126 if (!eql(entry.key, key)) continue;117 pub fn get(hm: &Self, key: K) -> ?&Entry {
118 return hm.internalGet(key);
119 }
127120
128 while (roll_over < hm.entries.len; roll_over += 1) {121 pub fn remove(hm: &Self, key: K) {
129 const next_index = (start_index + roll_over + 1) % hm.entries.len;122 hm.incrementModificationCount();
130 const next_entry = &hm.entries[next_index];123 const start_index = hm.keyToIndex(key);
131 if (!next_entry.used || next_entry.distance_from_start_index == 0) {124 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {
132 entry.used = false;125 const index = (start_index + roll_over) % hm.entries.len;
133 hm.size -= 1;126 var entry = &hm.entries[index];
134 return;127
128 assert(entry.used); // key not found
129
130 if (!eql(entry.key, key)) continue;
131
132 while (roll_over < hm.entries.len; roll_over += 1) {
133 const next_index = (start_index + roll_over + 1) % hm.entries.len;
134 const next_entry = &hm.entries[next_index];
135 if (!next_entry.used || next_entry.distance_from_start_index == 0) {
136 entry.used = false;
137 hm.size -= 1;
138 return;
139 }
140 *entry = *next_entry;
141 entry.distance_from_start_index -= 1;
142 entry = next_entry;
135 }143 }
136 *entry = *next_entry;144 @unreachable() // shifting everything in the table
137 entry.distance_from_start_index -= 1;145 }}
138 entry = next_entry;146 @unreachable() // key not found
139 }147 }
140 @unreachable() // shifting everything in the table
141 }}
142 @unreachable() // key not found
143 }
144148
145 pub fn entryIterator(hm: &Self) -> Iterator {149 pub fn entryIterator(hm: &Self) -> Iterator {
146 return Iterator {150 return Iterator {
147 .hm = hm,151 .hm = hm,
148 .count = 0,152 .count = 0,
149 .index = 0,153 .index = 0,
150 .initial_modification_count = hm.modification_count,154 .initial_modification_count = hm.modification_count,
151 };155 };
152 }156 }
153157
154 fn initCapacity(hm: &Self, capacity: usize) -> %void {158 fn initCapacity(hm: &Self, capacity: usize) -> %void {
155 hm.entries = %return hm.allocator.alloc(Entry, capacity);159 hm.entries = %return hm.allocator.alloc(Entry, capacity);
156 hm.size = 0;160 hm.size = 0;
157 hm.max_distance_from_start_index = 0;161 hm.max_distance_from_start_index = 0;
158 for (hm.entries) |*entry| {162 for (hm.entries) |*entry| {
159 entry.used = false;163 entry.used = false;
164 }
160 }165 }
161 }
162166
163 fn incrementModificationCount(hm: &Self) {167 fn incrementModificationCount(hm: &Self) {
164 if (want_modification_safety) {168 if (want_modification_safety) {
165 hm.modification_count +%= 1;169 hm.modification_count +%= 1;
170 }
166 }171 }
167 }
168172
169 fn internalPut(hm: &Self, orig_key: K, orig_value: V) {173 fn internalPut(hm: &Self, orig_key: K, orig_value: V) {
170 var key = orig_key;174 var key = orig_key;
171 var value = orig_value;175 var value = orig_value;
172 const start_index = hm.keyToIndex(key);176 const start_index = hm.keyToIndex(key);
173 var roll_over: usize = 0;177 var roll_over: usize = 0;
174 var distance_from_start_index: usize = 0;178 var distance_from_start_index: usize = 0;
175 while (roll_over < hm.entries.len; {roll_over += 1; distance_from_start_index += 1}) {179 while (roll_over < hm.entries.len; {roll_over += 1; distance_from_start_index += 1}) {
176 const index = (start_index + roll_over) % hm.entries.len;180 const index = (start_index + roll_over) % hm.entries.len;
177 const entry = &hm.entries[index];181 const entry = &hm.entries[index];
178182
179 if (entry.used && !eql(entry.key, key)) {183 if (entry.used && !eql(entry.key, key)) {
180 if (entry.distance_from_start_index < distance_from_start_index) {184 if (entry.distance_from_start_index < distance_from_start_index) {
181 // robin hood to the rescue185 // robin hood to the rescue
182 const tmp = *entry;186 const tmp = *entry;
183 hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,187 hm.max_distance_from_start_index = math.max(hm.max_distance_from_start_index,
184 distance_from_start_index);188 distance_from_start_index);
185 *entry = Entry {189 *entry = Entry {
186 .used = true,190 .used = true,
187 .distance_from_start_index = distance_from_start_index,191 .distance_from_start_index = distance_from_start_index,
188 .key = key,192 .key = key,
189 .value = value,193 .value = value,
190 };194 };
191 key = tmp.key;195 key = tmp.key;
192 value = tmp.value;196 value = tmp.value;
193 distance_from_start_index = tmp.distance_from_start_index;197 distance_from_start_index = tmp.distance_from_start_index;
198 }
199 continue;
194 }200 }
195 continue;
196 }
197201
198 if (!entry.used) {202 if (!entry.used) {
199 // adding an entry. otherwise overwriting old value with203 // adding an entry. otherwise overwriting old value with
200 // same key204 // same key
201 hm.size += 1;205 hm.size += 1;
202 }206 }
203207
204 hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);208 hm.max_distance_from_start_index = math.max(distance_from_start_index, hm.max_distance_from_start_index);
205 *entry = Entry {209 *entry = Entry {
206 .used = true,210 .used = true,
207 .distance_from_start_index = distance_from_start_index,211 .distance_from_start_index = distance_from_start_index,
208 .key = key,212 .key = key,
209 .value = value,213 .value = value,
210 };214 };
211 return;215 return;
216 }
217 @unreachable() // put into a full map
212 }218 }
213 @unreachable() // put into a full map
214 }
215219
216 fn internalGet(hm: &Self, key: K) -> ?&Entry {220 fn internalGet(hm: &Self, key: K) -> ?&Entry {
217 const start_index = hm.keyToIndex(key);221 const start_index = hm.keyToIndex(key);
218 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {222 {var roll_over: usize = 0; while (roll_over <= hm.max_distance_from_start_index; roll_over += 1) {
219 const index = (start_index + roll_over) % hm.entries.len;223 const index = (start_index + roll_over) % hm.entries.len;
220 const entry = &hm.entries[index];224 const entry = &hm.entries[index];
221225
222 if (!entry.used) return null;226 if (!entry.used) return null;
223 if (eql(entry.key, key)) return entry;227 if (eql(entry.key, key)) return entry;
224 }}228 }}
225 return null;229 return null;
226 }230 }
227231
228 fn keyToIndex(hm: &Self, key: K) -> usize {232 fn keyToIndex(hm: &Self, key: K) -> usize {
229 return usize(hash(key)) % hm.entries.len;233 return usize(hash(key)) % hm.entries.len;
234 }
230 }235 }
231}236}
232237
std/list.zig+36-34
...@@ -3,49 +3,51 @@ const assert = debug.assert;...@@ -3,49 +3,51 @@ const assert = debug.assert;
3const mem = @import("mem.zig");3const mem = @import("mem.zig");
4const Allocator = mem.Allocator;4const Allocator = mem.Allocator;
55
6pub struct List(T: type) {6pub fn List(inline T: type) -> type{
7 const Self = this;7 struct {
8 const Self = this;
89
9 items: []T,10 items: []T,
10 len: usize,11 len: usize,
11 allocator: &Allocator,12 allocator: &Allocator,
1213
13 pub fn init(allocator: &Allocator) -> Self {14 pub fn init(allocator: &Allocator) -> Self {
14 Self {15 Self {
15 .items = zeroes,16 .items = zeroes,
16 .len = 0,17 .len = 0,
17 .allocator = allocator,18 .allocator = allocator,
19 }
18 }20 }
19 }
2021
21 pub fn deinit(l: &Self) {22 pub fn deinit(l: &Self) {
22 l.allocator.free(T, l.items);23 l.allocator.free(T, l.items);
23 }24 }
2425
25 pub fn toSlice(l: &Self) -> []T {26 pub fn toSlice(l: &Self) -> []T {
26 return l.items[0...l.len];27 return l.items[0...l.len];
27 }28 }
2829
29 pub fn append(l: &Self, item: T) -> %void {30 pub fn append(l: &Self, item: T) -> %void {
30 const new_length = l.len + 1;31 const new_length = l.len + 1;
31 %return l.ensureCapacity(new_length);32 %return l.ensureCapacity(new_length);
32 l.items[l.len] = item;33 l.items[l.len] = item;
33 l.len = new_length;34 l.len = new_length;
34 }35 }
3536
36 pub fn resize(l: &Self, new_len: usize) -> %void {37 pub fn resize(l: &Self, new_len: usize) -> %void {
37 %return l.ensureCapacity(new_len);38 %return l.ensureCapacity(new_len);
38 l.len = new_len;39 l.len = new_len;
39 }40 }
4041
41 pub fn ensureCapacity(l: &Self, new_capacity: usize) -> %void {42 pub fn ensureCapacity(l: &Self, new_capacity: usize) -> %void {
42 var better_capacity = l.items.len;43 var better_capacity = l.items.len;
43 if (better_capacity >= new_capacity) return;44 if (better_capacity >= new_capacity) return;
44 while (true) {45 while (true) {
45 better_capacity += better_capacity / 2 + 8;46 better_capacity += better_capacity / 2 + 8;
46 if (better_capacity >= new_capacity) break;47 if (better_capacity >= new_capacity) break;
48 }
49 l.items = %return l.allocator.realloc(T, l.items, better_capacity);
47 }50 }
48 l.items = %return l.allocator.realloc(T, l.items, better_capacity);
49 }51 }
50}52}
5153
std/mem.zig+2-2
...@@ -8,7 +8,7 @@ pub const Cmp = math.Cmp;...@@ -8,7 +8,7 @@ pub const Cmp = math.Cmp;
8pub error NoMem;8pub error NoMem;
99
10pub type Context = u8;10pub type Context = u8;
11pub struct Allocator {11pub const Allocator = struct {
12 allocFn: fn (self: &Allocator, n: usize) -> %[]u8,12 allocFn: fn (self: &Allocator, n: usize) -> %[]u8,
13 reallocFn: fn (self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8,13 reallocFn: fn (self: &Allocator, old_mem: []u8, new_size: usize) -> %[]u8,
14 freeFn: fn (self: &Allocator, mem: []u8),14 freeFn: fn (self: &Allocator, mem: []u8),
...@@ -39,7 +39,7 @@ pub struct Allocator {...@@ -39,7 +39,7 @@ pub struct Allocator {
39 fn free(self: &Allocator, inline T: type, mem: []T) {39 fn free(self: &Allocator, inline T: type, mem: []T) {
40 self.freeFn(self, ([]u8)(mem));40 self.freeFn(self, ([]u8)(mem));
41 }41 }
42}42};
4343
44/// Copy all of source into dest at position 0.44/// Copy all of source into dest at position 0.
45/// dest.len must be >= source.len.45/// dest.len must be >= source.len.
std/net.zig+4-4
...@@ -13,7 +13,7 @@ pub error NoMem;...@@ -13,7 +13,7 @@ pub error NoMem;
13pub error NotSocket;13pub error NotSocket;
14pub error BadFd;14pub error BadFd;
1515
16struct Connection {16const Connection = struct {
17 socket_fd: i32,17 socket_fd: i32,
1818
19 pub fn send(c: Connection, buf: []const u8) -> %usize {19 pub fn send(c: Connection, buf: []const u8) -> %usize {
...@@ -56,14 +56,14 @@ struct Connection {...@@ -56,14 +56,14 @@ struct Connection {
56 else => return error.Unexpected,56 else => return error.Unexpected,
57 }57 }
58 }58 }
59}59};
6060
61struct Address {61const Address = struct {
62 family: u16,62 family: u16,
63 scope_id: u32,63 scope_id: u32,
64 addr: [16]u8,64 addr: [16]u8,
65 sort_key: i32,65 sort_key: i32,
66}66};
6767
68pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {68pub fn lookup(hostname: []const u8, out_addrs: []Address) -> %[]Address {
69 if (hostname.len == 0) {69 if (hostname.len == 0) {
std/rand.zig+49-47
...@@ -18,7 +18,7 @@ pub const MT19937_64 = MersenneTwister(...@@ -18,7 +18,7 @@ pub const MT19937_64 = MersenneTwister(
18 43, 6364136223846793005);18 43, 6364136223846793005);
1919
20/// Use `init` to initialize this state.20/// Use `init` to initialize this state.
21pub struct Rand {21pub const Rand = struct {
22 const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32;22 const Rng = if (@sizeOf(usize) >= 8) MT19937_64 else MT19937_32;
2323
24 rng: Rng,24 rng: Rng,
...@@ -91,65 +91,67 @@ pub struct Rand {...@@ -91,65 +91,67 @@ pub struct Rand {
91 };91 };
92 return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision);92 return T(r.rangeUnsigned(int_type, 0, precision)) / T(precision);
93 }93 }
94}94};
9595
96struct MersenneTwister(96fn MersenneTwister(
97 int: type, n: usize, m: usize, r: int,97 inline int: type, inline n: usize, inline m: usize, inline r: int,
98 a: int,98 inline a: int,
99 u: int, d: int,99 inline u: int, inline d: int,
100 s: int, b: int,100 inline s: int, inline b: int,
101 t: int, c: int,101 inline t: int, inline c: int,
102 l: int, f: int)102 inline l: int, inline f: int) -> type
103{103{
104 const Self = this;104 struct {
105 const Self = this;
105106
106 array: [n]int,107 array: [n]int,
107 index: usize,108 index: usize,
108109
109 pub fn init(mt: &Self, seed: int) {110 pub fn init(mt: &Self, seed: int) {
110 mt.index = n;111 mt.index = n;
111112
112 var prev_value = seed;113 var prev_value = seed;
113 mt.array[0] = prev_value;114 mt.array[0] = prev_value;
114 {var i: usize = 1; while (i < n; i += 1) {115 {var i: usize = 1; while (i < n; i += 1) {
115 prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));116 prev_value = int(i) +% f *% (prev_value ^ (prev_value >> (int.bit_count - 2)));
116 mt.array[i] = prev_value;117 mt.array[i] = prev_value;
117 }};118 }};
118 }119 }
119120
120 pub fn get(mt: &Self) -> int {121 pub fn get(mt: &Self) -> int {
121 const mag01 = []int{0, a};122 const mag01 = []int{0, a};
122 const LM: int = (1 << r) - 1;123 const LM: int = (1 << r) - 1;
123 const UM = ~LM;124 const UM = ~LM;
124125
125 if (mt.index >= n) {126 if (mt.index >= n) {
126 var i: usize = 0;127 var i: usize = 0;
127128
128 while (i < n - m; i += 1) {129 while (i < n - m; i += 1) {
129 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);130 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
130 mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[x & 0x1];131 mt.array[i] = mt.array[i + m] ^ (x >> 1) ^ mag01[x & 0x1];
131 }132 }
132133
133 while (i < n - 1; i += 1) {134 while (i < n - 1; i += 1) {
134 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);135 const x = (mt.array[i] & UM) | (mt.array[i + 1] & LM);
135 mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[x & 0x1];136 mt.array[i] = mt.array[i + m - n] ^ (x >> 1) ^ mag01[x & 0x1];
136137
137 }138 }
138 const x = (mt.array[i] & UM) | (mt.array[0] & LM);139 const x = (mt.array[i] & UM) | (mt.array[0] & LM);
139 mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[x & 0x1];140 mt.array[i] = mt.array[m - 1] ^ (x >> 1) ^ mag01[x & 0x1];
140141
141 mt.index = 0;142 mt.index = 0;
142 }143 }
143144
144 var x = mt.array[mt.index];145 var x = mt.array[mt.index];
145 mt.index += 1;146 mt.index += 1;
146147
147 x ^= ((x >> u) & d);148 x ^= ((x >> u) & d);
148 x ^= ((x <<% s) & b);149 x ^= ((x <<% s) & b);
149 x ^= ((x <<% t) & c);150 x ^= ((x <<% t) & c);
150 x ^= (x >> l);151 x ^= (x >> l);
151152
152 return x;153 return x;
154 }
153 }155 }
154}156}
155157