authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-12-31 04:58:00-05:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-01-01 13:38:30-08:00
log3f2a65594e1d3c0a4f4943a4ea522e8405db81e0
treed93d69c0a60cf7d8c695f9d434b114c57005257f
parent4129996211edd30b25c23454520fd78b2a70394b

Compilation: cleanup hashmap usage


5 files changed, 105 insertions(+), 152 deletions(-)

src/Compilation.zig+80-120
......@@ -410,22 +410,15 @@ pub const CObject = struct {
410410 }
411411
412412 pub const Bundle = struct {
413 file_names: std.AutoHashMapUnmanaged(u32, []const u8) = .{},
414 category_names: std.AutoHashMapUnmanaged(u32, []const u8) = .{},
413 file_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .{},
414 category_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .{},
415415 diags: []Diag = &.{},
416416
417417 pub fn destroy(bundle: *Bundle, gpa: Allocator) void {
418 var file_name_it = bundle.file_names.valueIterator();
419 while (file_name_it.next()) |file_name| gpa.free(file_name.*);
420 bundle.file_names.deinit(gpa);
421
422 var category_name_it = bundle.category_names.valueIterator();
423 while (category_name_it.next()) |category_name| gpa.free(category_name.*);
424 bundle.category_names.deinit(gpa);
425
418 for (bundle.file_names.values()) |file_name| gpa.free(file_name);
419 for (bundle.category_names.values()) |category_name| gpa.free(category_name);
426420 for (bundle.diags) |*diag| diag.deinit(gpa);
427421 gpa.free(bundle.diags);
428
429422 gpa.destroy(bundle);
430423 }
431424
......@@ -470,17 +463,15 @@ pub const CObject = struct {
470463 var bc = BitcodeReader.init(gpa, .{ .reader = reader.any() });
471464 defer bc.deinit();
472465
473 var file_names: std.AutoHashMapUnmanaged(u32, []const u8) = .{};
466 var file_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .{};
474467 errdefer {
475 var file_name_it = file_names.valueIterator();
476 while (file_name_it.next()) |file_name| gpa.free(file_name.*);
468 for (file_names.values()) |file_name| gpa.free(file_name);
477469 file_names.deinit(gpa);
478470 }
479471
480 var category_names: std.AutoHashMapUnmanaged(u32, []const u8) = .{};
472 var category_names: std.AutoArrayHashMapUnmanaged(u32, []const u8) = .{};
481473 errdefer {
482 var category_name_it = category_names.valueIterator();
483 while (category_name_it.next()) |category_name| gpa.free(category_name.*);
474 for (category_names.values()) |category_name| gpa.free(category_name);
484475 category_names.deinit(gpa);
485476 }
486477
......@@ -1014,46 +1005,39 @@ fn addModuleTableToCacheHash(
10141005) (error{OutOfMemory} || std.os.GetCwdError)!void {
10151006 const allocator = arena.allocator();
10161007
1017 const modules = try allocator.alloc(Package.Module.Deps.KV, mod_table.count());
1018 {
1019 // Copy over the hashmap entries to our slice
1020 var table_it = mod_table.iterator();
1021 var idx: usize = 0;
1022 while (table_it.next()) |entry| : (idx += 1) {
1023 modules[idx] = .{
1024 .key = entry.key_ptr.*,
1025 .value = entry.value_ptr.*,
1026 };
1027 }
1028 }
1008 const module_indices = try allocator.alloc(u32, mod_table.count());
1009 // Copy over the hashmap entries to our slice
1010 for (module_indices, 0..) |*module_index, index| module_index.* = @intCast(index);
10291011 // Sort the slice by package name
1030 mem.sortUnstable(Package.Module.Deps.KV, modules, {}, struct {
1031 fn lessThan(_: void, lhs: Package.Module.Deps.KV, rhs: Package.Module.Deps.KV) bool {
1032 return std.mem.lessThan(u8, lhs.key, rhs.key);
1012 mem.sortUnstable(u32, module_indices, &mod_table, struct {
1013 fn lessThan(deps: *const Package.Module.Deps, lhs: u32, rhs: u32) bool {
1014 const keys = deps.keys();
1015 return std.mem.lessThan(u8, keys[lhs], keys[rhs]);
10331016 }
10341017 }.lessThan);
10351018
1036 for (modules) |mod| {
1037 if ((try seen_table.getOrPut(mod.value)).found_existing) continue;
1019 for (module_indices) |module_index| {
1020 const module = mod_table.values()[module_index];
1021 if ((try seen_table.getOrPut(module)).found_existing) continue;
10381022
10391023 // Finally insert the package name and path to the cache hash.
1040 hash.addBytes(mod.key);
1024 hash.addBytes(mod_table.keys()[module_index]);
10411025 switch (hash_type) {
10421026 .path_bytes => {
1043 hash.addBytes(mod.value.root_src_path);
1044 hash.addOptionalBytes(mod.value.root.root_dir.path);
1045 hash.addBytes(mod.value.root.sub_path);
1027 hash.addBytes(module.root_src_path);
1028 hash.addOptionalBytes(module.root.root_dir.path);
1029 hash.addBytes(module.root.sub_path);
10461030 },
10471031 .files => |man| {
1048 const pkg_zig_file = try mod.value.root.joinString(
1032 const pkg_zig_file = try module.root.joinString(
10491033 allocator,
1050 mod.value.root_src_path,
1034 module.root_src_path,
10511035 );
10521036 _ = try man.addFile(pkg_zig_file, null);
10531037 },
10541038 }
10551039 // Recurse to handle the module's dependencies
1056 try addModuleTableToCacheHash(hash, arena, mod.value.deps, seen_table, hash_type);
1040 try addModuleTableToCacheHash(hash, arena, module.deps, seen_table, hash_type);
10571041 }
10581042}
10591043
......@@ -2260,8 +2244,8 @@ pub fn destroy(self: *Compilation) void {
22602244 }
22612245 self.c_object_table.deinit(gpa);
22622246
2263 for (self.failed_c_objects.values()) |value| {
2264 value.destroy(gpa);
2247 for (self.failed_c_objects.values()) |bundle| {
2248 bundle.destroy(gpa);
22652249 }
22662250 self.failed_c_objects.deinit(gpa);
22672251
......@@ -2483,13 +2467,9 @@ pub fn update(comp: *Compilation, main_progress_node: *std.Progress.Node) !void
24832467 }
24842468
24852469 // Put a work item in for checking if any files used with `@embedFile` changed.
2486 {
2487 try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count());
2488 var it = module.embed_table.iterator();
2489 while (it.next()) |entry| {
2490 const embed_file = entry.value_ptr.*;
2491 comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file);
2492 }
2470 try comp.embed_file_work_queue.ensureUnusedCapacity(module.embed_table.count());
2471 for (module.embed_table.values()) |embed_file| {
2472 comp.embed_file_work_queue.writeItemAssumeCapacity(embed_file);
24932473 }
24942474
24952475 try comp.work_queue.writeItem(.{ .analyze_mod = std_mod });
......@@ -3083,9 +3063,8 @@ pub fn totalErrorCount(self: *Compilation) u32 {
30833063 @intFromBool(self.alloc_failure_occurred) +
30843064 self.lld_errors.items.len;
30853065
3086 {
3087 var it = self.failed_c_objects.iterator();
3088 while (it.next()) |entry| total += entry.value_ptr.*.diags.len;
3066 for (self.failed_c_objects.values()) |bundle| {
3067 total += bundle.diags.len;
30893068 }
30903069
30913070 if (!build_options.only_core_functionality) {
......@@ -3098,19 +3077,15 @@ pub fn totalErrorCount(self: *Compilation) u32 {
30983077 total += module.failed_exports.count();
30993078 total += module.failed_embed_files.count();
31003079
3101 {
3102 var it = module.failed_files.iterator();
3103 while (it.next()) |entry| {
3104 if (entry.value_ptr.*) |_| {
3105 total += 1;
3106 } else {
3107 const file = entry.key_ptr.*;
3108 assert(file.zir_loaded);
3109 const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
3110 assert(payload_index != 0);
3111 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
3112 total += header.data.items_len;
3113 }
3080 for (module.failed_files.keys(), module.failed_files.values()) |file, error_msg| {
3081 if (error_msg) |_| {
3082 total += 1;
3083 } else {
3084 assert(file.zir_loaded);
3085 const payload_index = file.zir.extra[@intFromEnum(Zir.ExtraIndex.compile_errors)];
3086 assert(payload_index != 0);
3087 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
3088 total += header.data.items_len;
31143089 }
31153090 }
31163091
......@@ -3166,15 +3141,13 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
31663141 try bundle.init(gpa);
31673142 defer bundle.deinit();
31683143
3169 {
3170 var it = self.failed_c_objects.iterator();
3171 while (it.next()) |entry| try entry.value_ptr.*.addToErrorBundle(&bundle);
3144 for (self.failed_c_objects.values()) |diag_bundle| {
3145 try diag_bundle.addToErrorBundle(&bundle);
31723146 }
31733147
31743148 if (!build_options.only_core_functionality) {
3175 var it = self.failed_win32_resources.iterator();
3176 while (it.next()) |entry| {
3177 try bundle.addBundleAsRoots(entry.value_ptr.*);
3149 for (self.failed_win32_resources.values()) |error_bundle| {
3150 try bundle.addBundleAsRoots(error_bundle);
31783151 }
31793152 }
31803153
......@@ -3205,65 +3178,52 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
32053178 });
32063179 }
32073180 if (self.bin_file.options.module) |module| {
3208 {
3209 var it = module.failed_files.iterator();
3210 while (it.next()) |entry| {
3211 if (entry.value_ptr.*) |msg| {
3212 try addModuleErrorMsg(module, &bundle, msg.*);
3213 } else {
3214 // Must be ZIR errors. Note that this may include AST errors.
3215 // addZirErrorMessages asserts that the tree is loaded.
3216 _ = try entry.key_ptr.*.getTree(gpa);
3217 try addZirErrorMessages(&bundle, entry.key_ptr.*);
3218 }
3219 }
3220 }
3221 {
3222 var it = module.failed_embed_files.iterator();
3223 while (it.next()) |entry| {
3224 const msg = entry.value_ptr.*;
3181 for (module.failed_files.keys(), module.failed_files.values()) |file, error_msg| {
3182 if (error_msg) |msg| {
32253183 try addModuleErrorMsg(module, &bundle, msg.*);
3184 } else {
3185 // Must be ZIR errors. Note that this may include AST errors.
3186 // addZirErrorMessages asserts that the tree is loaded.
3187 _ = try file.getTree(gpa);
3188 try addZirErrorMessages(&bundle, file);
32263189 }
32273190 }
3228 {
3229 var it = module.failed_decls.iterator();
3230 while (it.next()) |entry| {
3231 const decl_index = entry.key_ptr.*;
3232 // Skip errors for Decls within files that had a parse failure.
3233 // We'll try again once parsing succeeds.
3234 if (module.declFileScope(decl_index).okToReportErrors()) {
3235 try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*);
3236 if (module.cimport_errors.get(entry.key_ptr.*)) |errors| {
3237 for (errors.getMessages()) |err_msg_index| {
3238 const err_msg = errors.getErrorMessage(err_msg_index);
3239 try bundle.addRootErrorMessage(.{
3240 .msg = try bundle.addString(errors.nullTerminatedString(err_msg.msg)),
3241 .src_loc = if (err_msg.src_loc != .none) blk: {
3242 const src_loc = errors.getSourceLocation(err_msg.src_loc);
3243 break :blk try bundle.addSourceLocation(.{
3244 .src_path = try bundle.addString(errors.nullTerminatedString(src_loc.src_path)),
3245 .span_start = src_loc.span_start,
3246 .span_main = src_loc.span_main,
3247 .span_end = src_loc.span_end,
3248 .line = src_loc.line,
3249 .column = src_loc.column,
3250 .source_line = if (src_loc.source_line != 0) try bundle.addString(errors.nullTerminatedString(src_loc.source_line)) else 0,
3251 });
3252 } else .none,
3253 });
3254 }
3191 for (module.failed_embed_files.values()) |error_msg| {
3192 try addModuleErrorMsg(module, &bundle, error_msg.*);
3193 }
3194 for (module.failed_decls.keys(), module.failed_decls.values()) |decl_index, error_msg| {
3195 // Skip errors for Decls within files that had a parse failure.
3196 // We'll try again once parsing succeeds.
3197 if (module.declFileScope(decl_index).okToReportErrors()) {
3198 try addModuleErrorMsg(module, &bundle, error_msg.*);
3199 if (module.cimport_errors.get(decl_index)) |errors| {
3200 for (errors.getMessages()) |err_msg_index| {
3201 const err_msg = errors.getErrorMessage(err_msg_index);
3202 try bundle.addRootErrorMessage(.{
3203 .msg = try bundle.addString(errors.nullTerminatedString(err_msg.msg)),
3204 .src_loc = if (err_msg.src_loc != .none) blk: {
3205 const src_loc = errors.getSourceLocation(err_msg.src_loc);
3206 break :blk try bundle.addSourceLocation(.{
3207 .src_path = try bundle.addString(errors.nullTerminatedString(src_loc.src_path)),
3208 .span_start = src_loc.span_start,
3209 .span_main = src_loc.span_main,
3210 .span_end = src_loc.span_end,
3211 .line = src_loc.line,
3212 .column = src_loc.column,
3213 .source_line = if (src_loc.source_line != 0) try bundle.addString(errors.nullTerminatedString(src_loc.source_line)) else 0,
3214 });
3215 } else .none,
3216 });
32553217 }
32563218 }
32573219 }
32583220 }
32593221 if (module.emit_h) |emit_h| {
3260 var it = emit_h.failed_decls.iterator();
3261 while (it.next()) |entry| {
3262 const decl_index = entry.key_ptr.*;
3222 for (emit_h.failed_decls.keys(), emit_h.failed_decls.values()) |decl_index, error_msg| {
32633223 // Skip errors for Decls within files that had a parse failure.
32643224 // We'll try again once parsing succeeds.
32653225 if (module.declFileScope(decl_index).okToReportErrors()) {
3266 try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*);
3226 try addModuleErrorMsg(module, &bundle, error_msg.*);
32673227 }
32683228 }
32693229 }
src/Module.zig+18-25
......@@ -87,7 +87,7 @@ import_table: std.StringArrayHashMapUnmanaged(*File) = .{},
8787/// modified on the file system when an update is requested, as well as to cache
8888/// `@embedFile` results.
8989/// Keys are fully resolved file paths. This table owns the keys and values.
90embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{},
90embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
9191
9292/// Stores all Type and Value objects.
9393/// The idea is that this will be periodically garbage-collected, but such logic
......@@ -2482,15 +2482,11 @@ pub fn deinit(mod: *Module) void {
24822482 }
24832483 mod.import_table.deinit(gpa);
24842484
2485 {
2486 var it = mod.embed_table.iterator();
2487 while (it.next()) |entry| {
2488 gpa.free(entry.key_ptr.*);
2489 const ef: *EmbedFile = entry.value_ptr.*;
2490 gpa.destroy(ef);
2491 }
2492 mod.embed_table.deinit(gpa);
2485 for (mod.embed_table.keys(), mod.embed_table.values()) |path, embed_file| {
2486 gpa.free(path);
2487 gpa.destroy(embed_file);
24932488 }
2489 mod.embed_table.deinit(gpa);
24942490
24952491 mod.compile_log_text.deinit(gpa);
24962492
......@@ -4035,7 +4031,7 @@ pub fn embedFile(
40354031
40364032 const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
40374033 errdefer {
4038 assert(mod.embed_table.remove(resolved_path));
4034 assert(std.mem.eql(u8, mod.embed_table.pop().key, resolved_path));
40394035 keep_resolved_path = false;
40404036 }
40414037 if (gop.found_existing) return gop.value_ptr.*.val;
......@@ -4044,7 +4040,7 @@ pub fn embedFile(
40444040 const sub_file_path = try gpa.dupe(u8, pkg.root_src_path);
40454041 errdefer gpa.free(sub_file_path);
40464042
4047 return newEmbedFile(mod, pkg, sub_file_path, resolved_path, gop, src_loc);
4043 return newEmbedFile(mod, pkg, sub_file_path, resolved_path, gop.value_ptr, src_loc);
40484044 }
40494045
40504046 // The resolved path is used as the key in the table, to detect if a file
......@@ -4062,7 +4058,7 @@ pub fn embedFile(
40624058
40634059 const gop = try mod.embed_table.getOrPut(gpa, resolved_path);
40644060 errdefer {
4065 assert(mod.embed_table.remove(resolved_path));
4061 assert(std.mem.eql(u8, mod.embed_table.pop().key, resolved_path));
40664062 keep_resolved_path = false;
40674063 }
40684064 if (gop.found_existing) return gop.value_ptr.*.val;
......@@ -4089,7 +4085,7 @@ pub fn embedFile(
40894085 };
40904086 defer gpa.free(sub_file_path);
40914087
4092 return newEmbedFile(mod, cur_file.mod, sub_file_path, resolved_path, gop, src_loc);
4088 return newEmbedFile(mod, cur_file.mod, sub_file_path, resolved_path, gop.value_ptr, src_loc);
40934089}
40944090
40954091/// https://github.com/ziglang/zig/issues/14307
......@@ -4098,7 +4094,7 @@ fn newEmbedFile(
40984094 pkg: *Package.Module,
40994095 sub_file_path: []const u8,
41004096 resolved_path: []const u8,
4101 gop: std.StringHashMapUnmanaged(*EmbedFile).GetOrPutResult,
4097 result: **EmbedFile,
41024098 src_loc: SrcLoc,
41034099) !InternPool.Index {
41044100 const gpa = mod.gpa;
......@@ -4154,7 +4150,7 @@ fn newEmbedFile(
41544150 } },
41554151 } });
41564152
4157 gop.value_ptr.* = new_file;
4153 result.* = new_file;
41584154 new_file.* = .{
41594155 .sub_file_path = try ip.getOrPutString(gpa, sub_file_path),
41604156 .owner = pkg,
......@@ -4621,16 +4617,13 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
46214617 else => |e| return e,
46224618 };
46234619
4624 {
4625 var it = sema.unresolved_inferred_allocs.keyIterator();
4626 while (it.next()) |ptr_inst| {
4627 // The lack of a resolve_inferred_alloc means that this instruction
4628 // is unused so it just has to be a no-op.
4629 sema.air_instructions.set(@intFromEnum(ptr_inst.*), .{
4630 .tag = .alloc,
4631 .data = .{ .ty = Type.single_const_pointer_to_comptime_int },
4632 });
4633 }
4620 for (sema.unresolved_inferred_allocs.keys()) |ptr_inst| {
4621 // The lack of a resolve_inferred_alloc means that this instruction
4622 // is unused so it just has to be a no-op.
4623 sema.air_instructions.set(@intFromEnum(ptr_inst), .{
4624 .tag = .alloc,
4625 .data = .{ .ty = Type.single_const_pointer_to_comptime_int },
4626 });
46344627 }
46354628
46364629 // If we don't get an error return trace from a caller, create our own.
src/Package/Module.zig+1-1
......@@ -14,7 +14,7 @@ fully_qualified_name: []const u8,
1414/// responsible for detecting these names and using the correct package.
1515deps: Deps = .{},
1616
17pub const Deps = std.StringHashMapUnmanaged(*Module);
17pub const Deps = std.StringArrayHashMapUnmanaged(*Module);
1818
1919pub const Tree = struct {
2020 /// Each `Package` exposes a `Module` with build.zig as its root source file.
src/Sema.zig+2-2
......@@ -93,7 +93,7 @@ no_partial_func_ty: bool = false,
9393
9494/// The temporary arena is used for the memory of the `InferredAlloc` values
9595/// here so the values can be dropped without any cleanup.
96unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{},
96unresolved_inferred_allocs: std.AutoArrayHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{},
9797
9898/// Indices of comptime-mutable decls created by this Sema. These decls' values
9999/// should be interned after analysis completes, as they may refer to memory in
......@@ -4040,7 +4040,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
40404040 },
40414041 .inferred_alloc => {
40424042 const ia1 = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc;
4043 const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value;
4043 const ia2 = sema.unresolved_inferred_allocs.fetchSwapRemove(ptr_inst).?.value;
40444044 const peer_vals = try sema.arena.alloc(Air.Inst.Ref, ia2.prongs.items.len);
40454045 for (peer_vals, ia2.prongs.items) |*peer_val, store_inst| {
40464046 assert(sema.air_instructions.items(.tag)[@intFromEnum(store_inst)] == .store);
src/codegen/llvm.zig+4-4
......@@ -9597,9 +9597,9 @@ pub const FuncGen = struct {
95979597 try wip.@"switch"(tag_int_value, bad_value_block, @intCast(enum_type.names.len));
95989598 defer wip_switch.finish(&wip);
95999599
9600 for (enum_type.names.get(ip), 0..) |name, field_index| {
9601 const name_string = try o.builder.string(ip.stringToSlice(name));
9602 const name_init = try o.builder.stringNullConst(name_string);
9600 for (0..enum_type.names.len) |field_index| {
9601 const name = try o.builder.string(ip.stringToSlice(enum_type.names.get(ip)[field_index]));
9602 const name_init = try o.builder.stringNullConst(name);
96039603 const name_variable_index =
96049604 try o.builder.addVariable(.empty, name_init.typeOf(&o.builder), .default);
96059605 try name_variable_index.setInitializer(name_init, &o.builder);
......@@ -9610,7 +9610,7 @@ pub const FuncGen = struct {
96109610
96119611 const name_val = try o.builder.structValue(ret_ty, &.{
96129612 name_variable_index.toConst(&o.builder),
9613 try o.builder.intConst(usize_ty, name_string.slice(&o.builder).?.len),
9613 try o.builder.intConst(usize_ty, name.slice(&o.builder).?.len),
96149614 });
96159615
96169616 const return_block = try wip.block(1, "Name");