diff --git a/src/Compilation.zig b/src/Compilation.zig index 0ee916c44681d68587c40f234a431854226ee9a0..64f947c3c338ae45fb6e8fefaa0b1f12c1065a45 100644 --- a/src/Compilation.zig +++ b/src/Compilation.zig @@ -1317,7 +1317,7 @@ pub fn create(gpa: Allocator, options: InitOptions) !*Compilation { .global_zir_cache = global_zir_cache, .local_zir_cache = local_zir_cache, .emit_h = emit_h, - .error_name_list = .{}, + .tmp_hack_arena = std.heap.ArenaAllocator.init(gpa), }; try module.init(); @@ -2627,7 +2627,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { var it = module.failed_files.iterator(); while (it.next()) |entry| { if (entry.value_ptr.*) |msg| { - try addModuleErrorMsg(&bundle, msg.*); + try addModuleErrorMsg(module, &bundle, msg.*); } else { // Must be ZIR errors. Note that this may include AST errors. // addZirErrorMessages asserts that the tree is loaded. @@ -2640,7 +2640,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { var it = module.failed_embed_files.iterator(); while (it.next()) |entry| { const msg = entry.value_ptr.*; - try addModuleErrorMsg(&bundle, msg.*); + try addModuleErrorMsg(module, &bundle, msg.*); } } { @@ -2650,7 +2650,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { // Skip errors for Decls within files that had a parse failure. // We'll try again once parsing succeeds. if (module.declFileScope(decl_index).okToReportErrors()) { - try addModuleErrorMsg(&bundle, entry.value_ptr.*.*); + try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*); if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| { try bundle.addRootErrorMessage(.{ .msg = try bundle.addString(std.mem.span(c_error.msg)), @@ -2675,12 +2675,12 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { // Skip errors for Decls within files that had a parse failure. // We'll try again once parsing succeeds. if (module.declFileScope(decl_index).okToReportErrors()) { - try addModuleErrorMsg(&bundle, entry.value_ptr.*.*); + try addModuleErrorMsg(module, &bundle, entry.value_ptr.*.*); } } } for (module.failed_exports.values()) |value| { - try addModuleErrorMsg(&bundle, value.*); + try addModuleErrorMsg(module, &bundle, value.*); } } @@ -2728,7 +2728,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle { }; } - try addModuleErrorMsg(&bundle, err_msg); + try addModuleErrorMsg(module, &bundle, err_msg); } } @@ -2784,8 +2784,9 @@ pub const ErrorNoteHashContext = struct { } }; -pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void { +pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void { const gpa = eb.gpa; + const ip = &mod.intern_pool; const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| { const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa); defer gpa.free(file_path); @@ -2811,7 +2812,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) .src_loc = .none, }); break; - } else if (module_reference.decl == null) { + } else if (module_reference.decl == .none) { try ref_traces.append(gpa, .{ .decl_name = 0, .src_loc = .none, @@ -2824,7 +2825,7 @@ pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa); defer gpa.free(rt_file_path); try ref_traces.append(gpa, .{ - .decl_name = try eb.addString(std.mem.sliceTo(module_reference.decl.?, 0)), + .decl_name = try eb.addString(ip.stringToSliceUnwrap(module_reference.decl).?), .src_loc = try eb.addSourceLocation(.{ .src_path = try eb.addString(rt_file_path), .span_start = span.start, diff --git a/src/InternPool.zig b/src/InternPool.zig index d593ad1e173f26c92b99a8ccf930cfde9e49f97f..ecdd30d1109c31492a6a3bc756d6f5c3e5bd9988 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -124,6 +124,8 @@ pub const String = enum(u32) { /// An index into `string_bytes`. pub const NullTerminatedString = enum(u32) { + /// This is distinct from `none` - it is a valid index that represents empty string. + empty = 0, _, pub fn toString(self: NullTerminatedString) String { @@ -157,6 +159,8 @@ pub const NullTerminatedString = enum(u32) { /// An index into `string_bytes` which might be `none`. pub const OptionalNullTerminatedString = enum(u32) { + /// This is distinct from `none` - it is a valid index that represents empty string. + empty = 0, none = std.math.maxInt(u32), _, @@ -2447,6 +2451,9 @@ pub const MemoizedCall = struct { pub fn init(ip: *InternPool, gpa: Allocator) !void { assert(ip.items.len == 0); + // Reserve string index 0 for an empty string. + assert((try ip.getOrPutString(gpa, "")) == .empty); + // So that we can use `catch unreachable` below. try ip.items.ensureUnusedCapacity(gpa, static_keys.len); try ip.map.ensureUnusedCapacity(gpa, static_keys.len); @@ -5222,6 +5229,28 @@ pub fn getOrPutString( return ip.getOrPutTrailingString(gpa, s.len + 1); } +pub fn getOrPutStringFmt( + ip: *InternPool, + gpa: Allocator, + comptime format: []const u8, + args: anytype, +) Allocator.Error!NullTerminatedString { + const start = ip.string_bytes.items.len; + try ip.string_bytes.writer(gpa).print(format, args); + try ip.string_bytes.append(gpa, 0); + return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); +} + +pub fn getOrPutStringOpt( + ip: *InternPool, + gpa: Allocator, + optional_string: ?[]const u8, +) Allocator.Error!OptionalNullTerminatedString { + const s = optional_string orelse return .none; + const interned = try getOrPutString(ip, gpa, s); + return interned.toOptional(); +} + /// Uses the last len bytes of ip.string_bytes as the key. pub fn getOrPutTrailingString( ip: *InternPool, @@ -5273,6 +5302,10 @@ pub fn stringToSliceUnwrap(ip: *const InternPool, s: OptionalNullTerminatedStrin return ip.stringToSlice(s.unwrap() orelse return null); } +pub fn stringEqlSlice(ip: *const InternPool, a: NullTerminatedString, b: []const u8) bool { + return std.mem.eql(u8, stringToSlice(ip, a), b); +} + pub fn typeOf(ip: *const InternPool, index: Index) Index { // This optimization of static keys is required so that typeOf can be called // on static keys that haven't been added yet during static key initialization. diff --git a/src/Module.zig b/src/Module.zig index d575f89b4186eba5d4541c17e9f942c756b4b9d8..1e75ab037d6ebd244ec4430d29c309125c6956d8 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -88,6 +88,14 @@ embed_table: std.StringHashMapUnmanaged(*EmbedFile) = .{}, /// Stores all Type and Value objects; periodically garbage collected. intern_pool: InternPool = .{}, +/// To be eliminated in a future commit by moving more data into InternPool. +/// Current uses that must be eliminated: +/// * Struct comptime_args +/// * Struct optimized_order +/// * Union fields +/// This memory lives until the Module is destroyed. +tmp_hack_arena: std.heap.ArenaAllocator, + /// This is currently only used for string literals. memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{}, @@ -125,13 +133,8 @@ cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, []CImportError) = .{}, /// contains Decls that need to be deleted if they end up having no references to them. deletion_set: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, -/// Error tags and their values, tag names are duped with mod.gpa. -/// Corresponds with `error_name_list`. -global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, - -/// ErrorInt -> []const u8 for fast lookups for @intToError at comptime -/// Corresponds with `global_error_set`. -error_name_list: ArrayListUnmanaged([]const u8), +/// Key is the error name, index is the error tag value. Index 0 has a length-0 string. +global_error_set: GlobalErrorSet = .{}, /// Incrementing integer used to compare against the corresponding Decl /// field to determine whether a Decl's status applies to an ongoing update, or a @@ -182,6 +185,8 @@ reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { src: LazySrcLoc, }) = .{}, +pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void); + pub const CImportError = struct { offset: u32, line: u32, @@ -248,7 +253,11 @@ pub const GlobalEmitH = struct { pub const ErrorInt = u32; pub const Export = struct { - options: std.builtin.ExportOptions, + name: InternPool.NullTerminatedString, + linkage: std.builtin.GlobalLinkage, + section: InternPool.OptionalNullTerminatedString, + visibility: std.builtin.SymbolVisibility, + src: LazySrcLoc, /// The Decl that performs the export. Note that this is *not* the Decl being exported. owner_decl: Decl.Index, @@ -392,8 +401,7 @@ const ValueArena = struct { }; pub const Decl = struct { - /// Allocated with Module's allocator; outlives the ZIR code. - name: [*:0]const u8, + name: InternPool.NullTerminatedString, /// The most recent Type of the Decl after a successful semantic analysis. /// Populated when `has_tv`. ty: Type, @@ -401,15 +409,11 @@ pub const Decl = struct { /// Populated when `has_tv`. val: Value, /// Populated when `has_tv`. - /// Points to memory inside value_arena. - @"linksection": ?[*:0]const u8, + @"linksection": InternPool.OptionalNullTerminatedString, /// Populated when `has_tv`. @"align": u32, /// Populated when `has_tv`. @"addrspace": std.builtin.AddressSpace, - /// The memory for ty, val, align, linksection, and captures. - /// If this is `null` then there is no memory management needed. - value_arena: ?*ValueArena = null, /// The direct parent namespace of the Decl. /// Reference to externally owned memory. /// In the case of the Decl corresponding to a file, this is @@ -564,13 +568,7 @@ pub const Decl = struct { function_body, }; - pub fn clearName(decl: *Decl, gpa: Allocator) void { - gpa.free(mem.sliceTo(decl.name, 0)); - decl.name = undefined; - } - pub fn clearValues(decl: *Decl, mod: *Module) void { - const gpa = mod.gpa; if (decl.getOwnedFunctionIndex(mod).unwrap()) |func| { _ = mod.align_stack_fns.remove(func); if (mod.funcPtr(func).comptime_args != null) { @@ -579,19 +577,6 @@ pub const Decl = struct { mod.destroyFunc(func); } _ = mod.memoized_decls.remove(decl.val.ip_index); - if (decl.value_arena) |value_arena| { - value_arena.deinit(gpa); - decl.value_arena = null; - decl.has_tv = false; - decl.owns_tv = false; - } - } - - pub fn finalizeNewArena(decl: *Decl, arena: *std.heap.ArenaAllocator) !void { - assert(decl.value_arena == null); - const value_arena = try arena.allocator().create(ValueArena); - value_arena.* = .{ .state = arena.state }; - decl.value_arena = value_arena; } /// This name is relative to the containing namespace of the decl. @@ -692,7 +677,7 @@ pub const Decl = struct { } pub fn renderFullyQualifiedName(decl: Decl, mod: *Module, writer: anytype) !void { - const unqualified_name = mem.sliceTo(decl.name, 0); + const unqualified_name = mod.intern_pool.stringToSlice(decl.name); if (decl.name_fully_qualified) { return writer.writeAll(unqualified_name); } @@ -700,24 +685,27 @@ pub const Decl = struct { } pub fn renderFullyQualifiedDebugName(decl: Decl, mod: *Module, writer: anytype) !void { - const unqualified_name = mem.sliceTo(decl.name, 0); + const unqualified_name = mod.intern_pool.stringToSlice(decl.name); return mod.namespacePtr(decl.src_namespace).renderFullyQualifiedDebugName(mod, unqualified_name, writer); } - pub fn getFullyQualifiedName(decl: Decl, mod: *Module) ![:0]u8 { - var buffer = std.ArrayList(u8).init(mod.gpa); - defer buffer.deinit(); - try decl.renderFullyQualifiedName(mod, buffer.writer()); + pub fn getFullyQualifiedName(decl: Decl, mod: *Module) !InternPool.NullTerminatedString { + const gpa = mod.gpa; + const ip = &mod.intern_pool; + const start = ip.string_bytes.items.len; + try decl.renderFullyQualifiedName(mod, ip.string_bytes.writer(gpa)); // Sanitize the name for nvptx which is more restrictive. + // TODO This should be handled by the backend, not the frontend. Have a + // look at how the C backend does it for inspiration. if (mod.comp.bin_file.options.target.cpu.arch.isNvptx()) { - for (buffer.items) |*byte| switch (byte.*) { + for (ip.string_bytes.items[start..]) |*byte| switch (byte.*) { '{', '}', '*', '[', ']', '(', ')', ',', ' ', '\'' => byte.* = '_', else => {}, }; } - return buffer.toOwnedSliceSentinel(0); + return ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); } pub fn typedValue(decl: Decl) error{AnalysisFail}!TypedValue { @@ -804,11 +792,11 @@ pub const Decl = struct { pub fn dump(decl: *Decl) void { const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src); - std.debug.print("{s}:{d}:{d} name={s} status={s}", .{ + std.debug.print("{s}:{d}:{d} name={d} status={s}", .{ decl.scope.sub_file_path, loc.line + 1, loc.column + 1, - mem.sliceTo(decl.name, 0), + @enumToInt(decl.name), @tagName(decl.analysis), }); if (decl.has_tv) { @@ -922,15 +910,15 @@ pub const Struct = struct { } }; - pub const Fields = std.StringArrayHashMapUnmanaged(Field); + pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field); /// The `Type` and `Value` memory is owned by the arena of the Struct's owner_decl. pub const Field = struct { /// Uses `noreturn` to indicate `anytype`. /// undefined until `status` is >= `have_field_types`. ty: Type, - /// Uses `unreachable_value` to indicate no default. - default_val: Value, + /// Uses `none` to indicate no default. + default_val: InternPool.Index, /// Zero means to use the ABI alignment of the type. abi_align: u32, /// undefined until `status` is `have_layout`. @@ -982,7 +970,7 @@ pub const Struct = struct { /// runtime version of the struct. pub const omitted_field = std.math.maxInt(u32); - pub fn getFullyQualifiedName(s: *Struct, mod: *Module) ![:0]u8 { + pub fn getFullyQualifiedName(s: *Struct, mod: *Module) !InternPool.NullTerminatedString { return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); } @@ -1141,9 +1129,9 @@ pub const Union = struct { } }; - pub const Fields = std.StringArrayHashMapUnmanaged(Field); + pub const Fields = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, Field); - pub fn getFullyQualifiedName(s: *Union, mod: *Module) ![:0]u8 { + pub fn getFullyQualifiedName(s: *Union, mod: *Module) !InternPool.NullTerminatedString { return mod.declPtr(s.owner_decl).getFullyQualifiedName(mod); } @@ -1569,15 +1557,15 @@ pub const Fn = struct { pub const DeclAdapter = struct { mod: *Module, - pub fn hash(self: @This(), s: []const u8) u32 { + pub fn hash(self: @This(), s: InternPool.NullTerminatedString) u32 { _ = self; - return @truncate(u32, std.hash.Wyhash.hash(0, s)); + return std.hash.uint32(@enumToInt(s)); } - pub fn eql(self: @This(), a: []const u8, b_decl_index: Decl.Index, b_index: usize) bool { + pub fn eql(self: @This(), a: InternPool.NullTerminatedString, b_decl_index: Decl.Index, b_index: usize) bool { _ = b_index; const b_decl = self.mod.declPtr(b_decl_index); - return mem.eql(u8, a, mem.sliceTo(b_decl.name, 0)); + return a == b_decl.name; } }; @@ -1628,16 +1616,14 @@ pub const Namespace = struct { pub fn hash(ctx: @This(), decl_index: Decl.Index) u32 { const decl = ctx.module.declPtr(decl_index); - return @truncate(u32, std.hash.Wyhash.hash(0, mem.sliceTo(decl.name, 0))); + return std.hash.uint32(@enumToInt(decl.name)); } pub fn eql(ctx: @This(), a_decl_index: Decl.Index, b_decl_index: Decl.Index, b_index: usize) bool { _ = b_index; const a_decl = ctx.module.declPtr(a_decl_index); const b_decl = ctx.module.declPtr(b_decl_index); - const a_name = mem.sliceTo(a_decl.name, 0); - const b_name = mem.sliceTo(b_decl.name, 0); - return mem.eql(u8, a_name, b_name); + return a_decl.name == b_decl.name; } }; @@ -1649,8 +1635,6 @@ pub const Namespace = struct { pub fn destroyDecls(ns: *Namespace, mod: *Module) void { const gpa = mod.gpa; - log.debug("destroyDecls {*}", .{ns}); - var decls = ns.decls; ns.decls = .{}; @@ -1676,8 +1660,6 @@ pub const Namespace = struct { ) !void { const gpa = mod.gpa; - log.debug("deleteAllDecls {*}", .{ns}); - var decls = ns.decls; ns.decls = .{}; @@ -1712,7 +1694,8 @@ pub const Namespace = struct { if (ns.parent.unwrap()) |parent| { const decl_index = ns.getDeclIndex(mod); const decl = mod.declPtr(decl_index); - try mod.namespacePtr(parent).renderFullyQualifiedName(mod, mem.sliceTo(decl.name, 0), writer); + const decl_name = mod.intern_pool.stringToSlice(decl.name); + try mod.namespacePtr(parent).renderFullyQualifiedName(mod, decl_name, writer); } else { try ns.file_scope.renderFullyQualifiedName(writer); } @@ -1733,7 +1716,8 @@ pub const Namespace = struct { if (ns.parent.unwrap()) |parent| { const decl_index = ns.getDeclIndex(mod); const decl = mod.declPtr(decl_index); - try mod.namespacePtr(parent).renderFullyQualifiedDebugName(mod, mem.sliceTo(decl.name, 0), writer); + const decl_name = mod.intern_pool.stringToSlice(decl.name); + try mod.namespacePtr(parent).renderFullyQualifiedDebugName(mod, decl_name, writer); } else { try ns.file_scope.renderFullyQualifiedDebugName(writer); separator_char = ':'; @@ -1927,11 +1911,11 @@ pub const File = struct { }; } - pub fn fullyQualifiedNameZ(file: File, gpa: Allocator) ![:0]u8 { - var buf = std.ArrayList(u8).init(gpa); - defer buf.deinit(); - try file.renderFullyQualifiedName(buf.writer()); - return buf.toOwnedSliceSentinel(0); + pub fn fullyQualifiedName(file: File, mod: *Module) !InternPool.NullTerminatedString { + const ip = &mod.intern_pool; + const start = ip.string_bytes.items.len; + try file.renderFullyQualifiedName(ip.string_bytes.writer(mod.gpa)); + return ip.getOrPutTrailingString(mod.gpa, ip.string_bytes.items.len - start); } /// Returns the full path to this file relative to its package. @@ -2055,7 +2039,7 @@ pub const ErrorMsg = struct { reference_trace: []Trace = &.{}, pub const Trace = struct { - decl: ?[*:0]const u8, + decl: InternPool.OptionalNullTerminatedString, src_loc: SrcLoc, hidden: u32 = 0, }; @@ -3180,8 +3164,8 @@ pub const CompileError = error{ pub fn init(mod: *Module) !void { const gpa = mod.gpa; - try mod.error_name_list.append(gpa, "(no error)"); try mod.intern_pool.init(gpa); + try mod.global_error_set.put(gpa, .empty, {}); } pub fn deinit(mod: *Module) void { @@ -3282,15 +3266,8 @@ pub fn deinit(mod: *Module) void { } mod.export_owners.deinit(gpa); - { - var it = mod.global_error_set.keyIterator(); - while (it.next()) |key| { - gpa.free(key.*); - } - mod.global_error_set.deinit(gpa); - } + mod.global_error_set.deinit(gpa); - mod.error_name_list.deinit(gpa); mod.test_functions.deinit(gpa); mod.align_stack_fns.deinit(gpa); mod.monomorphed_funcs.deinit(gpa); @@ -3305,13 +3282,13 @@ pub fn deinit(mod: *Module) void { mod.memoized_decls.deinit(gpa); mod.intern_pool.deinit(gpa); + mod.tmp_hack_arena.deinit(); } pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { const gpa = mod.gpa; { const decl = mod.declPtr(decl_index); - log.debug("destroy {*} ({s})", .{ decl, decl.name }); _ = mod.test_functions.swapRemove(decl_index); if (decl.deletion_flag) { assert(mod.deletion_set.swapRemove(decl_index)); @@ -3329,7 +3306,6 @@ pub fn destroyDecl(mod: *Module, decl_index: Decl.Index) void { decl.clearValues(mod); decl.dependants.deinit(gpa); decl.dependencies.deinit(gpa); - decl.clearName(gpa); decl.* = undefined; } mod.decls_free_list.append(gpa, decl_index) catch { @@ -3391,11 +3367,7 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool { } fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void { - for (export_list.items) |exp| { - gpa.free(exp.options.name); - if (exp.options.section) |s| gpa.free(s); - gpa.destroy(exp); - } + for (export_list.items) |exp| gpa.destroy(exp); export_list.deinit(gpa); } @@ -3814,9 +3786,6 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { if (decl.zir_decl_index != 0) { const old_zir_decl_index = decl.zir_decl_index; const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { - log.debug("updateZirRefs {s}: delete {*} ({s})", .{ - file.sub_file_path, decl, decl.name, - }); try file.deleted_decls.append(gpa, decl_index); continue; }; @@ -3824,14 +3793,7 @@ fn updateZirRefs(mod: *Module, file: *File, old_zir: Zir) !void { decl.zir_decl_index = new_zir_decl_index; const new_hash = decl.contentsHashZir(new_zir); if (!std.zig.srcHashEql(old_hash, new_hash)) { - log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{ - file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, - }); try file.outdated_decls.append(gpa, decl_index); - } else { - log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{ - file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, - }); } } @@ -4031,8 +3993,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { .complete => return, .outdated => blk: { - log.debug("re-analyzing {*} ({s})", .{ decl, decl.name }); - // The exports this Decl performs will be re-discovered, so we remove them here // prior to re-analysis. try mod.deleteDeclExports(decl_index); @@ -4047,9 +4007,6 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { const dep = mod.declPtr(dep_index); dep.removeDependant(decl_index); if (dep.dependants.count() == 0 and !dep.deletion_flag) { - log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ - decl, decl.name, dep, dep.name, - }); try mod.markDeclForDeletion(dep_index); } } @@ -4061,7 +4018,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { .unreferenced => false, }; - var decl_prog_node = mod.sema_prog_node.start(mem.sliceTo(decl.name, 0), 0); + var decl_prog_node = mod.sema_prog_node.start(mod.intern_pool.stringToSlice(decl.name), 0); decl_prog_node.activate(); defer decl_prog_node.end(); @@ -4190,14 +4147,11 @@ pub fn ensureFuncBodyAnalyzed(mod: *Module, func_index: Fn.Index) SemaError!void if (no_bin_file and !dump_air and !dump_llvm_ir) return; - log.debug("analyze liveness of {s}", .{decl.name}); var liveness = try Liveness.analyze(gpa, air, &mod.intern_pool); defer liveness.deinit(gpa); if (dump_air) { - const fqn = try decl.getFullyQualifiedName(mod); - defer mod.gpa.free(fqn); - + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); std.debug.print("# Begin Function AIR: {s}:\n", .{fqn}); @import("print_air.zig").dump(mod, air, liveness); std.debug.print("# End Function AIR: {s}\n\n", .{fqn}); @@ -4354,9 +4308,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { if (file.root_decl != .none) return; const gpa = mod.gpa; - var new_decl_arena = std.heap.ArenaAllocator.init(gpa); - errdefer new_decl_arena.deinit(); - const new_decl_arena_allocator = new_decl_arena.allocator(); // Because these three things each reference each other, `undefined` // placeholders are used before being set after the struct type gains an @@ -4394,7 +4345,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { new_namespace.ty = struct_ty.toType(); file.root_decl = new_decl_index.toOptional(); - new_decl.name = try file.fullyQualifiedNameZ(gpa); + new_decl.name = try file.fullyQualifiedName(mod); new_decl.src_line = 0; new_decl.is_pub = true; new_decl.is_exported = false; @@ -4403,7 +4354,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { new_decl.ty = Type.type; new_decl.val = struct_ty.toValue(); new_decl.@"align" = 0; - new_decl.@"linksection" = null; + new_decl.@"linksection" = .none; new_decl.has_tv = true; new_decl.owns_tv = true; new_decl.alive = true; // This Decl corresponds to a File and is therefore always alive. @@ -4431,7 +4382,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { .mod = mod, .gpa = gpa, .arena = sema_arena_allocator, - .perm_arena = new_decl_arena_allocator, .code = file.zir, .owner_decl = new_decl, .owner_decl_index = new_decl_index, @@ -4484,8 +4434,6 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { } else { new_decl.analysis = .file_failure; } - - try new_decl.finalizeNewArena(&new_decl_arena); } /// Returns `true` if the Decl type changed. @@ -4507,28 +4455,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl.analysis = .in_progress; - // We need the memory for the Type to go into the arena for the Decl - var decl_arena = std.heap.ArenaAllocator.init(gpa); - const decl_arena_allocator = decl_arena.allocator(); - const decl_value_arena = blk: { - errdefer decl_arena.deinit(); - const s = try decl_arena_allocator.create(ValueArena); - s.* = .{ .state = undefined }; - break :blk s; - }; - defer { - if (decl.value_arena) |value_arena| { - assert(value_arena.state_acquired == null); - decl_value_arena.prev = value_arena; - } - - decl_value_arena.state = decl_arena.state; - decl.value_arena = decl_value_arena; - } - var analysis_arena = std.heap.ArenaAllocator.init(gpa); defer analysis_arena.deinit(); - const analysis_arena_allocator = analysis_arena.allocator(); var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); defer comptime_mutable_decls.deinit(); @@ -4536,8 +4464,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { var sema: Sema = .{ .mod = mod, .gpa = gpa, - .arena = analysis_arena_allocator, - .perm_arena = decl_arena_allocator, + .arena = analysis_arena.allocator(), .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, @@ -4551,7 +4478,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { defer sema.deinit(); if (mod.declIsRoot(decl_index)) { - log.debug("semaDecl root {*} ({s})", .{ decl, decl.name }); const main_struct_inst = Zir.main_struct_inst; const struct_index = decl.getOwnedStructIndex(mod).unwrap().?; const struct_obj = mod.structPtr(struct_index); @@ -4563,7 +4489,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl.generation = mod.generation; return false; } - log.debug("semaDecl {*} ({s})", .{ decl, decl.name }); var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope); defer wip_captures.deinit(); @@ -4619,7 +4544,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl.ty = InternPool.Index.type_type.toType(); decl.val = ty.toValue(); decl.@"align" = 0; - decl.@"linksection" = null; + decl.@"linksection" = .none; decl.has_tv = true; decl.owns_tv = false; decl.analysis = .complete; @@ -4646,7 +4571,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { decl.clearValues(mod); decl.ty = decl_tv.ty; - decl.val = try decl_tv.val.copy(decl_arena_allocator); + decl.val = (try decl_tv.val.intern(decl_tv.ty, mod)).toValue(); // linksection, align, and addrspace were already set by Sema decl.has_tv = true; decl.owns_tv = owns_tv; @@ -4660,7 +4585,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { return sema.fail(&block_scope, export_src, "export of inline function", .{}); } // The scope needs to have the decl in it. - const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; + const options: std.builtin.ExportOptions = .{ + .name = mod.intern_pool.stringToSlice(decl.name), + }; try sema.analyzeExport(&block_scope, export_src, options, decl_index); } return type_changed or is_inline != prev_is_inline; @@ -4693,14 +4620,13 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { .func => {}, else => { - log.debug("send global const to linker: {*} ({s})", .{ decl, decl.name }); queue_linker_work = true; }, }, } decl.ty = decl_tv.ty; - decl.val = try decl_tv.val.copy(decl_arena_allocator); + decl.val = (try decl_tv.val.intern(decl_tv.ty, mod)).toValue(); decl.@"align" = blk: { const align_ref = decl.zirAlignRef(mod); if (align_ref == .none) break :blk 0; @@ -4708,14 +4634,15 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { }; decl.@"linksection" = blk: { const linksection_ref = decl.zirLinksectionRef(mod); - if (linksection_ref == .none) break :blk null; + if (linksection_ref == .none) break :blk .none; const bytes = try sema.resolveConstString(&block_scope, section_src, linksection_ref, "linksection must be comptime-known"); if (mem.indexOfScalar(u8, bytes, 0) != null) { return sema.fail(&block_scope, section_src, "linksection cannot contain null bytes", .{}); } else if (bytes.len == 0) { return sema.fail(&block_scope, section_src, "linksection cannot be empty", .{}); } - break :blk (try decl_arena_allocator.dupeZ(u8, bytes)).ptr; + const section = try mod.intern_pool.getOrPutString(gpa, bytes); + break :blk section.toOptional(); }; decl.@"addrspace" = blk: { const addrspace_ctx: Sema.AddressSpaceContext = switch (mod.intern_pool.indexToKey(decl_tv.val.toIntern())) { @@ -4743,7 +4670,6 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); if (has_runtime_bits) { - log.debug("queue linker work for {*} ({s})", .{ decl, decl.name }); // Needed for codegen_decl which will call updateDecl and then the // codegen backend wants full access to the Decl Type. @@ -4759,7 +4685,9 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { if (decl.is_exported) { const export_src: LazySrcLoc = .{ .token_offset = @boolToInt(decl.is_pub) }; // The scope needs to have the decl in it. - const options: std.builtin.ExportOptions = .{ .name = mem.sliceTo(decl.name, 0) }; + const options: std.builtin.ExportOptions = .{ + .name = mod.intern_pool.stringToSlice(decl.name), + }; try sema.analyzeExport(&block_scope, export_src, options, decl_index); } @@ -4785,10 +4713,6 @@ pub fn declareDeclDependencyType(mod: *Module, depender_index: Decl.Index, depen } } - log.debug("{*} ({s}) depends on {*} ({s})", .{ - depender, depender.name, dependee, dependee.name, - }); - if (dependee.deletion_flag) { dependee.deletion_flag = false; assert(mod.deletion_set.swapRemove(dependee_index)); @@ -5138,6 +5062,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err const namespace = mod.namespacePtr(namespace_index); const gpa = mod.gpa; const zir = namespace.file_scope.zir; + const ip = &mod.intern_pool; // zig fmt: off const is_pub = (flags & 0b0001) != 0; @@ -5157,31 +5082,31 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err // Every Decl needs a name. var is_named_test = false; var kind: Decl.Kind = .named; - const decl_name: [:0]const u8 = switch (decl_name_index) { + const decl_name: InternPool.NullTerminatedString = switch (decl_name_index) { 0 => name: { if (export_bit) { const i = iter.usingnamespace_index; iter.usingnamespace_index += 1; kind = .@"usingnamespace"; - break :name try std.fmt.allocPrintZ(gpa, "usingnamespace_{d}", .{i}); + break :name try ip.getOrPutStringFmt(gpa, "usingnamespace_{d}", .{i}); } else { const i = iter.comptime_index; iter.comptime_index += 1; kind = .@"comptime"; - break :name try std.fmt.allocPrintZ(gpa, "comptime_{d}", .{i}); + break :name try ip.getOrPutStringFmt(gpa, "comptime_{d}", .{i}); } }, 1 => name: { const i = iter.unnamed_test_index; iter.unnamed_test_index += 1; kind = .@"test"; - break :name try std.fmt.allocPrintZ(gpa, "test_{d}", .{i}); + break :name try ip.getOrPutStringFmt(gpa, "test_{d}", .{i}); }, 2 => name: { is_named_test = true; const test_name = zir.nullTerminatedString(decl_doccomment_index); kind = .@"test"; - break :name try std.fmt.allocPrintZ(gpa, "decltest.{s}", .{test_name}); + break :name try ip.getOrPutStringFmt(gpa, "decltest.{s}", .{test_name}); }, else => name: { const raw_name = zir.nullTerminatedString(decl_name_index); @@ -5189,14 +5114,12 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err is_named_test = true; const test_name = zir.nullTerminatedString(decl_name_index + 1); kind = .@"test"; - break :name try std.fmt.allocPrintZ(gpa, "test.{s}", .{test_name}); + break :name try ip.getOrPutStringFmt(gpa, "test.{s}", .{test_name}); } else { - break :name try gpa.dupeZ(u8, raw_name); + break :name try ip.getOrPutString(gpa, raw_name); } }, }; - var must_free_decl_name = true; - defer if (must_free_decl_name) gpa.free(decl_name); const is_exported = export_bit and decl_name_index != 0; if (kind == .@"usingnamespace") try namespace.usingnamespace_set.ensureUnusedCapacity(gpa, 1); @@ -5204,7 +5127,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err // We create a Decl for it regardless of analysis status. const gop = try namespace.decls.getOrPutContextAdapted( gpa, - @as([]const u8, mem.sliceTo(decl_name, 0)), + decl_name, DeclAdapter{ .mod = mod }, Namespace.DeclContext{ .module = mod }, ); @@ -5214,11 +5137,9 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err const new_decl = mod.declPtr(new_decl_index); new_decl.kind = kind; new_decl.name = decl_name; - must_free_decl_name = false; if (kind == .@"usingnamespace") { namespace.usingnamespace_set.putAssumeCapacity(new_decl_index, is_pub); } - log.debug("scan new {*} ({s}) into {*}", .{ new_decl, decl_name, namespace }); new_decl.src_line = line; gop.key_ptr.* = new_decl_index; // Exported decls, comptime decls, usingnamespace decls, and @@ -5239,7 +5160,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err if (!comp.bin_file.options.is_test) break :blk false; if (decl_pkg != mod.main_pkg) break :blk false; if (comp.test_filter) |test_filter| { - if (mem.indexOf(u8, decl_name, test_filter) == null) { + if (mem.indexOf(u8, ip.stringToSlice(decl_name), test_filter) == null) { break :blk false; } } @@ -5270,7 +5191,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err gpa, src_loc, "duplicate test name: {s}", - .{decl_name}, + .{ip.stringToSlice(decl_name)}, ); errdefer msg.destroy(gpa); try mod.failed_decls.putNoClobber(gpa, decl_index, msg); @@ -5281,7 +5202,6 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) Allocator.Err }; try mod.errNoteNonLazy(other_src_loc, msg, "other test here", .{}); } - log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace }); // Update the AST node of the decl; even if its contents are unchanged, it may // have been re-ordered. decl.src_node = decl_node; @@ -5315,7 +5235,6 @@ pub fn clearDecl( defer tracy.end(); const decl = mod.declPtr(decl_index); - log.debug("clearing {*} ({s})", .{ decl, decl.name }); const gpa = mod.gpa; try mod.deletion_set.ensureUnusedCapacity(gpa, decl.dependencies.count()); @@ -5330,9 +5249,6 @@ pub fn clearDecl( const dep = mod.declPtr(dep_index); dep.removeDependant(decl_index); if (dep.dependants.count() == 0 and !dep.deletion_flag) { - log.debug("insert {*} ({s}) dependant {*} ({s}) into deletion set", .{ - decl, decl.name, dep, dep.name, - }); // We don't recursively perform a deletion here, because during the update, // another reference to it may turn up. dep.deletion_flag = true; @@ -5387,7 +5303,6 @@ pub fn clearDecl( /// This function is exclusively called for anonymous decls. pub fn deleteUnusedDecl(mod: *Module, decl_index: Decl.Index) void { const decl = mod.declPtr(decl_index); - log.debug("deleteUnusedDecl {d} ({s})", .{ decl_index, decl.name }); assert(!mod.declIsRoot(decl_index)); assert(mod.namespacePtr(decl.src_namespace).anon_decls.swapRemove(decl_index)); @@ -5415,7 +5330,6 @@ fn markDeclForDeletion(mod: *Module, decl_index: Decl.Index) !void { /// If other decls depend on this decl, they must be aborted first. pub fn abortAnonDecl(mod: *Module, decl_index: Decl.Index) void { const decl = mod.declPtr(decl_index); - log.debug("abortAnonDecl {*} ({s})", .{ decl, decl.name }); assert(!mod.declIsRoot(decl_index)); assert(mod.namespacePtr(decl.src_namespace).anon_decls.swapRemove(decl_index)); @@ -5468,21 +5382,20 @@ fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void } } if (mod.comp.bin_file.cast(link.File.Elf)) |elf| { - elf.deleteDeclExport(decl_index, exp.options.name); + elf.deleteDeclExport(decl_index, exp.name); } if (mod.comp.bin_file.cast(link.File.MachO)) |macho| { - try macho.deleteDeclExport(decl_index, exp.options.name); + try macho.deleteDeclExport(decl_index, exp.name); } if (mod.comp.bin_file.cast(link.File.Wasm)) |wasm| { wasm.deleteDeclExport(decl_index); } if (mod.comp.bin_file.cast(link.File.Coff)) |coff| { - coff.deleteDeclExport(decl_index, exp.options.name); + coff.deleteDeclExport(decl_index, exp.name); } if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| { failed_kv.value.destroy(mod.gpa); } - mod.gpa.free(exp.options.name); mod.gpa.destroy(exp); } export_owners.deinit(mod.gpa); @@ -5497,11 +5410,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE const decl_index = func.owner_decl; const decl = mod.declPtr(decl_index); - // Use the Decl's arena for captured values. - var decl_arena: std.heap.ArenaAllocator = undefined; - const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); - defer decl.value_arena.?.release(&decl_arena); - var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa); defer comptime_mutable_decls.deinit(); @@ -5512,7 +5420,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE .mod = mod, .gpa = gpa, .arena = arena, - .perm_arena = decl_arena_allocator, .code = decl.getFileScope(mod).zir, .owner_decl = decl, .owner_decl_index = decl_index, @@ -5616,7 +5523,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE } func.state = .in_progress; - log.debug("set {s} to in_progress", .{decl.name}); const last_arg_index = inner_block.instructions.items.len; @@ -5677,7 +5583,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE sema.air_extra.items[@enumToInt(Air.ExtraIndex.main_block)] = main_block_index; func.state = .success; - log.debug("set {s} to success", .{decl.name}); // Finally we must resolve the return type and parameter types so that backends // have full access to type information. @@ -5724,7 +5629,6 @@ pub fn analyzeFnBody(mod: *Module, func_index: Fn.Index, arena: Allocator) SemaE fn markOutdatedDecl(mod: *Module, decl_index: Decl.Index) !void { const decl = mod.declPtr(decl_index); - log.debug("mark outdated {*} ({s})", .{ decl, decl.name }); try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl_index }); if (mod.failed_decls.fetchSwapRemove(decl_index)) |kv| { kv.value.destroy(mod.gpa); @@ -5821,7 +5725,7 @@ pub fn allocateNewDecl( .ty = undefined, .val = undefined, .@"align" = undefined, - .@"linksection" = undefined, + .@"linksection" = .none, .@"addrspace" = .generic, .analysis = .unreferenced, .deletion_flag = false, @@ -5839,25 +5743,20 @@ pub fn allocateNewDecl( return decl_and_index.decl_index; } -/// Get error value for error tag `name`. -pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(ErrorInt).KV { +pub fn getErrorValue( + mod: *Module, + name: InternPool.NullTerminatedString, +) Allocator.Error!ErrorInt { const gop = try mod.global_error_set.getOrPut(mod.gpa, name); - if (gop.found_existing) { - return std.StringHashMapUnmanaged(ErrorInt).KV{ - .key = gop.key_ptr.*, - .value = gop.value_ptr.*, - }; - } + return @intCast(ErrorInt, gop.index); +} - errdefer assert(mod.global_error_set.remove(name)); - try mod.error_name_list.ensureUnusedCapacity(mod.gpa, 1); - gop.key_ptr.* = try mod.gpa.dupe(u8, name); - gop.value_ptr.* = @intCast(ErrorInt, mod.error_name_list.items.len); - mod.error_name_list.appendAssumeCapacity(gop.key_ptr.*); - return std.StringHashMapUnmanaged(ErrorInt).KV{ - .key = gop.key_ptr.*, - .value = gop.value_ptr.*, - }; +pub fn getErrorValueFromSlice( + mod: *Module, + name: []const u8, +) Allocator.Error!ErrorInt { + const interned_name = try mod.intern_pool.getOrPutString(mod.gpa, name); + return getErrorValue(mod, interned_name); } pub fn createAnonymousDecl(mod: *Module, block: *Sema.Block, typed_value: TypedValue) !Decl.Index { @@ -5874,24 +5773,23 @@ pub fn createAnonymousDeclFromDecl( ) !Decl.Index { const new_decl_index = try mod.allocateNewDecl(namespace, src_decl.src_node, src_scope); errdefer mod.destroyDecl(new_decl_index); - const name = try std.fmt.allocPrintZ(mod.gpa, "{s}__anon_{d}", .{ - src_decl.name, @enumToInt(new_decl_index), + const ip = &mod.intern_pool; + const name = try ip.getOrPutStringFmt(mod.gpa, "{s}__anon_{d}", .{ + ip.stringToSlice(src_decl.name), @enumToInt(new_decl_index), }); try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, tv, name); return new_decl_index; } -/// Takes ownership of `name` even if it returns an error. pub fn initNewAnonDecl( mod: *Module, new_decl_index: Decl.Index, src_line: u32, namespace: Namespace.Index, typed_value: TypedValue, - name: [:0]u8, + name: InternPool.NullTerminatedString, ) Allocator.Error!void { assert(typed_value.ty.toIntern() == mod.intern_pool.typeOf(typed_value.val.toIntern())); - errdefer mod.gpa.free(name); const new_decl = mod.declPtr(new_decl_index); @@ -5900,7 +5798,7 @@ pub fn initNewAnonDecl( new_decl.ty = typed_value.ty; new_decl.val = typed_value.val; new_decl.@"align" = 0; - new_decl.@"linksection" = null; + new_decl.@"linksection" = .none; new_decl.has_tv = true; new_decl.analysis = .complete; new_decl.generation = mod.generation; @@ -6330,12 +6228,11 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { // deletion set at this time. for (file.deleted_decls.items) |decl_index| { const decl = mod.declPtr(decl_index); - log.debug("deleted from source: {*} ({s})", .{ decl, decl.name }); // Remove from the namespace it resides in, preserving declaration order. assert(decl.zir_decl_index != 0); _ = mod.namespacePtr(decl.src_namespace).decls.orderedRemoveAdapted( - @as([]const u8, mem.sliceTo(decl.name, 0)), + decl.name, DeclAdapter{ .mod = mod }, ); @@ -6357,7 +6254,7 @@ pub fn processOutdatedAndDeletedDecls(mod: *Module) !void { pub fn processExports(mod: *Module) !void { const gpa = mod.gpa; // Map symbol names to `Export` for name collision detection. - var symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}; + var symbol_exports: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export) = .{}; defer symbol_exports.deinit(gpa); var it = mod.decl_exports.iterator(); @@ -6365,13 +6262,13 @@ pub fn processExports(mod: *Module) !void { const exported_decl = entry.key_ptr.*; const exports = entry.value_ptr.items; for (exports) |new_export| { - const gop = try symbol_exports.getOrPut(gpa, new_export.options.name); + const gop = try symbol_exports.getOrPut(gpa, new_export.name); if (gop.found_existing) { new_export.status = .failed_retryable; try mod.failed_exports.ensureUnusedCapacity(gpa, 1); const src_loc = new_export.getSrcLoc(mod); const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {s}", .{ - new_export.options.name, + mod.intern_pool.stringToSlice(new_export.name), }); errdefer msg.destroy(gpa); const other_export = gop.value_ptr.*; @@ -6408,8 +6305,9 @@ pub fn populateTestFunctions( const builtin_file = (mod.importPkg(builtin_pkg) catch unreachable).file; const root_decl = mod.declPtr(builtin_file.root_decl.unwrap().?); const builtin_namespace = mod.namespacePtr(root_decl.src_namespace); + const test_functions_str = try mod.intern_pool.getOrPutString(gpa, "test_functions"); const decl_index = builtin_namespace.decls.getKeyAdapted( - @as([]const u8, "test_functions"), + test_functions_str, DeclAdapter{ .mod = mod }, ).?; { @@ -6443,7 +6341,7 @@ pub fn populateTestFunctions( for (test_fn_vals, mod.test_functions.keys()) |*test_fn_val, test_decl_index| { const test_decl = mod.declPtr(test_decl_index); - const test_decl_name = mem.span(test_decl.name); + const test_decl_name = mod.intern_pool.stringToSlice(test_decl.name); const test_name_decl_index = n: { const test_name_decl_ty = try mod.arrayType(.{ .len = test_decl_name.len, @@ -7156,7 +7054,7 @@ pub fn opaqueSrcLoc(mod: *Module, opaque_type: InternPool.Key.OpaqueType) SrcLoc return mod.declPtr(opaque_type.decl).srcLoc(mod); } -pub fn opaqueFullyQualifiedName(mod: *Module, opaque_type: InternPool.Key.OpaqueType) ![:0]u8 { +pub fn opaqueFullyQualifiedName(mod: *Module, opaque_type: InternPool.Key.OpaqueType) !InternPool.NullTerminatedString { return mod.declPtr(opaque_type.decl).getFullyQualifiedName(mod); } diff --git a/src/Sema.zig b/src/Sema.zig index 620a8a6a28a3763dd394c73ea69b2ef88991520e..da8878ed4d59886d1ea8e6a6ef25fde53867b50e 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -11,9 +11,6 @@ gpa: Allocator, /// Points to the temporary arena allocator of the Sema. /// This arena will be cleared when the sema is destroyed. arena: Allocator, -/// Points to the arena allocator for the owner_decl. -/// This arena will persist until the decl is invalidated. -perm_arena: Allocator, code: Zir, air_instructions: std.MultiArrayList(Air.Inst) = .{}, air_extra: std.ArrayListUnmanaged(u32) = .{}, @@ -740,7 +737,6 @@ pub const Block = struct { // TODO: migrate Decl alignment to use `InternPool.Alignment` new_decl.@"align" = @intCast(u32, alignment); errdefer sema.mod.abortAnonDecl(new_decl_index); - try new_decl.finalizeNewArena(&wad.new_decl_arena); wad.finished = true; try sema.mod.finalizeAnonDecl(new_decl_index); return new_decl_index; @@ -1825,6 +1821,20 @@ pub fn resolveConstString( return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod); } +pub fn resolveConstStringIntern( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + zir_ref: Zir.Inst.Ref, + reason: []const u8, +) !InternPool.NullTerminatedString { + const air_inst = try sema.resolveInst(zir_ref); + const wanted_type = Type.slice_const_u8; + const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src); + const val = try sema.resolveConstValue(block, src, coerced_inst, reason); + return val.toIpString(wanted_type, sema.mod); +} + pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type { const air_inst = try sema.resolveInst(zir_ref); assert(air_inst != .var_args_param_type); @@ -1847,11 +1857,13 @@ fn analyzeAsType( pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; if (!mod.backendSupportsFeature(.error_return_trace)) return; assert(!block.is_comptime); var err_trace_block = block.makeSubBlock(); - defer err_trace_block.instructions.deinit(sema.gpa); + defer err_trace_block.instructions.deinit(gpa); const src: LazySrcLoc = .unneeded; @@ -1866,17 +1878,19 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty)); // st.instruction_addresses = &addrs; - const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true); + const instruction_addresses_field_name = try ip.getOrPutString(gpa, "instruction_addresses"); + const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, instruction_addresses_field_name, src, true); try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store); // st.index = 0; - const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true); + const index_field_name = try ip.getOrPutString(gpa, "index"); + const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, index_field_name, src, true); try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store); // @errorReturnTrace() = &st; _ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr); - try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items); + try block.instructions.insertSlice(gpa, last_arg_index, err_trace_block.instructions.items); } /// May return Value Tags: `variable`, `undef`. @@ -2179,7 +2193,13 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError return sema.failWithOwnedErrorMsg(msg); } -fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError { +fn failWithInvalidFieldAccess( + sema: *Sema, + block: *Block, + src: LazySrcLoc, + object_ty: Type, + field_name: InternPool.NullTerminatedString, +) CompileError { const mod = sema.mod; const inner_ty = if (object_ty.isSinglePointer(mod)) object_ty.childType(mod) else object_ty; @@ -2207,15 +2227,16 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)}); } -fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: []const u8) bool { +fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: InternPool.NullTerminatedString) bool { + const ip = &mod.intern_pool; switch (ty.zigTypeTag(mod)) { - .Array => return mem.eql(u8, field_name, "len"), + .Array => return ip.stringEqlSlice(field_name, "len"), .Pointer => { const ptr_info = ty.ptrInfo(mod); if (ptr_info.size == .Slice) { - return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len"); + return ip.stringEqlSlice(field_name, "ptr") or ip.stringEqlSlice(field_name, "len"); } else if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) { - return mem.eql(u8, field_name, "len"); + return ip.stringEqlSlice(field_name, "len"); } else return false; }, .Type, .Struct, .Union => return true, @@ -2308,19 +2329,19 @@ pub fn fail( fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { @setCold(true); const gpa = sema.gpa; + const mod = sema.mod; - if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) { + if (crash_report.is_enabled and mod.comp.debug_compile_errors) { if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation; var wip_errors: std.zig.ErrorBundle.Wip = undefined; wip_errors.init(gpa) catch unreachable; - Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable; + Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*) catch unreachable; std.debug.print("compile error during Sema:\n", .{}); var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); crash_report.compilerPanic("unexpected compile error occurred", null, null); } - const mod = sema.mod; ref: { errdefer err_msg.destroy(gpa); if (err_msg.src_loc.lazy == .unneeded) { @@ -2330,9 +2351,9 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { try mod.failed_files.ensureUnusedCapacity(gpa, 1); const max_references = blk: { - if (sema.mod.comp.reference_trace) |num| break :blk num; + if (mod.comp.reference_trace) |num| break :blk num; // Do not add multiple traces without explicit request. - if (sema.mod.failed_decls.count() != 0) break :ref; + if (mod.failed_decls.count() != 0) break :ref; break :blk default_reference_trace_len; }; @@ -2350,13 +2371,16 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError { if (gop.found_existing) break; if (cur_reference_trace < max_references) { const decl = sema.mod.declPtr(ref.referencer); - try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl, mod) }); + try reference_stack.append(.{ + .decl = decl.name.toOptional(), + .src_loc = ref.src.toSrcLoc(decl, mod), + }); } referenced_by = ref.referencer; } if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) { try reference_stack.append(.{ - .decl = null, + .decl = .none, .src_loc = undefined, .hidden = 0, }); @@ -2795,7 +2819,6 @@ fn zirStructDecl( new_namespace.ty = struct_ty.toType(); try sema.analyzeStructDecl(new_decl, inst, struct_index); - try new_decl.finalizeNewArena(&new_decl_arena); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); return decl_val; @@ -2812,6 +2835,7 @@ fn createAnonymousDeclTypeNamed( ) !Decl.Index { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; const namespace = block.namespace; const src_scope = block.wip_capture_scope; const src_decl = mod.declPtr(block.src_decl); @@ -2827,16 +2851,19 @@ fn createAnonymousDeclTypeNamed( // semantically analyzed. // This name is also used as the key in the parent namespace so it cannot be // renamed. - const name = try std.fmt.allocPrintZ(gpa, "{s}__{s}_{d}", .{ - src_decl.name, anon_prefix, @enumToInt(new_decl_index), - }); - errdefer gpa.free(name); + + // This ensureUnusedCapacity protects against the src_decl slice from being + // reallocated during the call to `getOrPutStringFmt`. + try ip.string_bytes.ensureUnusedCapacity(gpa, ip.stringToSlice(src_decl.name).len + + anon_prefix.len + 20); + const name = ip.getOrPutStringFmt(gpa, "{s}__{s}_{d}", .{ + ip.stringToSlice(src_decl.name), anon_prefix, @enumToInt(new_decl_index), + }) catch unreachable; try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); return new_decl_index; }, .parent => { - const name = try gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); - errdefer gpa.free(name); + const name = mod.declPtr(block.src_decl).name; try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); return new_decl_index; }, @@ -2846,7 +2873,7 @@ fn createAnonymousDeclTypeNamed( var buf = std.ArrayList(u8).init(gpa); defer buf.deinit(); - try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0)); + try buf.appendSlice(ip.stringToSlice(mod.declPtr(block.src_decl).name)); try buf.appendSlice("("); var arg_i: usize = 0; @@ -2871,8 +2898,7 @@ fn createAnonymousDeclTypeNamed( }; try buf.appendSlice(")"); - const name = try buf.toOwnedSliceSentinel(0); - errdefer gpa.free(name); + const name = try ip.getOrPutString(gpa, buf.items); try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); return new_decl_index; }, @@ -2885,10 +2911,17 @@ fn createAnonymousDeclTypeNamed( .dbg_var_ptr, .dbg_var_val => { if (zir_data[i].str_op.operand != ref) continue; - const name = try std.fmt.allocPrintZ(gpa, "{s}.{s}", .{ - src_decl.name, zir_data[i].str_op.getStr(sema.code), - }); - errdefer gpa.free(name); + // This ensureUnusedCapacity protects against the src_decl + // slice from being reallocated during the call to + // `getOrPutStringFmt`. + const zir_str = zir_data[i].str_op.getStr(sema.code); + try ip.string_bytes.ensureUnusedCapacity( + gpa, + ip.stringToSlice(src_decl.name).len + zir_str.len + 10, + ); + const name = ip.getOrPutStringFmt(gpa, "{s}.{s}", .{ + ip.stringToSlice(src_decl.name), zir_str, + }) catch unreachable; try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name); return new_decl_index; @@ -3249,7 +3282,6 @@ fn zirUnionDecl( _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); - try new_decl.finalizeNewArena(&new_decl_arena); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); return decl_val; @@ -3315,7 +3347,6 @@ fn zirOpaqueDecl( extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl); - try new_decl.finalizeNewArena(&new_decl_arena); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); return decl_val; @@ -3344,8 +3375,8 @@ fn zirErrorSetDecl( while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string const str_index = sema.code.extra[extra_index]; const name = sema.code.nullTerminatedString(str_index); - const kv = try mod.getErrorValue(name); - const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key); + const name_ip = try mod.intern_pool.getOrPutString(gpa, name); + _ = try mod.getErrorValue(name_ip); const result = names.getOrPutAssumeCapacity(name_ip); assert(!result.found_existing); // verified in AstGen } @@ -3512,7 +3543,8 @@ fn indexablePtrLen( const is_pointer_to = object_ty.isSinglePointer(mod); const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty; try checkIndexable(sema, block, src, indexable_ty); - return sema.fieldVal(block, src, object, "len", src); + const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len"); + return sema.fieldVal(block, src, object, field_name, src); } fn indexablePtrLenOrNone( @@ -3525,7 +3557,8 @@ fn indexablePtrLenOrNone( const operand_ty = sema.typeOf(operand); try checkMemOperand(sema, block, src, operand_ty); if (operand_ty.ptrSize(mod) == .Many) return .none; - return sema.fieldVal(block, src, operand, "len", src); + const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len"); + return sema.fieldVal(block, src, operand, field_name, src); } fn zirAllocExtended( @@ -4079,6 +4112,7 @@ fn zirFieldBasePtr( fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); const args = sema.code.refSlice(extra.end, extra.data.operands_len); @@ -4122,7 +4156,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. } if (!object_ty.indexableHasLen(mod)) continue; - break :l try sema.fieldVal(block, arg_src, object, "len", arg_src); + break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, "len"), arg_src); }; const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src); if (len == .none) { @@ -4308,6 +4342,7 @@ fn validateUnionInit( union_ptr: Air.Inst.Ref, ) CompileError!void { const mod = sema.mod; + const gpa = sema.gpa; if (instrs.len != 1) { const msg = msg: { @@ -4317,7 +4352,7 @@ fn validateUnionInit( "cannot initialize multiple union fields at once; unions can only have one active field", .{}, ); - errdefer msg.destroy(sema.gpa); + errdefer msg.destroy(gpa); for (instrs[1..]) |inst| { const inst_data = sema.code.instructions.items(.data)[inst].pl_node; @@ -4341,7 +4376,7 @@ fn validateUnionInit( const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node; const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; - const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); + const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_ptr_extra.field_name_start)); // Validate the field access but ignore the index since we want the tag enum field index. _ = try sema.unionFieldIndex(block, union_ty, field_name, field_src); const air_tags = sema.air_instructions.items(.tag); @@ -4444,6 +4479,7 @@ fn validateStructInit( ) CompileError!void { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; // Maps field index to field_ptr index of where it was already initialized. const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount(mod)); @@ -4457,7 +4493,10 @@ fn validateStructInit( const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node }; const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; struct_ptr_zir_ref = field_ptr_extra.lhs; - const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start); + const field_name = try ip.getOrPutString( + gpa, + sema.code.nullTerminatedString(field_ptr_extra.field_name_start), + ); const field_index = if (struct_ty.isTuple(mod)) try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) else @@ -4504,7 +4543,7 @@ fn validateStructInit( } const field_name = struct_ty.structFieldName(i, mod); const template = "missing struct field: {s}"; - const args = .{field_name}; + const args = .{ip.stringToSlice(field_name)}; if (root_msg) |msg| { try sema.errNote(block, init_src, msg, template, args); } else { @@ -4525,8 +4564,7 @@ fn validateStructInit( if (root_msg) |msg| { if (mod.typeToStruct(struct_ty)) |struct_obj| { - const fqn = try struct_obj.getFullyQualifiedName(mod); - defer gpa.free(fqn); + const fqn = ip.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); try mod.errNoteNonLazy( struct_obj.srcLoc(mod), msg, @@ -4649,7 +4687,7 @@ fn validateStructInit( } const field_name = struct_ty.structFieldName(i, mod); const template = "missing struct field: {s}"; - const args = .{field_name}; + const args = .{ip.stringToSlice(field_name)}; if (root_msg) |msg| { try sema.errNote(block, init_src, msg, template, args); } else { @@ -4662,10 +4700,9 @@ fn validateStructInit( if (root_msg) |msg| { if (mod.typeToStruct(struct_ty)) |struct_obj| { - const fqn = try struct_obj.getFullyQualifiedName(sema.mod); - defer gpa.free(fqn); + const fqn = ip.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); try sema.mod.errNoteNonLazy( - struct_obj.srcLoc(sema.mod), + struct_obj.srcLoc(mod), msg, "struct '{s}' declared here", .{fqn}, @@ -4949,7 +4986,7 @@ fn failWithBadMemberAccess( block: *Block, agg_ty: Type, field_src: LazySrcLoc, - field_name: []const u8, + field_name_nts: InternPool.NullTerminatedString, ) CompileError { const mod = sema.mod; const kw_name = switch (agg_ty.zigTypeTag(mod)) { @@ -4959,6 +4996,7 @@ fn failWithBadMemberAccess( .Enum => "enum", else => unreachable, }; + const field_name = mod.intern_pool.stringToSlice(field_name_nts); if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (sema.mod.declIsRoot(some)) { return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{ agg_ty.fmt(sema.mod), field_name, @@ -4980,22 +5018,23 @@ fn failWithBadStructFieldAccess( block: *Block, struct_obj: *Module.Struct, field_src: LazySrcLoc, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, ) CompileError { + const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; - const fqn = try struct_obj.getFullyQualifiedName(sema.mod); - defer gpa.free(fqn); + const fqn = ip.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); const msg = msg: { const msg = try sema.errMsg( block, field_src, "no field named '{s}' in struct '{s}'", - .{ field_name, fqn }, + .{ ip.stringToSlice(field_name), fqn }, ); errdefer msg.destroy(gpa); - try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{}); + try mod.errNoteNonLazy(struct_obj.srcLoc(mod), msg, "struct declared here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -5006,22 +5045,23 @@ fn failWithBadUnionFieldAccess( block: *Block, union_obj: *Module.Union, field_src: LazySrcLoc, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, ) CompileError { + const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; - const fqn = try union_obj.getFullyQualifiedName(sema.mod); - defer gpa.free(fqn); + const fqn = ip.stringToSlice(try union_obj.getFullyQualifiedName(mod)); const msg = msg: { const msg = try sema.errMsg( block, field_src, "no field named '{s}' in union '{s}'", - .{ field_name, fqn }, + .{ ip.stringToSlice(field_name), fqn }, ); errdefer msg.destroy(gpa); - try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{}); + try mod.errNoteNonLazy(union_obj.srcLoc(mod), msg, "union declared here", .{}); break :msg msg; }; return sema.failWithOwnedErrorMsg(msg); @@ -5772,7 +5812,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const src = inst_data.src(); const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; - const decl_name = sema.code.nullTerminatedString(extra.decl_name); + const decl_name = try mod.intern_pool.getOrPutString(mod.gpa, sema.code.nullTerminatedString(extra.decl_name)); const decl_index = if (extra.namespace != .none) index_blk: { const container_ty = try sema.resolveType(block, operand_src, extra.namespace); const container_namespace = container_ty.getNamespaceIndex(mod).unwrap().?; @@ -5875,19 +5915,14 @@ pub fn analyzeExport( const new_export = try gpa.create(Export); errdefer gpa.destroy(new_export); - const symbol_name = try gpa.dupe(u8, borrowed_options.name); - errdefer gpa.free(symbol_name); - - const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null; - errdefer if (section) |s| gpa.free(s); + const symbol_name = try mod.intern_pool.getOrPutString(gpa, borrowed_options.name); + const section = try mod.intern_pool.getOrPutStringOpt(gpa, borrowed_options.section); new_export.* = .{ - .options = .{ - .name = symbol_name, - .linkage = borrowed_options.linkage, - .section = section, - .visibility = borrowed_options.visibility, - }, + .name = symbol_name, + .linkage = borrowed_options.linkage, + .section = section, + .visibility = borrowed_options.visibility, .src = src, .owner_decl = sema.owner_decl_index, .src_decl = block.src_decl, @@ -6121,23 +6156,25 @@ fn addDbgVar( } fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; const src = inst_data.src(); - const decl_name = inst_data.get(sema.code); + const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); const decl_index = try sema.lookupIdentifier(block, src, decl_name); try sema.addReferencedBy(block, src, decl_index); return sema.analyzeDeclRef(decl_index); } fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; const src = inst_data.src(); - const decl_name = inst_data.get(sema.code); + const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); const decl = try sema.lookupIdentifier(block, src, decl_name); return sema.analyzeDeclVal(block, src, decl); } -fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index { +fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPool.NullTerminatedString) !Decl.Index { const mod = sema.mod; var namespace = block.namespace; while (true) { @@ -6156,7 +6193,7 @@ fn lookupInNamespace( block: *Block, src: LazySrcLoc, namespace_index: Namespace.Index, - ident_name: []const u8, + ident_name: InternPool.NullTerminatedString, observe_usingnamespace: bool, ) CompileError!?Decl.Index { const mod = sema.mod; @@ -6249,9 +6286,6 @@ fn lookupInNamespace( return decl_index; } - log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{ - sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name, - }); // TODO This dependency is too strong. Really, it should only be a dependency // on the non-existence of `ident_name` in the namespace. We can lessen the number of // outdated declarations by making this dependency more sophisticated. @@ -6276,10 +6310,12 @@ fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl { } pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { + const mod = sema.mod; + const gpa = sema.gpa; const src = sema.src; - if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none; - if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none; + if (!mod.backendSupportsFeature(.error_return_trace)) return .none; + if (!mod.comp.bin_file.options.error_return_tracing) return .none; if (block.is_comptime) return .none; @@ -6292,7 +6328,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, else => |e| return e, }; - const field_index = sema.structFieldIndex(block, stack_trace_ty, "index", src) catch |err| switch (err) { + const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); + const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, src) catch |err| switch (err) { error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable, else => |e| return e, }; @@ -6316,6 +6353,7 @@ fn popErrorReturnTrace( saved_error_trace_index: Air.Inst.Ref, ) CompileError!void { const mod = sema.mod; + const gpa = sema.gpa; var is_non_error: ?bool = null; var is_non_error_inst: Air.Inst.Ref = undefined; if (operand != .none) { @@ -6332,13 +6370,14 @@ fn popErrorReturnTrace( const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); - const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true); + const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); + const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true); try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); } else if (is_non_error == null) { // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need // to pop any error trace that may have been propagated from our arguments. - try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len); + try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len); const cond_block_inst = try block.addInstAsIndex(.{ .tag = .block, .data = .{ @@ -6350,28 +6389,29 @@ fn popErrorReturnTrace( }); var then_block = block.makeSubBlock(); - defer then_block.instructions.deinit(sema.gpa); + defer then_block.instructions.deinit(gpa); // If non-error, then pop the error return trace by restoring the index. const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty); const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); - const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, "index", src, stack_trace_ty, true); + const field_name = try mod.intern_pool.getOrPutString(gpa, "index"); + const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true); try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); _ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); // Otherwise, do nothing var else_block = block.makeSubBlock(); - defer else_block.instructions.deinit(sema.gpa); + defer else_block.instructions.deinit(gpa); _ = try else_block.addBr(cond_block_inst, Air.Inst.Ref.void_value); - try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.CondBr).Struct.fields.len + + try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len + then_block.instructions.items.len + else_block.instructions.items.len + @typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block const cond_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len); - try sema.air_instructions.append(sema.gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{ + try sema.air_instructions.append(gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{ .operand = is_non_error_inst, .payload = sema.addExtraAssumeCapacity(Air.CondBr{ .then_body_len = @intCast(u32, then_block.instructions.items.len), @@ -6414,7 +6454,7 @@ fn zirCall( .direct => .{ .direct = try sema.resolveInst(extra.data.callee) }, .field => blk: { const object_ptr = try sema.resolveInst(extra.data.obj_ptr); - const field_name = sema.code.nullTerminatedString(extra.data.field_name_start); + const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start)); const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src); }, @@ -6509,7 +6549,8 @@ fn zirCall( if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) { const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace"); const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty); - const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", call_src); + const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index"); + const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); // Insert a save instruction before the arg resolution + call instructions we just generated const save_inst = try block.insertInst(block_index, .{ @@ -7436,9 +7477,10 @@ fn instantiateGenericCall( ) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known"); - const module_fn = mod.funcPtr(switch (mod.intern_pool.indexToKey(func_val.toIntern())) { + const module_fn = mod.funcPtr(switch (ip.indexToKey(func_val.toIntern())) { .func => |function| function.index, .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?, else => unreachable, @@ -7567,9 +7609,12 @@ fn instantiateGenericCall( const new_decl_index = try mod.allocateNewDecl(namespace_index, fn_owner_decl.src_node, src_decl.src_scope); const new_decl = mod.declPtr(new_decl_index); // TODO better names for generic function instantiations - const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{ - fn_owner_decl.name, @enumToInt(new_decl_index), - }); + // The ensureUnusedCapacity here protects against fn_owner_decl.name slice being + // reallocated during getOrPutStringFmt. + try ip.string_bytes.ensureUnusedCapacity(gpa, ip.stringToSlice(fn_owner_decl.name).len + 20); + const decl_name = ip.getOrPutStringFmt(gpa, "{s}__anon_{d}", .{ + ip.stringToSlice(fn_owner_decl.name), @enumToInt(new_decl_index), + }) catch unreachable; new_decl.name = decl_name; new_decl.src_line = fn_owner_decl.src_line; new_decl.is_pub = fn_owner_decl.is_pub; @@ -7590,12 +7635,8 @@ fn instantiateGenericCall( assert(new_decl.dependencies.keys().len == 0); try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body); - var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa); - const new_decl_arena_allocator = new_decl_arena.allocator(); - const new_func = sema.resolveGenericInstantiationType( block, - new_decl_arena_allocator, fn_zir, new_decl, new_decl_index, @@ -7608,7 +7649,6 @@ fn instantiateGenericCall( bound_arg_src, ) catch |err| switch (err) { error.GenericPoison, error.ComptimeReturn => { - new_decl_arena.deinit(); // Resolving the new function type below will possibly declare more decl dependencies // and so we remove them all here in case of error. for (new_decl.dependencies.keys()) |dep_index| { @@ -7623,10 +7663,6 @@ fn instantiateGenericCall( }, else => { assert(mod.monomorphed_funcs.removeContext(new_module_func_index, .{ .mod = mod })); - { - errdefer new_decl_arena.deinit(); - try new_decl.finalizeNewArena(&new_decl_arena); - } // TODO look up the compile error that happened here and attach a note to it // pointing here, at the generic instantiation callsite. if (sema.owner_func) |owner_func| { @@ -7637,9 +7673,7 @@ fn instantiateGenericCall( return err; }, }; - errdefer new_decl_arena.deinit(); - try new_decl.finalizeNewArena(&new_decl_arena); break :callee new_func; } else gop.key_ptr.*; const callee = mod.funcPtr(callee_index); @@ -7729,7 +7763,6 @@ fn instantiateGenericCall( fn resolveGenericInstantiationType( sema: *Sema, block: *Block, - new_decl_arena_allocator: Allocator, fn_zir: Zir, new_decl: *Decl, new_decl_index: Decl.Index, @@ -7755,7 +7788,6 @@ fn resolveGenericInstantiationType( .mod = mod, .gpa = gpa, .arena = sema.arena, - .perm_arena = new_decl_arena_allocator, .code = fn_zir, .owner_decl = new_decl, .owner_decl_index = new_decl_index, @@ -7764,7 +7796,8 @@ fn resolveGenericInstantiationType( .fn_ret_ty = Type.void, .owner_func = null, .owner_func_index = .none, - .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len), + // TODO: fully migrate functions into InternPool + .comptime_args = try mod.tmp_hack_arena.allocator().alloc(TypedValue, uncasted_args.len), .comptime_args_fn_inst = module_fn.zir_body_inst, .preallocated_new_func = new_module_func.toOptional(), .is_generic_instantiation = true, @@ -7931,10 +7964,6 @@ fn resolveGenericInstantiationType( new_decl.owns_tv = true; new_decl.analysis = .complete; - log.debug("generic function '{s}' instantiated with type {}", .{ - new_decl.name, new_decl.ty.fmtDebug(), - }); - // Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field // will be populated, ensuring it will have `analyzeBody` called with the ZIR // parameters mapped appropriately. @@ -8134,13 +8163,13 @@ fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError! _ = block; const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; - const name = inst_data.get(sema.code); + const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); + _ = try mod.getErrorValue(name); // Create an error set type with only this error value, and return the value. - const kv = try sema.mod.getErrorValue(name); - const error_set_type = try mod.singleErrorSetType(kv.key); + const error_set_type = try mod.singleErrorSetTypeNts(name); return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ .ty = error_set_type.toIntern(), - .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key), + .name = name, } })).toValue()); } @@ -8162,7 +8191,7 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat const err_name = mod.intern_pool.indexToKey(val.toIntern()).err.name; return sema.addConstant(Type.err_int, try mod.intValue( Type.err_int, - (try mod.getErrorValue(mod.intern_pool.stringToSlice(err_name))).value, + try mod.getErrorValue(err_name), )); } @@ -8173,8 +8202,8 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat switch (names.len) { 0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)), 1 => { - const name = mod.intern_pool.stringToSlice(names[0]); - return sema.addIntUnsigned(Type.err_int, mod.global_error_set.get(name).?); + const int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(names[0]).?); + return sema.addIntUnsigned(Type.err_int, int); }, else => {}, } @@ -8197,11 +8226,11 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod)); - if (int > sema.mod.global_error_set.count() or int == 0) + if (int > mod.global_error_set.count() or int == 0) return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{ .ty = .anyerror_type, - .name = mod.intern_pool.getString(sema.mod.error_name_list.items[int]).unwrap().?, + .name = mod.global_error_set.keys()[int], } })).toValue()); } try sema.requireRuntimeBlock(block, src, operand_src); @@ -8917,7 +8946,7 @@ fn handleExternLibName( const FuncLinkSection = union(enum) { generic, default, - explicit: []const u8, + explicit: InternPool.NullTerminatedString, }; fn funcCommon( @@ -9186,9 +9215,9 @@ fn funcCommon( }; sema.owner_decl.@"linksection" = switch (section) { - .generic => undefined, - .default => null, - .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name), + .generic => .none, + .default => .none, + .explicit => |section_name| section_name.toOptional(), }; sema.owner_decl.@"align" = alignment orelse 0; sema.owner_decl.@"addrspace" = address_space orelse .generic; @@ -9572,11 +9601,12 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const tracy = trace(@src()); defer tracy.end(); + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; - const field_name = sema.code.nullTerminatedString(extra.field_name_start); + const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start)); const object = try sema.resolveInst(extra.lhs); return sema.fieldVal(block, src, object, field_name, field_name_src); } @@ -9585,11 +9615,12 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b const tracy = trace(@src()); defer tracy.end(); + const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node }; const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; - const field_name = sema.code.nullTerminatedString(extra.field_name_start); + const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start)); const object_ptr = try sema.resolveInst(extra.lhs); return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing); } @@ -9603,7 +9634,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; const object = try sema.resolveInst(extra.lhs); - const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, "field name must be comptime-known"); return sema.fieldVal(block, src, object, field_name, field_name_src); } @@ -9616,7 +9647,7 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data; const object_ptr = try sema.resolveInst(extra.lhs); - const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, "field name must be comptime-known"); return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false); } @@ -10434,6 +10465,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const src = inst_data.src(); const src_node_offset = inst_data.src_node; @@ -10605,7 +10637,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError i, msg, "unhandled enumeration value: '{s}'", - .{field_name}, + .{ip.stringToSlice(field_name)}, ); } try mod.errNoteNonLazy( @@ -10689,7 +10721,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa); for (operand_ty.errorSetNames(mod)) |error_name_ip| { - const error_name = mod.intern_pool.stringToSlice(error_name_ip); + const error_name = ip.stringToSlice(error_name_ip); if (!seen_errors.contains(error_name) and special_prong != .@"else") { const msg = maybe_msg orelse blk: { maybe_msg = try sema.errMsg( @@ -10758,7 +10790,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError var names: Module.Fn.InferredErrorSet.NameMap = .{}; try names.ensureUnusedCapacity(sema.arena, error_names.len); for (error_names) |error_name_ip| { - const error_name = mod.intern_pool.stringToSlice(error_name_ip); + const error_name = ip.stringToSlice(error_name_ip); if (seen_errors.contains(error_name)) continue; names.putAssumeCapacityNoClobber(error_name_ip, {}); @@ -12062,7 +12094,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs); - const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, "field name must be comptime-known"); const ty = try sema.resolveTypeFields(unresolved_ty); const ip = &mod.intern_pool; @@ -12070,19 +12102,17 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai switch (ip.indexToKey(ty.toIntern())) { .ptr_type => |ptr_type| switch (ptr_type.flags.size) { .Slice => { - if (mem.eql(u8, field_name, "ptr")) break :hf true; - if (mem.eql(u8, field_name, "len")) break :hf true; + if (ip.stringEqlSlice(field_name, "ptr")) break :hf true; + if (ip.stringEqlSlice(field_name, "len")) break :hf true; break :hf false; }, else => {}, }, .anon_struct_type => |anon_struct| { if (anon_struct.names.len != 0) { - // If the string is not interned, then the field certainly is not present. - const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; - break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, name_interned) != null; + break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, field_name) != null; } else { - const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false; + const field_index = std.fmt.parseUnsigned(u32, ip.stringToSlice(field_name), 10) catch break :hf false; break :hf field_index < ty.structFieldCount(mod); } }, @@ -12097,11 +12127,9 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai break :hf union_obj.fields.contains(field_name); }, .enum_type => |enum_type| { - // If the string is not interned, then the field certainly is not present. - const name_interned = ip.getString(field_name).unwrap() orelse break :hf false; - break :hf enum_type.nameIndex(ip, name_interned) != null; + break :hf enum_type.nameIndex(ip, field_name) != null; }, - .array_type => break :hf mem.eql(u8, field_name, "len"), + .array_type => break :hf ip.stringEqlSlice(field_name, "len"), else => {}, } return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{ @@ -12123,7 +12151,7 @@ fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node }; const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node }; const container_type = try sema.resolveType(block, lhs_src, extra.lhs); - const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime-known"); + const decl_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "decl name must be comptime-known"); try sema.checkNamespaceType(block, lhs_src, container_type); @@ -12218,14 +12246,12 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; - const err_name = inst_data.get(sema.code); - - // Return the error code from the function. - const kv = try mod.getErrorValue(err_name); - const error_set_type = try mod.singleErrorSetType(kv.key); + const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); + _ = try mod.getErrorValue(name); + const error_set_type = try mod.singleErrorSetTypeNts(name); return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ .ty = error_set_type.toIntern(), - .name = mod.intern_pool.getString(kv.key).unwrap().?, + .name = name, } })).toValue()); } @@ -15730,12 +15756,7 @@ fn zirThis( return sema.analyzeDeclVal(block, src, this_decl_index); } -fn zirClosureCapture( - sema: *Sema, - block: *Block, - inst: Zir.Inst.Index, -) CompileError!void { - // TODO: Compile error when closed over values are modified +fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const inst_data = sema.code.instructions.items(.data)[inst].un_tok; // Closures are not necessarily constant values. For example, the // code might do something like this: @@ -15754,13 +15775,8 @@ fn zirClosureCapture( try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, capture); } -fn zirClosureGet( - sema: *Sema, - block: *Block, - inst: Zir.Inst.Index, -) CompileError!Air.Inst.Ref { +fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; - // TODO CLOSURE: Test this with inline functions const inst_data = sema.code.instructions.items(.data)[inst].inst_node; var scope: *CaptureScope = mod.declPtr(block.src_decl).src_scope.?; // Note: The target closure must be in this scope list. @@ -15896,7 +15912,7 @@ fn zirBuiltinSrc( const func_name_val = blk: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); - const name = mem.span(fn_owner_decl.name); + const name = mod.intern_pool.stringToSlice(fn_owner_decl.name); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, @@ -15965,6 +15981,7 @@ fn zirBuiltinSrc( fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; const inst_data = sema.code.instructions.items(.data)[inst].un_node; const src = inst_data.src(); const ty = try sema.resolveType(block, src, inst_data.operand); @@ -15995,7 +16012,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Fn", + try ip.getOrPutString(gpa, "Fn"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index); try sema.ensureDeclAnalyzed(fn_info_decl_index); @@ -16006,7 +16023,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, fn_info_ty.getNamespaceIndex(mod).unwrap().?, - "Param", + try ip.getOrPutString(gpa, "Param"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index); try sema.ensureDeclAnalyzed(param_info_decl_index); @@ -16018,8 +16035,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const info = mod.typeToFunc(ty).?; const param_ty = info.param_types[i]; const is_generic = param_ty == .generic_poison_type; - const param_ty_val = try mod.intern_pool.get(gpa, .{ .opt = .{ - .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }), + const param_ty_val = try ip.get(gpa, .{ .opt = .{ + .ty = try ip.get(gpa, .{ .opt_type = .type_type }), .val = if (is_generic) .none else param_ty, } }); @@ -16070,7 +16087,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const info = mod.typeToFunc(ty).?; const ret_ty_opt = try mod.intern(.{ .opt = .{ - .ty = try mod.intern_pool.get(gpa, .{ .opt_type = .type_type }), + .ty = try ip.get(gpa, .{ .opt_type = .type_type }), .val = if (info.return_type == .generic_poison_type) .none else info.return_type, } }); @@ -16104,7 +16121,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Int", + try ip.getOrPutString(gpa, "Int"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, int_info_decl_index); try sema.ensureDeclAnalyzed(int_info_decl_index); @@ -16133,7 +16150,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Float", + try ip.getOrPutString(gpa, "Float"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index); try sema.ensureDeclAnalyzed(float_info_decl_index); @@ -16166,7 +16183,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, - "Pointer", + try ip.getOrPutString(gpa, "Pointer"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, decl_index); try sema.ensureDeclAnalyzed(decl_index); @@ -16178,7 +16195,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, pointer_ty.getNamespaceIndex(mod).unwrap().?, - "Size", + try ip.getOrPutString(gpa, "Size"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, decl_index); try sema.ensureDeclAnalyzed(decl_index); @@ -16219,7 +16236,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Array", + try ip.getOrPutString(gpa, "Array"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, array_field_ty_decl_index); try sema.ensureDeclAnalyzed(array_field_ty_decl_index); @@ -16251,7 +16268,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Vector", + try ip.getOrPutString(gpa, "Vector"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, vector_field_ty_decl_index); try sema.ensureDeclAnalyzed(vector_field_ty_decl_index); @@ -16281,7 +16298,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Optional", + try ip.getOrPutString(gpa, "Optional"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, optional_field_ty_decl_index); try sema.ensureDeclAnalyzed(optional_field_ty_decl_index); @@ -16312,7 +16329,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Error", + try ip.getOrPutString(gpa, "Error"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index); try sema.ensureDeclAnalyzed(set_field_ty_decl_index); @@ -16332,7 +16349,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const names = ty.errorSetNames(mod); const vals = try sema.arena.alloc(InternPool.Index, names.len); for (vals, names) |*field_val, name_ip| { - const name = mod.intern_pool.stringToSlice(name_ip); + const name = ip.stringToSlice(name_ip); const name_val = v: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); @@ -16415,7 +16432,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "ErrorUnion", + try ip.getOrPutString(gpa, "ErrorUnion"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index); try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index); @@ -16440,7 +16457,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }, .Enum => { // TODO: look into memoizing this result. - const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type; + const enum_type = ip.indexToKey(ty.toIntern()).enum_type; const is_exhaustive = Value.makeBool(enum_type.tag_mode != .nonexhaustive); @@ -16452,7 +16469,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "EnumField", + try ip.getOrPutString(gpa, "EnumField"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index); try sema.ensureDeclAnalyzed(enum_field_ty_decl_index); @@ -16462,8 +16479,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_type.names.len); for (enum_field_vals, 0..) |*field_val, i| { - const name_ip = mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names[i]; - const name = mod.intern_pool.stringToSlice(name_ip); + const name_ip = ip.indexToKey(ty.toIntern()).enum_type.names[i]; + const name = ip.stringToSlice(name_ip); const name_val = v: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); @@ -16532,7 +16549,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Enum", + try ip.getOrPutString(gpa, "Enum"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, type_enum_ty_decl_index); try sema.ensureDeclAnalyzed(type_enum_ty_decl_index); @@ -16570,7 +16587,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Union", + try ip.getOrPutString(gpa, "Union"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, type_union_ty_decl_index); try sema.ensureDeclAnalyzed(type_union_ty_decl_index); @@ -16583,7 +16600,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "UnionField", + try ip.getOrPutString(gpa, "UnionField"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index); try sema.ensureDeclAnalyzed(union_field_ty_decl_index); @@ -16601,7 +16618,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai for (union_field_vals, 0..) |*field_val, i| { const field = union_fields.values()[i]; - const name = union_fields.keys()[i]; + const name = ip.stringToSlice(union_fields.keys()[i]); const name_val = v: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); @@ -16682,7 +16699,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, - "ContainerLayout", + try ip.getOrPutString(gpa, "ContainerLayout"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, decl_index); try sema.ensureDeclAnalyzed(decl_index); @@ -16721,7 +16738,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Struct", + try ip.getOrPutString(gpa, "Struct"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index); try sema.ensureDeclAnalyzed(type_struct_ty_decl_index); @@ -16734,7 +16751,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "StructField", + try ip.getOrPutString(gpa, "StructField"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index); try sema.ensureDeclAnalyzed(struct_field_ty_decl_index); @@ -16749,11 +16766,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai var struct_field_vals: []InternPool.Index = &.{}; defer gpa.free(struct_field_vals); fv: { - const struct_type = switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { + const struct_type = switch (ip.indexToKey(struct_ty.toIntern())) { .anon_struct_type => |tuple| { struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len); for (struct_field_vals, 0..) |*struct_field_val, i| { - const anon_struct_type = mod.intern_pool.indexToKey(struct_ty.toIntern()).anon_struct_type; + const anon_struct_type = ip.indexToKey(struct_ty.toIntern()).anon_struct_type; const field_ty = anon_struct_type.types[i]; const field_val = anon_struct_type.values[i]; const name_val = v: { @@ -16761,7 +16778,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai defer anon_decl.deinit(); const bytes = if (tuple.names.len != 0) // https://github.com/ziglang/zig/issues/15709 - @as([]const u8, mod.intern_pool.stringToSlice(tuple.names[i])) + @as([]const u8, ip.stringToSlice(tuple.names[i])) else try std.fmt.allocPrint(sema.arena, "{d}", .{i}); const new_decl_ty = try mod.arrayType(.{ @@ -16815,7 +16832,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai struct_field_vals, struct_obj.fields.keys(), struct_obj.fields.values(), - ) |*field_val, name, field| { + ) |*field_val, name_nts, field| { + const name = ip.stringToSlice(name_nts); const name_val = v: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); @@ -16838,10 +16856,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai } }); }; - const opt_default_val = if (field.default_val.toIntern() == .unreachable_value) + const opt_default_val = if (field.default_val == .none) null else - field.default_val; + field.default_val.toValue(); const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val); const alignment = field.alignment(mod, layout); @@ -16908,7 +16926,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?, - "ContainerLayout", + try ip.getOrPutString(gpa, "ContainerLayout"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, decl_index); try sema.ensureDeclAnalyzed(decl_index); @@ -16945,7 +16963,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Opaque", + try ip.getOrPutString(gpa, "Opaque"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, type_opaque_ty_decl_index); try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index); @@ -16982,6 +17000,8 @@ fn typeInfoDecls( opt_namespace: Module.Namespace.OptionalIndex, ) CompileError!InternPool.Index { const mod = sema.mod; + const gpa = sema.gpa; + var decls_anon_decl = try block.startAnonDecl(); defer decls_anon_decl.deinit(); @@ -16990,7 +17010,7 @@ fn typeInfoDecls( block, src, type_info_ty.getNamespaceIndex(mod).unwrap().?, - "Declaration", + try mod.intern_pool.getOrPutString(gpa, "Declaration"), )).?; try mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index); try sema.ensureDeclAnalyzed(declaration_ty_decl_index); @@ -16999,10 +17019,10 @@ fn typeInfoDecls( }; try sema.queueFullTypeResolution(declaration_ty); - var decl_vals = std.ArrayList(InternPool.Index).init(sema.gpa); + var decl_vals = std.ArrayList(InternPool.Index).init(gpa); defer decl_vals.deinit(); - var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa); + var seen_namespaces = std.AutoHashMap(*Namespace, void).init(gpa); defer seen_namespaces.deinit(); if (opt_namespace.unwrap()) |namespace_index| { @@ -17061,7 +17081,7 @@ fn typeInfoNamespaceDecls( const name_val = v: { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); - const name = mem.span(decl.name); + const name = mod.intern_pool.stringToSlice(decl.name); const new_decl_ty = try mod.arrayType(.{ .len = name.len, .child = .u8_type, @@ -17696,15 +17716,14 @@ fn zirRetErrValue( ) CompileError!Zir.Inst.Index { const mod = sema.mod; const inst_data = sema.code.instructions.items(.data)[inst].str_tok; - const err_name = inst_data.get(sema.code); + const err_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code)); + _ = try mod.getErrorValue(err_name); const src = inst_data.src(); - // Return the error code from the function. - const kv = try mod.getErrorValue(err_name); - const error_set_type = try mod.singleErrorSetType(err_name); + const error_set_type = try mod.singleErrorSetTypeNts(err_name); const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ .ty = error_set_type.toIntern(), - .name = try mod.intern_pool.getOrPutString(sema.gpa, kv.key), + .name = err_name, } })).toValue()); return sema.analyzeRet(block, result_inst, src); } @@ -18177,7 +18196,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data; const union_ty = try sema.resolveType(block, ty_src, extra.union_type); - const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, "name of field being initialized must be comptime-known"); const init = try sema.resolveInst(extra.init); return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src); } @@ -18189,7 +18208,7 @@ fn unionInit( init_src: LazySrcLoc, union_ty: Type, union_ty_src: LazySrcLoc, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { const mod = sema.mod; @@ -18257,7 +18276,7 @@ fn zirStructInit( const field_type_data = zir_datas[item.data.field_type].pl_node; const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; - const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); + const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start)); const field_index = if (resolved_ty.isTuple(mod)) try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src) else @@ -18298,7 +18317,7 @@ fn zirStructInit( const field_type_data = zir_datas[item.data.field_type].pl_node; const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node }; const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data; - const field_name = sema.code.nullTerminatedString(field_type_extra.name_start); + const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start)); const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src); const tag_ty = resolved_ty.unionTagTypeHypothetical(mod); const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?); @@ -18347,12 +18366,12 @@ fn finishStructInit( is_ref: bool, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - const gpa = sema.gpa; + const ip = &mod.intern_pool; var root_msg: ?*Module.ErrorMsg = null; errdefer if (root_msg) |msg| msg.destroy(sema.gpa); - switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { + switch (ip.indexToKey(struct_ty.toIntern())) { .anon_struct_type => |anon_struct| { for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| { if (field_inits[i] != .none) continue; @@ -18366,9 +18385,9 @@ fn finishStructInit( root_msg = try sema.errMsg(block, init_src, template, .{i}); } } else { - const field_name = mod.intern_pool.stringToSlice(anon_struct.names[i]); + const field_name = anon_struct.names[i]; const template = "missing struct field: {s}"; - const args = .{field_name}; + const args = .{ip.stringToSlice(field_name)}; if (root_msg) |msg| { try sema.errNote(block, init_src, msg, template, args); } else { @@ -18385,17 +18404,17 @@ fn finishStructInit( for (struct_obj.fields.values(), 0..) |field, i| { if (field_inits[i] != .none) continue; - if (field.default_val.toIntern() == .unreachable_value) { + if (field.default_val == .none) { const field_name = struct_obj.fields.keys()[i]; const template = "missing struct field: {s}"; - const args = .{field_name}; + const args = .{ip.stringToSlice(field_name)}; if (root_msg) |msg| { try sema.errNote(block, init_src, msg, template, args); } else { root_msg = try sema.errMsg(block, init_src, template, args); } } else { - field_inits[i] = try sema.addConstant(field.ty, field.default_val); + field_inits[i] = try sema.addConstant(field.ty, field.default_val.toValue()); } } }, @@ -18404,10 +18423,9 @@ fn finishStructInit( if (root_msg) |msg| { if (mod.typeToStruct(struct_ty)) |struct_obj| { - const fqn = try struct_obj.getFullyQualifiedName(sema.mod); - defer gpa.free(fqn); - try sema.mod.errNoteNonLazy( - struct_obj.srcLoc(sema.mod), + const fqn = ip.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); + try mod.errNoteNonLazy( + struct_obj.srcLoc(mod), msg, "struct '{s}' declared here", .{fqn}, @@ -18826,11 +18844,13 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro const ty_src = inst_data.src(); const field_src = inst_data.src(); const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type); - const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, "field name must be comptime-known"); return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src); } fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { + const mod = sema.mod; + const ip = &mod.intern_pool; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data; const ty_src = inst_data.src(); @@ -18843,7 +18863,8 @@ fn zirFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A error.GenericPoison => return Air.Inst.Ref.generic_poison_type, else => |e| return e, }; - const field_name = sema.code.nullTerminatedString(extra.name_start); + const zir_field_name = sema.code.nullTerminatedString(extra.name_start); + const field_name = try ip.getOrPutString(sema.gpa, zir_field_name); return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src); } @@ -18851,7 +18872,7 @@ fn fieldType( sema: *Sema, block: *Block, aggregate_ty: Type, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ty_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { @@ -19050,13 +19071,14 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const operand = try sema.resolveInst(inst_data.operand); const operand_ty = sema.typeOf(operand); const mod = sema.mod; + const ip = &mod.intern_pool; try sema.resolveTypeLayout(operand_ty); const enum_ty = switch (operand_ty.zigTypeTag(mod)) { .EnumLiteral => { const val = try sema.resolveConstValue(block, .unneeded, operand, ""); - const tag_name = mod.intern_pool.indexToKey(val.toIntern()).enum_literal; - const bytes = mod.intern_pool.stringToSlice(tag_name); + const tag_name = ip.indexToKey(val.toIntern()).enum_literal; + const bytes = ip.stringToSlice(tag_name); return sema.addStrLit(block, bytes); }, .Enum => operand_ty, @@ -19089,7 +19111,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air const enum_decl = mod.declPtr(enum_decl_index); const msg = msg: { const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{ - val.fmtValue(enum_ty, sema.mod), enum_decl.name, + val.fmtValue(enum_ty, sema.mod), ip.stringToSlice(enum_decl.name), }); errdefer msg.destroy(sema.gpa); try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{}); @@ -19098,7 +19120,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air return sema.failWithOwnedErrorMsg(msg); }; const field_name = enum_ty.enumFieldName(field_index, mod); - return sema.addStrLit(block, field_name); + return sema.addStrLit(block, ip.stringToSlice(field_name)); } try sema.requireRuntimeBlock(block, src, operand_src); if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { @@ -19119,6 +19141,7 @@ fn zirReify( ) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; const name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small); const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; const src = LazySrcLoc.nodeOffset(extra.node); @@ -19127,11 +19150,10 @@ fn zirReify( const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node }; const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src); const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime-known"); - const union_val = mod.intern_pool.indexToKey(val.toIntern()).un; + const union_val = ip.indexToKey(val.toIntern()).un; const target = mod.getTarget(); if (try union_val.val.toValue().anyUndef(mod)) return sema.failWithUseOfUndef(block, src); const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag.toValue(), mod).?; - const ip = &mod.intern_pool; switch (@intToEnum(std.builtin.TypeId, tag_index)) { .Type => return Air.Inst.Ref.type_type, .Void => return Air.Inst.Ref.void_type, @@ -19145,8 +19167,14 @@ fn zirReify( .EnumLiteral => return Air.Inst.Ref.enum_literal_type, .Int => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const signedness_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("signedness").?); - const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("bits").?); + const signedness_val = try union_val.val.toValue().fieldValue( + mod, + fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?, + ); + const bits_val = try union_val.val.toValue().fieldValue( + mod, + fields.getIndex(try ip.getOrPutString(gpa, "bits")).?, + ); const signedness = mod.toEnum(std.builtin.Signedness, signedness_val); const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); @@ -19155,8 +19183,12 @@ fn zirReify( }, .Vector => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("len").?); - const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); + const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "len"), + ).?); + const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "child"), + ).?); const len = @intCast(u32, len_val.toUnsignedInt(mod)); const child_ty = child_val.toType(); @@ -19171,7 +19203,9 @@ fn zirReify( }, .Float => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("bits").?); + const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "bits"), + ).?); const bits = @intCast(u16, bits_val.toUnsignedInt(mod)); const ty = switch (bits) { @@ -19186,14 +19220,30 @@ fn zirReify( }, .Pointer => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("size").?); - const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_const").?); - const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_volatile").?); - const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("alignment").?); - const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("address_space").?); - const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); - const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_allowzero").?); - const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("sentinel").?); + const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "size"), + ).?); + const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_const"), + ).?); + const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_volatile"), + ).?); + const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "alignment"), + ).?); + const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "address_space"), + ).?); + const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "child"), + ).?); + const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_allowzero"), + ).?); + const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "sentinel"), + ).?); if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { return sema.fail(block, src, "alignment must fit in 'u32'", .{}); @@ -19279,9 +19329,15 @@ fn zirReify( }, .Array => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("len").?); - const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); - const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("sentinel").?); + const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "len"), + ).?); + const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "child"), + ).?); + const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "sentinel"), + ).?); const len = len_val.toUnsignedInt(mod); const child_ty = child_val.toType(); @@ -19298,7 +19354,9 @@ fn zirReify( }, .Optional => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("child").?); + const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "child"), + ).?); const child_ty = child_val.toType(); @@ -19307,8 +19365,12 @@ fn zirReify( }, .ErrorUnion => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("error_set").?); - const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("payload").?); + const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "error_set"), + ).?); + const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "payload"), + ).?); const error_set_ty = error_set_val.toType(); const payload_ty = payload_val.toType(); @@ -19330,14 +19392,17 @@ fn zirReify( for (0..len) |i| { const elem_val = try payload_val.elemValue(mod, i); const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); - const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); + const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "name"), + ).?); - const name_str = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); - const kv = try mod.getErrorValue(name_str); - const name_ip = try mod.intern_pool.getOrPutString(gpa, kv.key); - const gop = names.getOrPutAssumeCapacity(name_ip); + const name = try name_val.toIpString(Type.slice_const_u8, mod); + _ = try mod.getErrorValue(name); + const gop = names.getOrPutAssumeCapacity(name); if (gop.found_existing) { - return sema.fail(block, src, "duplicate error '{s}'", .{name_str}); + return sema.fail(block, src, "duplicate error '{s}'", .{ + ip.stringToSlice(name), + }); } } @@ -19346,11 +19411,21 @@ fn zirReify( }, .Struct => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("layout").?); - const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("backing_integer").?); - const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?); - const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); - const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_tuple").?); + const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "layout"), + ).?); + const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "backing_integer"), + ).?); + const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "fields"), + ).?); + const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "decls"), + ).?); + const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_tuple"), + ).?); const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val); @@ -19367,10 +19442,18 @@ fn zirReify( }, .Enum => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("tag_type").?); - const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?); - const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); - const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_exhaustive").?); + const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "tag_type"), + ).?); + const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "fields"), + ).?); + const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "decls"), + ).?); + const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_exhaustive"), + ).?); // Decls if (decls_val.sliceLen(mod) > 0) { @@ -19396,7 +19479,7 @@ fn zirReify( // Define our empty enum decl const fields_len = @intCast(u32, try sema.usizeCast(block, src, fields_val.sliceLen(mod))); - const incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{ + const incomplete_enum = try ip.getIncompleteEnum(gpa, .{ .decl = new_decl_index, .namespace = .none, .fields_len = fields_len, @@ -19407,35 +19490,36 @@ fn zirReify( .explicit, .tag_ty = int_tag_ty.toIntern(), }); - errdefer mod.intern_pool.remove(incomplete_enum.index); + errdefer ip.remove(incomplete_enum.index); new_decl.val = incomplete_enum.index.toValue(); for (0..fields_len) |field_i| { const elem_val = try fields_val.elemValue(mod, field_i); const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); - const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); - const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("value").?); + const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "name"), + ).?); + const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "value"), + ).?); - const field_name = try name_val.toAllocatedBytes( - Type.slice_const_u8, - sema.arena, - mod, - ); - const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name); + const field_name = try name_val.toIpString(Type.slice_const_u8, mod); if (!try sema.intFitsInType(value_val, int_tag_ty, null)) { // TODO: better source location return sema.fail(block, src, "field '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{ - field_name, + ip.stringToSlice(field_name), value_val.fmtValue(Type.comptime_int, mod), int_tag_ty.fmt(mod), }); } - if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name_ip)) |other_index| { + if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| { const msg = msg: { - const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name}); + const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{ + ip.stringToSlice(field_name), + }); errdefer msg.destroy(gpa); _ = other_index; // TODO: this note is incorrect try sema.errNote(block, src, msg, "other field here", .{}); @@ -19444,7 +19528,7 @@ fn zirReify( return sema.failWithOwnedErrorMsg(msg); } - if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { + if (try incomplete_enum.addFieldValue(ip, gpa, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| { const msg = msg: { const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)}); errdefer msg.destroy(gpa); @@ -19462,7 +19546,9 @@ fn zirReify( }, .Opaque => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); + const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "decls"), + ).?); // Decls if (decls_val.sliceLen(mod) > 0) { @@ -19496,22 +19582,29 @@ fn zirReify( .decl = new_decl_index, .namespace = new_namespace_index, } }); - errdefer mod.intern_pool.remove(opaque_ty); + errdefer ip.remove(opaque_ty); new_decl.val = opaque_ty.toValue(); new_namespace.ty = opaque_ty.toType(); - try new_decl.finalizeNewArena(&new_decl_arena); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); return decl_val; }, .Union => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("layout").?); - const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("tag_type").?); - const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("fields").?); - const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("decls").?); + const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "layout"), + ).?); + const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "tag_type"), + ).?); + const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "fields"), + ).?); + const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "decls"), + ).?); // Decls if (decls_val.sliceLen(mod) > 0) { @@ -19555,7 +19648,7 @@ fn zirReify( const union_obj = mod.unionPtr(union_index); errdefer mod.destroyUnion(union_index); - const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{ + const union_ty = try ip.get(gpa, .{ .union_type = .{ .index = union_index, .runtime_tag = if (!tag_type_val.isNull(mod)) .tagged @@ -19566,7 +19659,7 @@ fn zirReify( .ReleaseFast, .ReleaseSmall => .none, }, } }); - errdefer mod.intern_pool.remove(union_ty); + errdefer ip.remove(union_ty); new_decl.val = union_ty.toValue(); new_namespace.ty = union_ty.toType(); @@ -19579,7 +19672,7 @@ fn zirReify( if (tag_type_val.optionalValue(mod)) |payload_val| { union_obj.tag_ty = payload_val.toType(); - const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.toIntern())) { + const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) { .enum_type => |x| x, else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}), }; @@ -19597,26 +19690,26 @@ fn zirReify( for (0..fields_len) |i| { const elem_val = try fields_val.elemValue(mod, i); const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); - const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); - const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?); - const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?); + const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "name"), + ).?); + const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "type"), + ).?); + const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "alignment"), + ).?); - const field_name = try name_val.toAllocatedBytes( - Type.slice_const_u8, - new_decl_arena_allocator, - mod, - ); - - const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name); + const field_name = try name_val.toIpString(Type.slice_const_u8, mod); if (enum_field_names.len != 0) { - enum_field_names[i] = field_name_ip; + enum_field_names[i] = field_name; } if (explicit_enum_info) |tag_info| { - const enum_index = tag_info.nameIndex(&mod.intern_pool, field_name_ip) orelse { + const enum_index = tag_info.nameIndex(ip, field_name) orelse { const msg = msg: { - const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(mod) }); + const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ ip.stringToSlice(field_name), union_obj.tag_ty.fmt(mod) }); errdefer msg.destroy(gpa); try sema.addDeclaredHereNote(msg, union_obj.tag_ty); break :msg msg; @@ -19632,7 +19725,7 @@ fn zirReify( const gop = union_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { // TODO: better source location - return sema.fail(block, src, "duplicate union field {s}", .{field_name}); + return sema.fail(block, src, "duplicate union field {s}", .{ip.stringToSlice(field_name)}); } const field_ty = type_val.toType(); @@ -19688,7 +19781,7 @@ fn zirReify( for (tag_info.names, 0..) |field_name, field_index| { if (explicit_tags_seen[field_index]) continue; try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{ - mod.intern_pool.stringToSlice(field_name), + ip.stringToSlice(field_name), }); } try sema.addDeclaredHereNote(msg, union_obj.tag_ty); @@ -19700,19 +19793,30 @@ fn zirReify( union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null); } - try new_decl.finalizeNewArena(&new_decl_arena); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); return decl_val; }, .Fn => { const fields = ip.typeOf(union_val.val).toType().structFields(mod); - const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("calling_convention").?); - const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("alignment").?); - const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_generic").?); - const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("is_var_args").?); - const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("return_type").?); - const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex("params").?); + const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "calling_convention"), + ).?); + const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "alignment"), + ).?); + const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_generic"), + ).?); + const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "is_var_args"), + ).?); + const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "return_type"), + ).?); + const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex( + try ip.getOrPutString(gpa, "params"), + ).?); const is_generic = is_generic_val.toBool(); if (is_generic) { @@ -19746,9 +19850,15 @@ fn zirReify( for (param_types, 0..) |*param_type, i| { const elem_val = try params_val.elemValue(mod, i); const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); - const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_generic").?); - const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_noalias").?); - const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?); + const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "is_generic"), + ).?); + const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "is_noalias"), + ).?); + const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "type"), + ).?); if (param_is_generic_val.toBool()) { return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{}); @@ -19801,6 +19911,7 @@ fn reifyStruct( ) CompileError!Air.Inst.Ref { const mod = sema.mod; const gpa = sema.gpa; + const ip = &mod.intern_pool; var new_decl_arena = std.heap.ArenaAllocator.init(gpa); errdefer new_decl_arena.deinit(); @@ -19839,11 +19950,11 @@ fn reifyStruct( const struct_obj = mod.structPtr(struct_index); errdefer mod.destroyStruct(struct_index); - const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{ + const struct_ty = try ip.get(gpa, .{ .struct_type = .{ .index = struct_index.toOptional(), .namespace = new_namespace_index.toOptional(), } }); - errdefer mod.intern_pool.remove(struct_ty); + errdefer ip.remove(struct_ty); new_decl.val = struct_ty.toValue(); new_namespace.ty = struct_ty.toType(); @@ -19854,12 +19965,22 @@ fn reifyStruct( var i: usize = 0; while (i < fields_len) : (i += 1) { const elem_val = try fields_val.elemValue(mod, i); - const elem_fields = mod.intern_pool.typeOf(elem_val.toIntern()).toType().structFields(mod); - const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex("name").?); - const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex("type").?); - const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex("default_value").?); - const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex("is_comptime").?); - const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex("alignment").?); + const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod); + const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "name"), + ).?); + const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "type"), + ).?); + const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "default_value"), + ).?); + const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "is_comptime"), + ).?); + const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex( + try ip.getOrPutString(gpa, "alignment"), + ).?); if (!try sema.intFitsInType(alignment_val, Type.u32, null)) { return sema.fail(block, src, "alignment must fit in 'u32'", .{}); @@ -19874,19 +19995,15 @@ fn reifyStruct( return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}); } - const field_name = try name_val.toAllocatedBytes( - Type.slice_const_u8, - new_decl_arena_allocator, - mod, - ); + const field_name = try name_val.toIpString(Type.slice_const_u8, mod); if (is_tuple) { - const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch { + const field_index = std.fmt.parseUnsigned(u32, ip.stringToSlice(field_name), 10) catch { return sema.fail( block, src, "tuple cannot have non-numeric field '{s}'", - .{field_name}, + .{ip.stringToSlice(field_name)}, ); }; @@ -19902,16 +20019,16 @@ fn reifyStruct( const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { // TODO: better source location - return sema.fail(block, src, "duplicate struct field {s}", .{field_name}); + return sema.fail(block, src, "duplicate struct field {s}", .{ip.stringToSlice(field_name)}); } const field_ty = type_val.toType(); const default_val = if (default_value_val.optionalValue(mod)) |opt_val| - try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse - return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known") + (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse + return sema.failWithNeededComptime(block, src, "struct field default value must be comptime-known")).toIntern() else - Value.@"unreachable"; - if (is_comptime_val.toBool() and default_val.toIntern() == .unreachable_value) { + .none; + if (is_comptime_val.toBool() and default_val == .none) { return sema.fail(block, src, "comptime field without default initialization value", .{}); } @@ -20000,7 +20117,6 @@ fn reifyStruct( struct_obj.status = .have_layout; } - try new_decl.finalizeNewArena(&new_decl_arena); const decl_val = sema.analyzeDeclVal(block, src, new_decl_index); try mod.finalizeAnonDecl(new_decl_index); return decl_val; @@ -20871,7 +20987,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const ty = try sema.resolveType(block, lhs_src, extra.lhs); - const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "name of field must be comptime-known"); const mod = sema.mod; try sema.resolveTypeLayout(ty); @@ -20889,7 +21005,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6 } const field_index = if (ty.isTuple(mod)) blk: { - if (mem.eql(u8, field_name, "len")) { + if (mod.intern_pool.stringEqlSlice(field_name, "len")) { return sema.fail(block, src, "no offset available for 'len' field of tuple", .{}); } break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src); @@ -21351,6 +21467,8 @@ fn resolveExportOptions( zir_ref: Zir.Inst.Ref, ) CompileError!std.builtin.ExportOptions { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const export_options_ty = try sema.getBuiltinType("ExportOptions"); const air_ref = try sema.resolveInst(zir_ref); const options = try sema.coerce(block, export_options_ty, air_ref, src); @@ -21360,16 +21478,16 @@ fn resolveExportOptions( const section_src = sema.maybeOptionsSrc(block, src, "section"); const visibility_src = sema.maybeOptionsSrc(block, src, "visibility"); - const name_operand = try sema.fieldVal(block, src, options, "name", name_src); + const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known"); const name_ty = Type.slice_const_u8; const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod); - const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src); + const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime-known"); const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val); - const section_operand = try sema.fieldVal(block, src, options, "section", section_src); + const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "section"), section_src); const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known"); const section_ty = Type.slice_const_u8; const section = if (section_opt_val.optionalValue(mod)) |section_val| @@ -21377,7 +21495,7 @@ fn resolveExportOptions( else null; - const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src); + const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "visibility"), visibility_src); const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime-known"); const visibility = mod.toEnum(std.builtin.SymbolVisibility, visibility_val); @@ -22217,10 +22335,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node }; const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type); - const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known"); + const field_name = try sema.resolveConstStringIntern(block, name_src, extra.field_name, "field name must be comptime-known"); const field_ptr = try sema.resolveInst(extra.field_ptr); const field_ptr_ty = sema.typeOf(field_ptr); const mod = sema.mod; + const ip = &mod.intern_pool; if (parent_ty.zigTypeTag(mod) != .Struct and parent_ty.zigTypeTag(mod) != .Union) { return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)}); @@ -22230,7 +22349,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const field_index = switch (parent_ty.zigTypeTag(mod)) { .Struct => blk: { if (parent_ty.isTuple(mod)) { - if (mem.eql(u8, field_name, "len")) { + if (ip.stringEqlSlice(field_name, "len")) { return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{}); } break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src); @@ -22276,7 +22395,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data); if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| { - const field = switch (mod.intern_pool.indexToKey(field_ptr_val.toIntern())) { + const field = switch (ip.indexToKey(field_ptr_val.toIntern())) { .ptr => |ptr| switch (ptr.addr) { .field => |field| field, else => null, @@ -22291,7 +22410,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr src, "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'", .{ - field_name, + ip.stringToSlice(field_name), field_index, field.index, parent_ty.fmt(sema.mod), @@ -22807,6 +22926,8 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const inst_data = sema.code.instructions.items(.data)[inst].pl_node; const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; const src = inst_data.src(); @@ -22824,7 +22945,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const dest_elem_ty = dest_ptr_ty.elemType2(mod); const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: { - const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src); + const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len"), dest_src); const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src; const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?; @@ -23068,11 +23189,11 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A if (val.isGenericPoison()) { break :blk FuncLinkSection{ .generic = {} }; } - break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) }; + break :blk FuncLinkSection{ .explicit = try val.toIpString(ty, mod) }; } else if (extra.data.bits.has_section_ref) blk: { const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]); extra_index += 1; - const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { + const section_name = sema.resolveConstStringIntern(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) { error.GenericPoison => { break :blk FuncLinkSection{ .generic = {} }; }, @@ -23272,6 +23393,8 @@ fn resolvePrefetchOptions( zir_ref: Zir.Inst.Ref, ) CompileError!std.builtin.PrefetchOptions { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const options_ty = try sema.getBuiltinType("PrefetchOptions"); const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src); @@ -23279,13 +23402,13 @@ fn resolvePrefetchOptions( const locality_src = sema.maybeOptionsSrc(block, src, "locality"); const cache_src = sema.maybeOptionsSrc(block, src, "cache"); - const rw = try sema.fieldVal(block, src, options, "rw", rw_src); + const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "rw"), rw_src); const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime-known"); - const locality = try sema.fieldVal(block, src, options, "locality", locality_src); + const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "locality"), locality_src); const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime-known"); - const cache = try sema.fieldVal(block, src, options, "cache", cache_src); + const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "cache"), cache_src); const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known"); return std.builtin.PrefetchOptions{ @@ -23336,6 +23459,8 @@ fn resolveExternOptions( zir_ref: Zir.Inst.Ref, ) CompileError!std.builtin.ExternOptions { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const options_inst = try sema.resolveInst(zir_ref); const extern_options_ty = try sema.getBuiltinType("ExternOptions"); const options = try sema.coerce(block, extern_options_ty, options_inst, src); @@ -23345,18 +23470,18 @@ fn resolveExternOptions( const linkage_src = sema.maybeOptionsSrc(block, src, "linkage"); const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local"); - const name_ref = try sema.fieldVal(block, src, options, "name", name_src); + const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src); const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known"); const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod); - const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src); + const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src); const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known"); - const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src); + const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src); const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime-known"); const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val); - const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src); + const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "is_thread_local"), thread_local_src); const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known"); const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: { @@ -23425,7 +23550,7 @@ fn zirBuiltinExtern( const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null); errdefer mod.destroyDecl(new_decl_index); const new_decl = mod.declPtr(new_decl_index); - new_decl.name = try sema.gpa.dupeZ(u8, options.name); + new_decl.name = try mod.intern_pool.getOrPutString(sema.gpa, options.name); { const new_var = try mod.intern(.{ .variable = .{ @@ -23444,7 +23569,7 @@ fn zirBuiltinExtern( new_decl.ty = ty; new_decl.val = new_var.toValue(); new_decl.@"align" = 0; - new_decl.@"linksection" = null; + new_decl.@"linksection" = .none; new_decl.has_tv = true; new_decl.analysis = .complete; new_decl.generation = mod.generation; @@ -24265,12 +24390,13 @@ fn safetyPanic( panic_id: PanicId, ) CompileError!void { const mod = sema.mod; + const gpa = sema.gpa; const panic_messages_ty = try sema.getBuiltinType("panic_messages"); const msg_decl_index = (try sema.namespaceLookup( block, sema.src, panic_messages_ty.getNamespaceIndex(mod).unwrap().?, - @tagName(panic_id), + try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)), )).?; const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index); @@ -24302,14 +24428,13 @@ fn fieldVal( block: *Block, src: LazySrcLoc, object: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, ) CompileError!Air.Inst.Ref { // When editing this function, note that there is corresponding logic to be edited // in `fieldPtr`. This function takes a value and returns a value. const mod = sema.mod; - const gpa = sema.gpa; const ip = &mod.intern_pool; const object_src = src; // TODO better source location const object_ty = sema.typeOf(object); @@ -24326,12 +24451,12 @@ fn fieldVal( switch (inner_ty.zigTypeTag(mod)) { .Array => { - if (mem.eql(u8, field_name, "len")) { + if (ip.stringEqlSlice(field_name, "len")) { return sema.addConstant( Type.usize, try mod.intValue(Type.usize, inner_ty.arrayLen(mod)), ); - } else if (mem.eql(u8, field_name, "ptr") and is_pointer_to) { + } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) { const ptr_info = object_ty.ptrInfo(mod); const result_ty = try Type.ptr(sema.arena, mod, .{ .pointee_type = ptr_info.pointee_type.childType(mod), @@ -24352,20 +24477,20 @@ fn fieldVal( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty.fmt(mod) }, + .{ ip.stringToSlice(field_name), object_ty.fmt(mod) }, ); } }, .Pointer => { const ptr_info = inner_ty.ptrInfo(mod); if (ptr_info.size == .Slice) { - if (mem.eql(u8, field_name, "ptr")) { + if (ip.stringEqlSlice(field_name, "ptr")) { const slice = if (is_pointer_to) try sema.analyzeLoad(block, src, object, object_src) else object; return sema.analyzeSlicePtr(block, object_src, slice, inner_ty); - } else if (mem.eql(u8, field_name, "len")) { + } else if (ip.stringEqlSlice(field_name, "len")) { const slice = if (is_pointer_to) try sema.analyzeLoad(block, src, object, object_src) else @@ -24376,7 +24501,7 @@ fn fieldVal( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty.fmt(mod) }, + .{ ip.stringToSlice(field_name), object_ty.fmt(mod) }, ); } } @@ -24392,13 +24517,12 @@ fn fieldVal( switch (try child_type.zigTypeTagOrPoison(mod)) { .ErrorSet => { - const name = try ip.getOrPutString(gpa, field_name); switch (ip.indexToKey(child_type.toIntern())) { .error_set_type => |error_set_type| blk: { - if (error_set_type.nameIndex(ip, name) != null) break :blk; + if (error_set_type.nameIndex(ip, field_name) != null) break :blk; const msg = msg: { const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{ - field_name, child_type.fmt(mod), + ip.stringToSlice(field_name), child_type.fmt(mod), }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, child_type); @@ -24419,10 +24543,10 @@ fn fieldVal( const error_set_type = if (!child_type.isAnyError(mod)) child_type else - try mod.singleErrorSetTypeNts(name); + try mod.singleErrorSetTypeNts(field_name); return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{ .ty = error_set_type.toIntern(), - .name = name, + .name = field_name, } })).toValue()); }, .Union => { @@ -24499,7 +24623,7 @@ fn fieldPtr( block: *Block, src: LazySrcLoc, object_ptr: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, initializing: bool, ) CompileError!Air.Inst.Ref { @@ -24507,7 +24631,6 @@ fn fieldPtr( // in `fieldVal`. This function takes a pointer and returns a pointer. const mod = sema.mod; - const gpa = sema.gpa; const ip = &mod.intern_pool; const object_ptr_src = src; // TODO better source location const object_ptr_ty = sema.typeOf(object_ptr); @@ -24528,7 +24651,7 @@ fn fieldPtr( switch (inner_ty.zigTypeTag(mod)) { .Array => { - if (mem.eql(u8, field_name, "len")) { + if (ip.stringEqlSlice(field_name, "len")) { var anon_decl = try block.startAnonDecl(); defer anon_decl.deinit(); return sema.analyzeDeclRef(try anon_decl.finish( @@ -24541,7 +24664,7 @@ fn fieldPtr( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty.fmt(mod) }, + .{ ip.stringToSlice(field_name), object_ty.fmt(mod) }, ); } }, @@ -24553,7 +24676,7 @@ fn fieldPtr( const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty; - if (mem.eql(u8, field_name, "ptr")) { + if (ip.stringEqlSlice(field_name, "ptr")) { const slice_ptr_ty = inner_ty.slicePtrFieldType(mod); const result_ty = try Type.ptr(sema.arena, mod, .{ @@ -24575,7 +24698,7 @@ fn fieldPtr( try sema.requireRuntimeBlock(block, src, null); return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr); - } else if (mem.eql(u8, field_name, "len")) { + } else if (ip.stringEqlSlice(field_name, "len")) { const result_ty = try Type.ptr(sema.arena, mod, .{ .pointee_type = Type.usize, .mutable = attr_ptr_ty.ptrIsMutable(mod), @@ -24600,7 +24723,7 @@ fn fieldPtr( block, field_name_src, "no member named '{s}' in '{}'", - .{ field_name, object_ty.fmt(mod) }, + .{ ip.stringToSlice(field_name), object_ty.fmt(mod) }, ); } }, @@ -24617,14 +24740,13 @@ fn fieldPtr( switch (child_type.zigTypeTag(mod)) { .ErrorSet => { - const name = try ip.getOrPutString(gpa, field_name); switch (ip.indexToKey(child_type.toIntern())) { .error_set_type => |error_set_type| blk: { - if (error_set_type.nameIndex(ip, name) != null) { + if (error_set_type.nameIndex(ip, field_name) != null) { break :blk; } return sema.fail(block, src, "no error named '{s}' in '{}'", .{ - field_name, child_type.fmt(mod), + ip.stringToSlice(field_name), child_type.fmt(mod), }); }, .inferred_error_set_type => { @@ -24642,12 +24764,12 @@ fn fieldPtr( const error_set_type = if (!child_type.isAnyError(mod)) child_type else - try mod.singleErrorSetTypeNts(name); + try mod.singleErrorSetTypeNts(field_name); return sema.analyzeDeclRef(try anon_decl.finish( error_set_type, (try mod.intern(.{ .err = .{ .ty = error_set_type.toIntern(), - .name = name, + .name = field_name, } })).toValue(), 0, // default alignment )); @@ -24736,13 +24858,14 @@ fn fieldCallBind( block: *Block, src: LazySrcLoc, raw_ptr: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, ) CompileError!ResolvedFieldCallee { // When editing this function, note that there is corresponding logic to be edited // in `fieldVal`. This function takes a pointer and returns a pointer. const mod = sema.mod; + const ip = &mod.intern_pool; const raw_ptr_src = src; // TODO better source location const raw_ptr_ty = sema.typeOf(raw_ptr); const inner_ty = if (raw_ptr_ty.zigTypeTag(mod) == .Pointer and (raw_ptr_ty.ptrSize(mod) == .One or raw_ptr_ty.ptrSize(mod) == .C)) @@ -24771,18 +24894,18 @@ fn fieldCallBind( return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr); } else if (struct_ty.isTuple(mod)) { - if (mem.eql(u8, field_name, "len")) { + if (ip.stringEqlSlice(field_name, "len")) { return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)) }; } - if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { + if (std.fmt.parseUnsigned(u32, ip.stringToSlice(field_name), 10)) |field_index| { if (field_index >= struct_ty.structFieldCount(mod)) break :find_field; return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr); } else |_| {} } else { const max = struct_ty.structFieldCount(mod); - var i: u32 = 0; - while (i < max) : (i += 1) { - if (mem.eql(u8, struct_ty.structFieldName(i, mod), field_name)) { + for (0..max) |i_usize| { + const i = @intCast(u32, i_usize); + if (field_name == struct_ty.structFieldName(i, mod)) { return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr); } } @@ -24876,12 +24999,12 @@ fn fieldCallBind( }; const msg = msg: { - const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(mod) }); + const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ ip.stringToSlice(field_name), concrete_ty.fmt(mod) }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, concrete_ty); if (found_decl) |decl_idx| { const decl = mod.declPtr(decl_idx); - try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{s}' is not a member function", .{field_name}); + try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{s}' is not a member function", .{ip.stringToSlice(field_name)}); } break :msg msg; }; @@ -24933,7 +25056,7 @@ fn namespaceLookup( block: *Block, src: LazySrcLoc, namespace: Namespace.Index, - decl_name: []const u8, + decl_name: InternPool.NullTerminatedString, ) CompileError!?Decl.Index { const mod = sema.mod; const gpa = sema.gpa; @@ -24942,7 +25065,7 @@ fn namespaceLookup( if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) { const msg = msg: { const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{ - decl_name, + mod.intern_pool.stringToSlice(decl_name), }); errdefer msg.destroy(gpa); try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "declared here", .{}); @@ -24960,7 +25083,7 @@ fn namespaceLookupRef( block: *Block, src: LazySrcLoc, namespace: Namespace.Index, - decl_name: []const u8, + decl_name: InternPool.NullTerminatedString, ) CompileError!?Air.Inst.Ref { const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; try sema.addReferencedBy(block, src, decl); @@ -24972,7 +25095,7 @@ fn namespaceLookupVal( block: *Block, src: LazySrcLoc, namespace: Namespace.Index, - decl_name: []const u8, + decl_name: InternPool.NullTerminatedString, ) CompileError!?Air.Inst.Ref { const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null; return try sema.analyzeDeclVal(block, src, decl); @@ -24983,7 +25106,7 @@ fn structFieldPtr( block: *Block, src: LazySrcLoc, struct_ptr: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, unresolved_struct_ty: Type, initializing: bool, @@ -24995,7 +25118,7 @@ fn structFieldPtr( try sema.resolveStructLayout(struct_ty); if (struct_ty.isTuple(mod)) { - if (mem.eql(u8, field_name, "len")) { + if (mod.intern_pool.stringEqlSlice(field_name, "len")) { const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)); return sema.analyzeRef(block, src, len_inst); } @@ -25101,7 +25224,7 @@ fn structFieldPtrByIndex( if (field.is_comptime) { const val = try mod.intern(.{ .ptr = .{ .ty = ptr_field_ty.toIntern(), - .addr = .{ .comptime_field = try field.default_val.intern(field.ty, mod) }, + .addr = .{ .comptime_field = field.default_val }, } }); return sema.addConstant(ptr_field_ty, val.toValue()); } @@ -25126,7 +25249,7 @@ fn structFieldVal( block: *Block, src: LazySrcLoc, struct_byval: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, unresolved_struct_ty: Type, ) CompileError!Air.Inst.Ref { @@ -25145,7 +25268,7 @@ fn structFieldVal( const field = struct_obj.fields.values()[field_index]; if (field.is_comptime) { - return sema.addConstant(field.ty, field.default_val); + return sema.addConstant(field.ty, field.default_val.toValue()); } if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| { @@ -25176,12 +25299,12 @@ fn tupleFieldVal( block: *Block, src: LazySrcLoc, tuple_byval: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, tuple_ty: Type, ) CompileError!Air.Inst.Ref { const mod = sema.mod; - if (mem.eql(u8, field_name, "len")) { + if (mod.intern_pool.stringEqlSlice(field_name, "len")) { return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount(mod)); } const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src); @@ -25193,11 +25316,12 @@ fn tupleFieldIndex( sema: *Sema, block: *Block, tuple_ty: Type, - field_name: []const u8, + field_name_ip: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, ) CompileError!u32 { const mod = sema.mod; - assert(!mem.eql(u8, field_name, "len")); + const field_name = mod.intern_pool.stringToSlice(field_name_ip); + assert(!std.mem.eql(u8, field_name, "len")); if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| { if (field_index < tuple_ty.structFieldCount(mod)) return field_index; return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{ @@ -25253,13 +25377,14 @@ fn unionFieldPtr( block: *Block, src: LazySrcLoc, union_ptr: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, unresolved_union_ty: Type, initializing: bool, ) CompileError!Air.Inst.Ref { const arena = sema.arena; const mod = sema.mod; + const ip = &mod.intern_pool; assert(unresolved_union_ty.zigTypeTag(mod) == .Union); @@ -25281,7 +25406,9 @@ fn unionFieldPtr( const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{}); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{ + ip.stringToSlice(field_name), + }); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; }; @@ -25296,14 +25423,17 @@ fn unionFieldPtr( if (union_val.isUndef(mod)) { return sema.failWithUseOfUndef(block, src); } - const un = mod.intern_pool.indexToKey(union_val.toIntern()).un; + const un = ip.indexToKey(union_val.toIntern()).un; const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); const tag_matches = un.tag == field_tag.toIntern(); if (!tag_matches) { const msg = msg: { const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); - const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); + const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ + ip.stringToSlice(field_name), + ip.stringToSlice(active_field_name), + }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; @@ -25345,11 +25475,12 @@ fn unionFieldVal( block: *Block, src: LazySrcLoc, union_byval: Air.Inst.Ref, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_name_src: LazySrcLoc, unresolved_union_ty: Type, ) CompileError!Air.Inst.Ref { const mod = sema.mod; + const ip = &mod.intern_pool; assert(unresolved_union_ty.zigTypeTag(mod) == .Union); const union_ty = try sema.resolveTypeFields(unresolved_union_ty); @@ -25361,7 +25492,7 @@ fn unionFieldVal( if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| { if (union_val.isUndef(mod)) return sema.addConstUndef(field.ty); - const un = mod.intern_pool.indexToKey(union_val.toIntern()).un; + const un = ip.indexToKey(union_val.toIntern()).un; const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index); const tag_matches = un.tag == field_tag.toIntern(); switch (union_obj.layout) { @@ -25372,7 +25503,9 @@ fn unionFieldVal( const msg = msg: { const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?; const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod); - const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name }); + const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ + ip.stringToSlice(field_name), ip.stringToSlice(active_field_name), + }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; @@ -26470,14 +26603,13 @@ fn coerceExtra( // enum literal to enum const val = try sema.resolveConstValue(block, .unneeded, inst, ""); const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal; - const bytes = mod.intern_pool.stringToSlice(string); - const field_index = dest_ty.enumFieldIndex(bytes, mod) orelse { + const field_index = dest_ty.enumFieldIndex(string, mod) orelse { const msg = msg: { const msg = try sema.errMsg( block, inst_src, "no field named '{s}' in enum '{}'", - .{ bytes, dest_ty.fmt(mod) }, + .{ mod.intern_pool.stringToSlice(string), dest_ty.fmt(mod) }, ); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, dest_ty); @@ -27876,10 +28008,7 @@ fn storePtrVal( error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}), }; - const arena = mut_kit.beginArena(mod); - defer mut_kit.finishArena(mod); - - reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, arena)).intern(mut_kit.ty, mod)).toValue(); + reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, sema.arena)).intern(mut_kit.ty, mod)).toValue(); }, .bad_decl_ty, .bad_ptr_ty => { // TODO show the decl declaration site in a note and explain whether the decl @@ -27913,18 +28042,6 @@ const ComptimePtrMutationKit = struct { bad_ptr_ty, }, ty: Type, - decl_arena: std.heap.ArenaAllocator = undefined, - - fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator { - const decl = mod.declPtr(self.mut_decl.decl); - return decl.value_arena.?.acquire(mod.gpa, &self.decl_arena); - } - - fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void { - const decl = mod.declPtr(self.mut_decl.decl); - decl.value_arena.?.release(&self.decl_arena); - self.decl_arena = undefined; - } }; fn beginComptimePtrMutation( @@ -27966,10 +28083,8 @@ fn beginComptimePtrMutation( // An error union has been initialized to undefined at comptime and now we // are for the first time setting the payload. We must change the // representation of the error union from `undef` to `opt_payload`. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); - const payload = try arena.create(Value.Payload.SubValue); + const payload = try sema.arena.create(Value.Payload.SubValue); payload.* = .{ .base = .{ .tag = .eu_payload }, .data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(), @@ -28019,10 +28134,8 @@ fn beginComptimePtrMutation( // An optional has been initialized to undefined at comptime and now we // are for the first time setting the payload. We must change the // representation of the optional from `undef` to `opt_payload`. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); - const payload = try arena.create(Value.Payload.SubValue); + const payload = try sema.arena.create(Value.Payload.SubValue); payload.* = .{ .base = .{ .tag = .opt_payload }, .data = payload_val.toValue(), @@ -28088,8 +28201,7 @@ fn beginComptimePtrMutation( // If we wanted to avoid this, there would need to be special detection // elsewhere to identify when writing a value to an array element that is stored // using the `bytes` tag, and handle it without making a call to this function. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); + const arena = sema.arena; const bytes = val_ptr.castTag(.bytes).?.data; const dest_len = parent.ty.arrayLenIncludingSentinel(mod); @@ -28121,8 +28233,7 @@ fn beginComptimePtrMutation( // need to be special detection elsewhere to identify when writing a value to an // array element that is stored using the `repeated` tag, and handle it // without making a call to this function. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); + const arena = sema.arena; const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena); const array_len_including_sentinel = @@ -28163,8 +28274,7 @@ fn beginComptimePtrMutation( // An array has been initialized to undefined at comptime and now we // are for the first time setting an element. We must change the representation // of the array from `undef` to `array`. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); + const arena = sema.arena; const array_len_including_sentinel = try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod)); @@ -28261,8 +28371,7 @@ fn beginComptimePtrMutation( parent.mut_decl, ), .repeated => { - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); + const arena = sema.arena; const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod)); @memset(elems, val_ptr.castTag(.repeated).?.data); @@ -28325,8 +28434,7 @@ fn beginComptimePtrMutation( // A struct or union has been initialized to undefined at comptime and now we // are for the first time setting a field. We must change the representation // of the struct/union from `undef` to `struct`/`union`. - const arena = parent.beginArena(sema.mod); - defer parent.finishArena(sema.mod); + const arena = sema.arena; switch (parent.ty.zigTypeTag(mod)) { .Struct => { @@ -28436,11 +28544,7 @@ fn beginComptimePtrMutationInner( const target = mod.getTarget(); const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok; - const decl = mod.declPtr(mut_decl.decl); - var decl_arena: std.heap.ArenaAllocator = undefined; - const allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena); - defer decl.value_arena.?.release(&decl_arena); - decl_val.* = try decl_val.unintern(allocator, mod); + decl_val.* = try decl_val.unintern(sema.arena, mod); if (coerce_ok) { return ComptimePtrMutationKit{ @@ -28928,6 +29032,7 @@ fn coerceEnumToUnion( inst_src: LazySrcLoc, ) !Air.Inst.Ref { const mod = sema.mod; + const ip = &mod.intern_pool; const inst_ty = sema.typeOf(inst); const tag_ty = union_ty.unionTagType(mod) orelse { @@ -28966,7 +29071,9 @@ fn coerceEnumToUnion( errdefer msg.destroy(sema.gpa); const field_name = union_obj.fields.keys()[field_index]; - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{ + ip.stringToSlice(field_name), + }); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; }; @@ -28976,11 +29083,14 @@ fn coerceEnumToUnion( const msg = msg: { const field_name = union_obj.fields.keys()[field_index]; const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{ - inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name, + inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), + field_ty.fmt(sema.mod), ip.stringToSlice(field_name), }); errdefer msg.destroy(sema.gpa); - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name}); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{ + ip.stringToSlice(field_name), + }); try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; }; @@ -29049,7 +29159,10 @@ fn coerceEnumToUnion( const field_name = field.key_ptr.*; const field_ty = field.value_ptr.ty; if (!(try sema.typeHasRuntimeBits(field_ty))) continue; - try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) }); + try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ + ip.stringToSlice(field_name), + field_ty.fmt(sema.mod), + }); } try sema.addDeclaredHereNote(msg, union_ty); break :msg msg; @@ -29068,11 +29181,11 @@ fn coerceAnonStructToUnion( const mod = sema.mod; const inst_ty = sema.typeOf(inst); const field_info: union(enum) { - name: []const u8, + name: InternPool.NullTerminatedString, count: usize, } = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 1) - .{ .name = mod.intern_pool.stringToSlice(anon_struct_type.names[0]) } + .{ .name = anon_struct_type.names[0] } else .{ .count = anon_struct_type.names.len }, .struct_type => |struct_type| name: { @@ -29335,6 +29448,7 @@ fn coerceTupleToStruct( inst_src: LazySrcLoc, ) !Air.Inst.Ref { const mod = sema.mod; + const ip = &mod.intern_pool; const struct_ty = try sema.resolveTypeFields(dest_ty); if (struct_ty.isTupleOrAnonStruct(mod)) { @@ -29348,7 +29462,7 @@ fn coerceTupleToStruct( const inst_ty = sema.typeOf(inst); var runtime_src: ?LazySrcLoc = null; - const field_count = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { + const field_count = switch (ip.indexToKey(inst_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| struct_obj.fields.count() @@ -29360,11 +29474,11 @@ fn coerceTupleToStruct( const field_i = @intCast(u32, field_index_usize); const field_src = inst_src; // TODO better source location // https://github.com/ziglang/zig/issues/15709 - const field_name: []const u8 = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { + const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) { .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) - mod.intern_pool.stringToSlice(anon_struct_type.names[field_i]) + anon_struct_type.names[field_i] else - try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}), + try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], else => unreachable, }; @@ -29378,7 +29492,7 @@ fn coerceTupleToStruct( return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known"); }; - if (!init_val.eql(field.default_val, field.ty, sema.mod)) { + if (!init_val.eql(field.default_val.toValue(), field.ty, sema.mod)) { return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i); } } @@ -29401,9 +29515,9 @@ fn coerceTupleToStruct( const field_name = fields.keys()[i]; const field = fields.values()[i]; const field_src = inst_src; // TODO better source location - if (field.default_val.toIntern() == .unreachable_value) { + if (field.default_val == .none) { const template = "missing struct field: {s}"; - const args = .{field_name}; + const args = .{ip.stringToSlice(field_name)}; if (root_msg) |msg| { try sema.errNote(block, field_src, msg, template, args); } else { @@ -29412,9 +29526,9 @@ fn coerceTupleToStruct( continue; } if (runtime_src == null) { - field_vals[i] = field.default_val.toIntern(); + field_vals[i] = field.default_val; } else { - field_ref.* = try sema.addConstant(field.ty, field.default_val); + field_ref.* = try sema.addConstant(field.ty, field.default_val.toValue()); } } @@ -29433,7 +29547,7 @@ fn coerceTupleToStruct( .ty = struct_ty.toIntern(), .storage = .{ .elems = field_vals }, } }); - errdefer mod.intern_pool.remove(struct_val); + errdefer ip.remove(struct_val); return sema.addConstant(struct_ty, struct_val.toValue()); } @@ -29446,7 +29560,8 @@ fn coerceTupleToTuple( inst_src: LazySrcLoc, ) !Air.Inst.Ref { const mod = sema.mod; - const dest_field_count = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { + const ip = &mod.intern_pool; + const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| struct_obj.fields.count() @@ -29459,7 +29574,7 @@ fn coerceTupleToTuple( @memset(field_refs, .none); const inst_ty = sema.typeOf(inst); - const src_field_count = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { + const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.types.len, .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| struct_obj.fields.count() @@ -29474,30 +29589,26 @@ fn coerceTupleToTuple( const field_i = @intCast(u32, field_index_usize); const field_src = inst_src; // TODO better source location // https://github.com/ziglang/zig/issues/15709 - const field_name: []const u8 = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) { + const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) { .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0) - mod.intern_pool.stringToSlice(anon_struct_type.names[field_i]) + anon_struct_type.names[field_i] else - try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}), + try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}), .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i], else => unreachable, }; - if (mem.eql(u8, field_name, "len")) { + if (ip.stringEqlSlice(field_name, "len")) return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{}); - } - const field_ty = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { + const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.types[field_index_usize].toType(), .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty, else => unreachable, }; - const default_val = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { + const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.values[field_index_usize], - .struct_type => |struct_type| switch (mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val.toIntern()) { - .unreachable_value => .none, - else => |default_val| default_val, - }, + .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val, else => unreachable, }; @@ -29531,12 +29642,9 @@ fn coerceTupleToTuple( for (field_refs, 0..) |*field_ref, i| { if (field_ref.* != .none) continue; - const default_val = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { + const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.values[i], - .struct_type => |struct_type| switch (mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val.toIntern()) { - .unreachable_value => .none, - else => |default_val| default_val, - }, + .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val, else => unreachable, }; @@ -29552,7 +29660,7 @@ fn coerceTupleToTuple( continue; } const template = "missing struct field: {s}"; - const args = .{tuple_ty.structFieldName(i, mod)}; + const args = .{ip.stringToSlice(tuple_ty.structFieldName(i, mod))}; if (root_msg) |msg| { try sema.errNote(block, field_src, msg, template, args); } else { @@ -29563,7 +29671,7 @@ fn coerceTupleToTuple( if (runtime_src == null) { field_vals[i] = default_val; } else { - const field_ty = switch (mod.intern_pool.indexToKey(tuple_ty.toIntern())) { + const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) { .anon_struct_type => |anon_struct_type| anon_struct_type.types[i].toType(), .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].ty, else => unreachable, @@ -31803,15 +31911,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void { } if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) { - const optimized_order = if (struct_obj.owner_decl == sema.owner_decl_index) - try sema.perm_arena.alloc(u32, struct_obj.fields.count()) - else blk: { - const decl = mod.declPtr(struct_obj.owner_decl); - var decl_arena: std.heap.ArenaAllocator = undefined; - const decl_arena_allocator = decl.value_arena.?.acquire(sema.gpa, &decl_arena); - defer decl.value_arena.?.release(&decl_arena); - break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count()); - }; + const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count()); for (struct_obj.fields.values(), 0..) |field, i| { optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty)) @@ -31852,9 +31952,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi const decl_index = struct_obj.owner_decl; const decl = mod.declPtr(decl_index); - var decl_arena: std.heap.ArenaAllocator = undefined; - const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); - defer decl.value_arena.?.release(&decl_arena); const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; @@ -31880,7 +31977,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi .mod = mod, .gpa = gpa, .arena = analysis_arena.allocator(), - .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, @@ -31936,7 +32032,6 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi .mod = mod, .gpa = gpa, .arena = undefined, - .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, @@ -32581,6 +32676,7 @@ fn resolveInferredErrorSetTy( fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void { const gpa = mod.gpa; + const ip = &mod.intern_pool; const decl_index = struct_obj.owner_decl; const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir; const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended; @@ -32628,9 +32724,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void } const decl = mod.declPtr(decl_index); - var decl_arena: std.heap.ArenaAllocator = undefined; - const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); - defer decl.value_arena.?.release(&decl_arena); var analysis_arena = std.heap.ArenaAllocator.init(gpa); defer analysis_arena.deinit(); @@ -32642,7 +32735,6 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void .mod = mod, .gpa = gpa, .arena = analysis_arena.allocator(), - .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, @@ -32674,7 +32766,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void } struct_obj.fields = .{}; - try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); + try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); const Field = struct { type_body_len: u32 = 0, @@ -32725,16 +32817,15 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void extra_index += 1; // This string needs to outlive the ZIR code. - const field_name = if (field_name_zir) |some| - try decl_arena_allocator.dupe(u8, some) - else - try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i}); + const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s| s else try std.fmt.allocPrint(sema.arena, "{d}", .{ + field_i, + })); const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name); if (gop.found_existing) { const msg = msg: { const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy; - const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name}); + const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{ip.stringToSlice(field_name)}); errdefer msg.destroy(gpa); const prev_field_index = struct_obj.fields.getIndex(field_name).?; @@ -32748,7 +32839,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void gop.value_ptr.* = .{ .ty = Type.noreturn, .abi_align = 0, - .default_val = Value.@"unreachable", + .default_val = .none, .is_comptime = is_comptime, .offset = undefined, }; @@ -32917,7 +33008,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void }).lazy; return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known"); }; - field.default_val = try default_val.copy(decl_arena_allocator); + field.default_val = try default_val.intern(field.ty, mod); } } } @@ -32935,6 +33026,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { defer tracy.end(); const gpa = mod.gpa; + const ip = &mod.intern_pool; const decl_index = union_obj.owner_decl; const zir = mod.namespacePtr(union_obj.namespace).file_scope.zir; const extended = zir.instructions.items(.data)[union_obj.zir_index].extended; @@ -32978,9 +33070,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { extra_index += body.len; const decl = mod.declPtr(decl_index); - var decl_arena: std.heap.ArenaAllocator = undefined; - const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena); - defer decl.value_arena.?.release(&decl_arena); var analysis_arena = std.heap.ArenaAllocator.init(gpa); defer analysis_arena.deinit(); @@ -32992,7 +33081,6 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { .mod = mod, .gpa = gpa, .arena = analysis_arena.allocator(), - .perm_arena = decl_arena_allocator, .code = zir, .owner_decl = decl, .owner_decl_index = decl_index, @@ -33033,7 +33121,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { try ct_decl.intern(mod); } - try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len); + try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len); var int_tag_ty: Type = undefined; var enum_field_names: []InternPool.NullTerminatedString = &.{}; @@ -33070,7 +33158,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { } else { // The provided type is the enum tag type. union_obj.tag_ty = provided_ty; - const enum_type = switch (mod.intern_pool.indexToKey(union_obj.tag_ty.toIntern())) { + const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) { .enum_type => |x| x, else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}), }; @@ -33174,10 +33262,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { } // This string needs to outlive the ZIR code. - const field_name = try decl_arena_allocator.dupe(u8, field_name_zir); - const field_name_ip = try mod.intern_pool.getOrPutString(gpa, field_name); + const field_name = try ip.getOrPutString(gpa, field_name_zir); if (enum_field_names.len != 0) { - enum_field_names[field_i] = field_name_ip; + enum_field_names[field_i] = field_name; } const field_ty: Type = if (!has_type) @@ -33205,7 +33292,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { if (gop.found_existing) { const msg = msg: { const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy; - const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name}); + const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{ + ip.stringToSlice(field_name), + }); errdefer msg.destroy(gpa); const prev_field_index = union_obj.fields.getIndex(field_name).?; @@ -33218,14 +33307,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { } if (explicit_enum_info) |tag_info| { - const enum_index = tag_info.nameIndex(&mod.intern_pool, field_name_ip) orelse { + const enum_index = tag_info.nameIndex(ip, field_name) orelse { const msg = msg: { const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i, .range = .type, }).lazy; const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{ - field_name, union_obj.tag_ty.fmt(mod), + ip.stringToSlice(field_name), union_obj.tag_ty.fmt(mod), }); errdefer msg.destroy(sema.gpa); try sema.addDeclaredHereNote(msg, union_obj.tag_ty); @@ -33317,7 +33406,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void { for (tag_info.names, 0..) |field_name, field_index| { if (explicit_tags_seen[field_index]) continue; try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{ - mod.intern_pool.stringToSlice(field_name), + ip.stringToSlice(field_name), }); } try sema.addDeclaredHereNote(msg, union_obj.tag_ty); @@ -33345,14 +33434,22 @@ fn generateUnionTagTypeNumbered( union_obj: *Module.Union, ) !Type { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const src_decl = mod.declPtr(block.src_decl); const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); errdefer mod.destroyDecl(new_decl_index); const name = name: { - const fqn = try union_obj.getFullyQualifiedName(mod); - defer sema.gpa.free(fqn); - break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); + const prefix = "@typeInfo("; + const fqn = ip.stringToSlice(try union_obj.getFullyQualifiedName(mod)); + const suffix = ").Union.tag_type.?"; + const start = ip.string_bytes.items.len; + try ip.string_bytes.ensureUnusedCapacity(gpa, prefix.len + suffix.len + fqn.len); + ip.string_bytes.appendSliceAssumeCapacity(prefix); + ip.string_bytes.appendSliceAssumeCapacity(fqn); + ip.string_bytes.appendSliceAssumeCapacity(suffix); + break :name try ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); }; try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ .ty = Type.type, @@ -33390,6 +33487,8 @@ fn generateUnionTagTypeSimple( maybe_union_obj: ?*Module.Union, ) !Type { const mod = sema.mod; + const gpa = sema.gpa; + const ip = &mod.intern_pool; const new_decl_index = new_decl_index: { const union_obj = maybe_union_obj orelse { @@ -33402,9 +33501,15 @@ fn generateUnionTagTypeSimple( const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope); errdefer mod.destroyDecl(new_decl_index); const name = name: { - const fqn = try union_obj.getFullyQualifiedName(mod); - defer sema.gpa.free(fqn); - break :name try std.fmt.allocPrintZ(sema.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn}); + const prefix = "@typeInfo("; + const fqn = ip.stringToSlice(try union_obj.getFullyQualifiedName(mod)); + const suffix = ").Union.tag_type.?"; + const start = ip.string_bytes.items.len; + try ip.string_bytes.ensureUnusedCapacity(gpa, prefix.len + suffix.len + fqn.len); + ip.string_bytes.appendSliceAssumeCapacity(prefix); + ip.string_bytes.appendSliceAssumeCapacity(fqn); + ip.string_bytes.appendSliceAssumeCapacity(suffix); + break :name try ip.getOrPutTrailingString(gpa, ip.string_bytes.items.len - start); }; try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{ .ty = Type.type, @@ -33436,7 +33541,9 @@ fn generateUnionTagTypeSimple( } fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { - var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope); + const gpa = sema.gpa; + + var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope); defer wip_captures.deinit(); var block: Block = .{ @@ -33450,19 +33557,20 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { .is_comptime = true, }; defer { - block.instructions.deinit(sema.gpa); - block.params.deinit(sema.gpa); + block.instructions.deinit(gpa); + block.params.deinit(gpa); } const src = LazySrcLoc.nodeOffset(0); const mod = sema.mod; + const ip = &mod.intern_pool; const std_pkg = mod.main_pkg.table.get("std").?; const std_file = (mod.importPkg(std_pkg) catch unreachable).file; const opt_builtin_inst = (try sema.namespaceLookupRef( &block, src, mod.declPtr(std_file.root_decl.unwrap().?).src_namespace, - "builtin", + try ip.getOrPutString(gpa, "builtin"), )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'"); const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src); const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) { @@ -33473,7 +33581,7 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref { &block, src, builtin_ty.getNamespaceIndex(mod).unwrap().?, - name, + try ip.getOrPutString(gpa, name), )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name}); return sema.analyzeDeclVal(&block, src, opt_ty_decl); } @@ -33608,7 +33716,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count()); for (field_vals, s.fields.values(), 0..) |*field_val, field, i| { if (field.is_comptime) { - field_val.* = try field.default_val.intern(field.ty, mod); + field_val.* = field.default_val; continue; } if (field.ty.eql(resolved_ty, sema.mod)) { @@ -34287,7 +34395,7 @@ fn unionFieldIndex( sema: *Sema, block: *Block, unresolved_union_ty: Type, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; @@ -34302,7 +34410,7 @@ fn structFieldIndex( sema: *Sema, block: *Block, unresolved_struct_ty: Type, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; @@ -34321,19 +34429,17 @@ fn anonStructFieldIndex( sema: *Sema, block: *Block, struct_ty: Type, - field_name: []const u8, + field_name: InternPool.NullTerminatedString, field_src: LazySrcLoc, ) !u32 { const mod = sema.mod; switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) { .anon_struct_type => |anon_struct_type| for (anon_struct_type.names, 0..) |name, i| { - if (mem.eql(u8, mod.intern_pool.stringToSlice(name), field_name)) { - return @intCast(u32, i); - } + if (name == field_name) return @intCast(u32, i); }, .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| { for (struct_obj.fields.keys(), 0..) |name, i| { - if (mem.eql(u8, name, field_name)) { + if (name == field_name) { return @intCast(u32, i); } } @@ -34341,7 +34447,7 @@ fn anonStructFieldIndex( else => unreachable, } return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{ - field_name, struct_ty.fmt(sema.mod), + mod.intern_pool.stringToSlice(field_name), struct_ty.fmt(sema.mod), }); } diff --git a/src/TypedValue.zig b/src/TypedValue.zig index 1ff3ce9415f57d3396ed0868886787a916f5d874..0d771aa18428618e4b142e44be5882168e7ed609 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -201,10 +201,10 @@ pub fn print( }, .variable => return writer.writeAll("(variable)"), .extern_func => |extern_func| return writer.print("(extern function '{s}')", .{ - mod.declPtr(extern_func.decl).name, + mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name), }), - .func => |func| return writer.print("(function '{s}')", .{ - mod.declPtr(mod.funcPtr(func.index).owner_decl).name, + .func => |func| return writer.print("(function '{d}')", .{ + mod.intern_pool.stringToSlice(mod.declPtr(mod.funcPtr(func.index).owner_decl).name), }), .int => |int| switch (int.storage) { inline .u64, .i64, .big_int => |x| return writer.print("{}", .{x}), @@ -296,19 +296,20 @@ fn printAggregate( } if (ty.zigTypeTag(mod) == .Struct) { try writer.writeAll(".{"); - const max_len = std.math.min(ty.structFieldCount(mod), max_aggregate_items); + const max_len = @min(ty.structFieldCount(mod), max_aggregate_items); - var i: u32 = 0; - while (i < max_len) : (i += 1) { + for (0..max_len) |i| { if (i != 0) try writer.writeAll(", "); - if (switch (mod.intern_pool.indexToKey(ty.toIntern())) { - .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[i], - .anon_struct_type => |anon_struct_type| if (anon_struct_type.isTuple()) - null - else - mod.intern_pool.stringToSlice(anon_struct_type.names[i]), + + const field_name = switch (mod.intern_pool.indexToKey(ty.toIntern())) { + .struct_type => |x| mod.structPtrUnwrap(x.index).?.fields.keys()[i].toOptional(), + .anon_struct_type => |x| if (x.isTuple()) .none else x.names[i].toOptional(), else => unreachable, - }) |field_name| try writer.print(".{s} = ", .{field_name}); + }; + + if (field_name.unwrap()) |name_ip| try writer.print(".{s} = ", .{ + mod.intern_pool.stringToSlice(name_ip), + }); try print(.{ .ty = ty.structFieldType(i, mod), .val = try val.fieldValue(mod, i), diff --git a/src/arch/aarch64/CodeGen.zig b/src/arch/aarch64/CodeGen.zig index d01a93dd0d319e85ae3bf71293d150c318271b46..bf945e6983dea2c1087367b1f4eb72b907965eaa 100644 --- a/src/arch/aarch64/CodeGen.zig +++ b/src/arch/aarch64/CodeGen.zig @@ -4350,7 +4350,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier .data = .{ .reg = .x30 }, }); } else if (func_value.getExternFunc(mod)) |extern_func| { - const decl_name = mem.sliceTo(mod.declPtr(extern_func.decl).name, 0); + const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name); const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); if (self.bin_file.cast(link.File.MachO)) |macho_file| { const sym_index = try macho_file.getGlobalSymbol(decl_name, lib_name); diff --git a/src/arch/sparc64/CodeGen.zig b/src/arch/sparc64/CodeGen.zig index fde5424ddce02623a158dde6a5186e8ee11a5f2f..b66012660475e487cbdf0ccfa7e76366a0b484f7 100644 --- a/src/arch/sparc64/CodeGen.zig +++ b/src/arch/sparc64/CodeGen.zig @@ -276,8 +276,6 @@ pub fn generate( assert(fn_owner_decl.has_tv); const fn_type = fn_owner_decl.ty; - log.debug("fn {s}", .{fn_owner_decl.name}); - var branch_stack = std.ArrayList(Branch).init(bin_file.allocator); defer { assert(branch_stack.items.len == 1); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 7b1258155c61d1a97913fc483cfce94ddd3bb7b6..9b7ba19c13a16ce871d59a957bfd5a29a06a2412 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -2208,7 +2208,7 @@ fn airCall(func: *CodeGen, inst: Air.Inst.Index, modifier: std.builtin.CallModif const atom = func.bin_file.getAtomPtr(atom_index); const type_index = try func.bin_file.storeDeclType(extern_func.decl, func_type); try func.bin_file.addOrUpdateImport( - mem.sliceTo(ext_decl.name, 0), + mod.intern_pool.stringToSlice(ext_decl.name), atom.getSymbolIndex().?, mod.intern_pool.stringToSliceUnwrap(ext_decl.getOwnedExternFunc(mod).?.lib_name), type_index, @@ -3180,9 +3180,8 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { } }, .err => |err| { - const name = mod.intern_pool.stringToSlice(err.name); - const kv = try mod.getErrorValue(name); - return WValue{ .imm32 = kv.value }; + const int = try mod.getErrorValue(err.name); + return WValue{ .imm32 = int }; }, .error_union => |error_union| { const err_tv: TypedValue = switch (error_union.val) { @@ -3320,18 +3319,15 @@ fn valueAsI32(func: *const CodeGen, val: Value, ty: Type) i32 { .enum_tag => |enum_tag| intIndexAsI32(&mod.intern_pool, enum_tag.int, mod), .int => |int| intStorageAsI32(int.storage, mod), .ptr => |ptr| intIndexAsI32(&mod.intern_pool, ptr.addr.int, mod), - .err => |err| @bitCast(i32, mod.global_error_set.get(mod.intern_pool.stringToSlice(err.name)).?), + .err => |err| @bitCast(i32, @intCast(Module.ErrorInt, mod.global_error_set.getIndex(err.name).?)), else => unreachable, }, } - switch (ty.zigTypeTag(mod)) { - .ErrorSet => { - const kv = func.bin_file.base.options.module.?.getErrorValue(val.getError(mod).?) catch unreachable; // passed invalid `Value` to function - return @bitCast(i32, kv.value); - }, + return switch (ty.zigTypeTag(mod)) { + .ErrorSet => @bitCast(i32, val.getErrorInt(mod)), else => unreachable, // Programmer called this function for an illegal type - } + }; } fn intIndexAsI32(ip: *const InternPool, int: InternPool.Index, mod: *Module) i32 { @@ -6874,8 +6870,7 @@ fn getTagNameFunction(func: *CodeGen, enum_ty: Type) InnerError!u32 { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const fqn = try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod); - defer mod.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try mod.declPtr(enum_decl_index).getFullyQualifiedName(mod)); const func_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); // check if we already generated code for this. @@ -7037,9 +7032,8 @@ fn airErrorSetHasValue(func: *CodeGen, inst: Air.Inst.Index) InnerError!void { var lowest: ?u32 = null; var highest: ?u32 = null; - for (names) |name_ip| { - const name = mod.intern_pool.stringToSlice(name_ip); - const err_int = mod.global_error_set.get(name).?; + for (names) |name| { + const err_int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); if (lowest) |*l| { if (err_int < l.*) { l.* = err_int; diff --git a/src/arch/x86_64/CodeGen.zig b/src/arch/x86_64/CodeGen.zig index b9cc3f705218df58905b2bb4991fea136a81e201..2675d5350a58ecafefe286a79e08a09c5055e279 100644 --- a/src/arch/x86_64/CodeGen.zig +++ b/src/arch/x86_64/CodeGen.zig @@ -8132,7 +8132,7 @@ fn airCall(self: *Self, inst: Air.Inst.Index, modifier: std.builtin.CallModifier })); } else unreachable; } else if (func_value.getExternFunc(mod)) |extern_func| { - const decl_name = mem.sliceTo(mod.declPtr(extern_func.decl).name, 0); + const decl_name = mod.intern_pool.stringToSlice(mod.declPtr(extern_func.decl).name); const lib_name = mod.intern_pool.stringToSliceUnwrap(extern_func.lib_name); if (self.bin_file.cast(link.File.Coff)) |coff_file| { const atom_index = try self.owner.getSymbolIndex(self); diff --git a/src/codegen.zig b/src/codegen.zig index b0febb5ea72a7b63500e1b0575b1a17602f77c70..77359d78da0afe666df0fff145d047fe1d39d978 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -142,11 +142,12 @@ pub fn generateLazySymbol( if (lazy_sym.ty.isAnyError(mod)) { alignment.* = 4; - const err_names = mod.error_name_list.items; + const err_names = mod.global_error_set.keys(); mem.writeInt(u32, try code.addManyAsArray(4), @intCast(u32, err_names.len), endian); var offset = code.items.len; try code.resize((1 + err_names.len + 1) * 4); - for (err_names) |err_name| { + for (err_names) |err_name_nts| { + const err_name = mod.intern_pool.stringToSlice(err_name_nts); mem.writeInt(u32, code.items[offset..][0..4], @intCast(u32, code.items.len), endian); offset += 4; try code.ensureUnusedCapacity(err_name.len + 1); @@ -251,15 +252,13 @@ pub fn generateSymbol( val.writeTwosComplement(try code.addManyAsSlice(abi_size), endian); }, .err => |err| { - const name = mod.intern_pool.stringToSlice(err.name); - const kv = try mod.getErrorValue(name); - try code.writer().writeInt(u16, @intCast(u16, kv.value), endian); + const int = try mod.getErrorValue(err.name); + try code.writer().writeInt(u16, @intCast(u16, int), endian); }, .error_union => |error_union| { const payload_ty = typed_value.ty.errorUnionPayload(mod); - const err_val = switch (error_union.val) { - .err_name => |err_name| @intCast(u16, (try mod.getErrorValue(mod.intern_pool.stringToSlice(err_name))).value), + .err_name => |err_name| @intCast(u16, try mod.getErrorValue(err_name)), .payload => @as(u16, 0), }; @@ -974,11 +973,8 @@ pub fn genTypedValue( }, owner_decl_index); }, .ErrorSet => { - const err_name = mod.intern_pool.stringToSlice( - mod.intern_pool.indexToKey(typed_value.val.toIntern()).err.name, - ); - const global_error_set = mod.global_error_set; - const error_index = global_error_set.get(err_name).?; + const err_name = mod.intern_pool.indexToKey(typed_value.val.toIntern()).err.name; + const error_index = mod.global_error_set.getIndex(err_name).?; return GenResult.mcv(.{ .immediate = error_index }); }, .ErrorUnion => { diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 4b325122cad6f4094867653293b7b3ac63d3e731..7b091d682362d29a709e11c503193861dd9c7212 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -452,6 +452,7 @@ pub const Function = struct { var promoted = f.object.dg.ctypes.promote(gpa); defer f.object.dg.ctypes.demote(promoted); const arena = promoted.arena.allocator(); + const mod = f.object.dg.module; gop.value_ptr.* = .{ .fn_name = switch (key) { @@ -460,7 +461,7 @@ pub const Function = struct { .never_inline, => |owner_decl| try std.fmt.allocPrint(arena, "zig_{s}_{}__{d}", .{ @tagName(key), - fmtIdent(mem.span(f.object.dg.module.declPtr(owner_decl).name)), + fmtIdent(mod.intern_pool.stringToSlice(mod.declPtr(owner_decl).name)), @enumToInt(owner_decl), }), }, @@ -1465,7 +1466,7 @@ pub const DeclGen = struct { try writer.writeAll(" .payload = {"); } if (field_ty.hasRuntimeBits(mod)) { - try writer.print(" .{ } = ", .{fmtIdent(field_name)}); + try writer.print(" .{ } = ", .{fmtIdent(mod.intern_pool.stringToSlice(field_name))}); try dg.renderValue(writer, field_ty, un.val.toValue(), initializer_type); try writer.writeByte(' '); } else for (ty.unionFields(mod).values()) |field| { @@ -1849,9 +1850,9 @@ pub const DeclGen = struct { try mod.markDeclAlive(decl); if (mod.decl_exports.get(decl_index)) |exports| { - try writer.writeAll(exports.items[export_index].options.name); + try writer.writeAll(mod.intern_pool.stringToSlice(exports.items[export_index].name)); } else if (decl.isExtern(mod)) { - try writer.writeAll(mem.span(decl.name)); + try writer.writeAll(mod.intern_pool.stringToSlice(decl.name)); } else { // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case), // expand to 3x the length of its input, but let's cut it off at a much shorter limit. @@ -1987,7 +1988,7 @@ fn renderTypeName( try w.print("{s} {s}{}__{d}", .{ @tagName(tag)["fwd_".len..], attributes, - fmtIdent(mem.span(mod.declPtr(owner_decl).name)), + fmtIdent(mod.intern_pool.stringToSlice(mod.declPtr(owner_decl).name)), @enumToInt(owner_decl), }); }, @@ -2406,11 +2407,12 @@ pub fn genErrDecls(o: *Object) !void { try writer.writeAll("enum {\n"); o.indent_writer.pushIndent(); var max_name_len: usize = 0; - for (mod.error_name_list.items[1..], 1..) |name, value| { - max_name_len = std.math.max(name.len, max_name_len); + for (mod.global_error_set.keys()[1..], 1..) |name_nts, value| { + const name = mod.intern_pool.stringToSlice(name_nts); + max_name_len = @max(name.len, max_name_len); const err_val = try mod.intern(.{ .err = .{ .ty = .anyerror_type, - .name = mod.intern_pool.getString(name).unwrap().?, + .name = name_nts, } }); try o.dg.renderValue(writer, Type.anyerror, err_val.toValue(), .Other); try writer.print(" = {d}u,\n", .{value}); @@ -2424,7 +2426,8 @@ pub fn genErrDecls(o: *Object) !void { defer o.dg.gpa.free(name_buf); @memcpy(name_buf[0..name_prefix.len], name_prefix); - for (mod.error_name_list.items) |name| { + for (mod.global_error_set.keys()) |name_nts| { + const name = mod.intern_pool.stringToSlice(name_nts); @memcpy(name_buf[name_prefix.len..][0..name.len], name); const identifier = name_buf[0 .. name_prefix.len + name.len]; @@ -2446,14 +2449,15 @@ pub fn genErrDecls(o: *Object) !void { } const name_array_ty = try mod.arrayType(.{ - .len = mod.error_name_list.items.len, + .len = mod.global_error_set.count(), .child = .slice_const_u8_sentinel_0_type, }); try writer.writeAll("static "); try o.dg.renderTypeAndName(writer, name_array_ty, .{ .identifier = array_identifier }, Const, 0, .complete); try writer.writeAll(" = {"); - for (mod.error_name_list.items, 0..) |name, value| { + for (mod.global_error_set.keys(), 0..) |name_nts, value| { + const name = mod.intern_pool.stringToSlice(name_nts); if (value != 0) try writer.writeByte(','); const len_val = try mod.intValue(Type.usize, name.len); @@ -2469,14 +2473,16 @@ fn genExports(o: *Object) !void { const tracy = trace(@src()); defer tracy.end(); + const mod = o.dg.module; + const ip = &mod.intern_pool; const fwd_decl_writer = o.dg.fwd_decl.writer(); - if (o.dg.module.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| { + if (mod.decl_exports.get(o.dg.decl_index.unwrap().?)) |exports| { for (exports.items[1..], 1..) |@"export", i| { try fwd_decl_writer.writeAll("zig_export("); try o.dg.renderFunctionSignature(fwd_decl_writer, o.dg.decl_index.unwrap().?, .forward, .{ .export_index = @intCast(u32, i) }); try fwd_decl_writer.print(", {s}, {s});\n", .{ - fmtStringLiteral(exports.items[0].options.name, null), - fmtStringLiteral(@"export".options.name, null), + fmtStringLiteral(ip.stringToSlice(exports.items[0].name), null), + fmtStringLiteral(ip.stringToSlice(@"export".name), null), }); } } @@ -2680,9 +2686,10 @@ pub fn genDecl(o: *Object) !void { if (!is_global) try w.writeAll("static "); if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage "); - if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); + if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| + try w.print("zig_linksection(\"{s}\", ", .{s}); try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.@"align", .complete); - if (decl.@"linksection" != null) try w.writeAll(", read, write)"); + if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); try w.writeAll(" = "); try o.dg.renderValue(w, tv.ty, variable.init.toValue(), .StaticInitializer); try w.writeByte(';'); @@ -2697,9 +2704,10 @@ pub fn genDecl(o: *Object) !void { const w = o.writer(); if (!is_global) try w.writeAll("static "); - if (decl.@"linksection") |section| try w.print("zig_linksection(\"{s}\", ", .{section}); + if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| + try w.print("zig_linksection(\"{s}\", ", .{s}); try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.@"align", .complete); - if (decl.@"linksection" != null) try w.writeAll(", read)"); + if (decl.@"linksection" != .none) try w.writeAll(", read)"); try w.writeAll(" = "); try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); try w.writeAll(";\n"); @@ -4229,7 +4237,9 @@ fn airDbgInline(f: *Function, inst: Air.Inst.Index) !CValue { const mod = f.object.dg.module; const writer = f.object.writer(); const function = mod.funcPtr(ty_fn.func); - try writer.print("/* dbg func:{s} */\n", .{mod.declPtr(function.owner_decl).name}); + try writer.print("/* dbg func:{s} */\n", .{ + mod.intern_pool.stringToSlice(mod.declPtr(function.owner_decl).name), + }); return .none; } @@ -5176,6 +5186,7 @@ fn fieldLocation( byte_offset: u32, end: void, } { + const ip = &mod.intern_pool; return switch (container_ty.zigTypeTag(mod)) { .Struct => switch (container_ty.containerLayout(mod)) { .Auto, .Extern => for (field_index..container_ty.structFieldCount(mod)) |next_field_index| { @@ -5186,7 +5197,7 @@ fn fieldLocation( break .{ .field = if (container_ty.isSimpleTuple(mod)) .{ .field = next_field_index } else - .{ .identifier = container_ty.structFieldName(next_field_index, mod) } }; + .{ .identifier = ip.stringToSlice(container_ty.structFieldName(next_field_index, mod)) } }; } else if (container_ty.hasRuntimeBitsIgnoreComptime(mod)) .end else .begin, .Packed => if (field_ptr_ty.ptrInfo(mod).host_size == 0) .{ .byte_offset = container_ty.packedStructFieldByteOffset(field_index, mod) } @@ -5204,9 +5215,9 @@ fn fieldLocation( .begin; const field_name = container_ty.unionFields(mod).keys()[field_index]; return .{ .field = if (container_ty.unionTagTypeSafety(mod)) |_| - .{ .payload_identifier = field_name } + .{ .payload_identifier = ip.stringToSlice(field_name) } else - .{ .identifier = field_name } }; + .{ .identifier = ip.stringToSlice(field_name) } }; }, .Packed => .begin, }, @@ -5347,6 +5358,7 @@ fn fieldPtr( fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { const mod = f.object.dg.module; + const ip = &mod.intern_pool; const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const extra = f.air.extraData(Air.StructField, ty_pl.payload).data; @@ -5369,7 +5381,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { .Auto, .Extern => if (struct_ty.isSimpleTuple(mod)) .{ .field = extra.field_index } else - .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, + .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, .Packed => { const struct_obj = mod.typeToStruct(struct_ty).?; const int_info = struct_ty.intInfo(mod); @@ -5431,7 +5443,7 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 0) .{ .field = extra.field_index } else - .{ .identifier = struct_ty.structFieldName(extra.field_index, mod) }, + .{ .identifier = ip.stringToSlice(struct_ty.structFieldName(extra.field_index, mod)) }, .union_type => |union_type| field_name: { const union_obj = mod.unionPtr(union_type.index); @@ -5462,9 +5474,9 @@ fn airStructFieldVal(f: *Function, inst: Air.Inst.Index) !CValue { } else { const name = union_obj.fields.keys()[extra.field_index]; break :field_name if (union_type.hasTag()) .{ - .payload_identifier = name, + .payload_identifier = ip.stringToSlice(name), } else .{ - .identifier = name, + .identifier = ip.stringToSlice(name), }; } }, @@ -6723,6 +6735,7 @@ fn airReduce(f: *Function, inst: Air.Inst.Index) !CValue { fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { const mod = f.object.dg.module; + const ip = &mod.intern_pool; const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const inst_ty = f.typeOfIndex(inst); const len = @intCast(usize, inst_ty.arrayLen(mod)); @@ -6773,7 +6786,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { try f.writeCValueMember(writer, local, if (inst_ty.isSimpleTuple(mod)) .{ .field = field_i } else - .{ .identifier = inst_ty.structFieldName(field_i, mod) }); + .{ .identifier = ip.stringToSlice(inst_ty.structFieldName(field_i, mod)) }); try a.assign(f, writer); try f.writeCValue(writer, element, .Other); try a.end(f, writer); @@ -6851,6 +6864,7 @@ fn airAggregateInit(f: *Function, inst: Air.Inst.Index) !CValue { fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { const mod = f.object.dg.module; + const ip = &mod.intern_pool; const ty_pl = f.air.instructions.items(.data)[inst].ty_pl; const extra = f.air.extraData(Air.UnionInit, ty_pl.payload).data; @@ -6886,8 +6900,8 @@ fn airUnionInit(f: *Function, inst: Air.Inst.Index) !CValue { try writer.print("{}", .{try f.fmtIntLiteral(tag_ty, int_val)}); try a.end(f, writer); } - break :field .{ .payload_identifier = field_name }; - } else .{ .identifier = field_name }; + break :field .{ .payload_identifier = ip.stringToSlice(field_name) }; + } else .{ .identifier = ip.stringToSlice(field_name) }; const a = try Assignment.start(f, writer, payload_ty); try f.writeCValueMember(writer, local, field); diff --git a/src/codegen/c/type.zig b/src/codegen/c/type.zig index dc1749d42e0e46fdf0a675abec38f0b75f1a87a0..81ca1dd80d5bfc984ce1a48e37c3d2e306bdb53e 100644 --- a/src/codegen/c/type.zig +++ b/src/codegen/c/type.zig @@ -1953,11 +1953,11 @@ pub const CType = extern union { .name = try if (ty.isSimpleTuple(mod)) std.fmt.allocPrintZ(arena, "f{}", .{field_i}) else - arena.dupeZ(u8, switch (zig_ty_tag) { + arena.dupeZ(u8, mod.intern_pool.stringToSlice(switch (zig_ty_tag) { .Struct => ty.structFieldName(field_i, mod), .Union => ty.unionFields(mod).keys()[field_i], else => unreachable, - }), + })), .type = store.set.typeToIndex(field_ty, mod, switch (kind) { .forward, .forward_parameter => .forward, .complete, .parameter, .payload => .complete, @@ -2102,12 +2102,13 @@ pub const CType = extern union { }) or !mem.eql( u8, if (ty.isSimpleTuple(mod)) - std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable - else switch (zig_ty_tag) { - .Struct => ty.structFieldName(field_i, mod), - .Union => ty.unionFields(mod).keys()[field_i], - else => unreachable, - }, + std.fmt.bufPrintZ(&name_buf, "f{}", .{field_i}) catch unreachable + else + mod.intern_pool.stringToSlice(switch (zig_ty_tag) { + .Struct => ty.structFieldName(field_i, mod), + .Union => ty.unionFields(mod).keys()[field_i], + else => unreachable, + }), mem.span(c_field.name), ) or AlignAs.fieldAlign(ty, field_i, mod).@"align" != c_field.alignas.@"align") return false; @@ -2225,11 +2226,12 @@ pub const CType = extern union { }); hasher.update(if (ty.isSimpleTuple(mod)) std.fmt.bufPrint(&name_buf, "f{}", .{field_i}) catch unreachable - else switch (zig_ty_tag) { - .Struct => ty.structFieldName(field_i, mod), - .Union => ty.unionFields(mod).keys()[field_i], - else => unreachable, - }); + else + mod.intern_pool.stringToSlice(switch (zig_ty_tag) { + .Struct => ty.structFieldName(field_i, mod), + .Union => ty.unionFields(mod).keys()[field_i], + else => unreachable, + })); autoHash(hasher, AlignAs.fieldAlign(ty, field_i, mod).@"align"); } }, diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index be6ca714a61396c4bad92c1e77dcf77431f46d41..bd5052809512a51d224abbca225abf78ca09666b 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -585,13 +585,13 @@ pub const Object = struct { const slice_ty = Type.slice_const_u8_sentinel_0; const slice_alignment = slice_ty.abiAlignment(mod); - const error_name_list = mod.error_name_list.items; + const error_name_list = mod.global_error_set.keys(); const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len); defer mod.gpa.free(llvm_errors); llvm_errors[0] = llvm_slice_ty.getUndef(); - for (llvm_errors[1..], 0..) |*llvm_error, i| { - const name = error_name_list[1..][i]; + for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| { + const name = mod.intern_pool.stringToSlice(name_nts); const str_init = self.context.constString(name.ptr, @intCast(c_uint, name.len), .False); const str_global = self.llvm_module.addGlobal(str_init.typeOf(), ""); str_global.setInitializer(str_init); @@ -671,7 +671,7 @@ pub const Object = struct { const llvm_global = entry.value_ptr.*; // Same logic as below but for externs instead of exports. const decl = mod.declPtr(decl_index); - const other_global = object.getLlvmGlobal(decl.name) orelse continue; + const other_global = object.getLlvmGlobal(mod.intern_pool.stringToSlice(decl.name)) orelse continue; if (other_global == llvm_global) continue; llvm_global.replaceAllUsesWith(other_global); @@ -689,8 +689,7 @@ pub const Object = struct { // case, we need to replace all uses of it with this exported global. // TODO update std.builtin.ExportOptions to have the name be a // null-terminated slice. - const exp_name_z = try mod.gpa.dupeZ(u8, exp.options.name); - defer mod.gpa.free(exp_name_z); + const exp_name_z = mod.intern_pool.stringToSlice(exp.name); const other_global = object.getLlvmGlobal(exp_name_z.ptr) orelse continue; if (other_global == llvm_global) continue; @@ -923,9 +922,8 @@ pub const Object = struct { dg.addFnAttrString(llvm_func, "no-stack-arg-probe", ""); } - if (decl.@"linksection") |section| { + if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| llvm_func.setSection(section); - } // Remove all the basic blocks of a function in order to start over, generating // LLVM IR from an empty function body. @@ -1173,7 +1171,7 @@ pub const Object = struct { 0; const subprogram = dib.createFunction( di_file.?.toScope(), - decl.name, + mod.intern_pool.stringToSlice(decl.name), llvm_func.getValueName(), di_file.?, line_number, @@ -1273,22 +1271,26 @@ pub const Object = struct { if (decl.isExtern(mod)) { var free_decl_name = false; const decl_name = decl_name: { + const decl_name = mod.intern_pool.stringToSlice(decl.name); + if (mod.getTarget().isWasm() and try decl.isFunction(mod)) { if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { if (!std.mem.eql(u8, lib_name, "c")) { free_decl_name = true; - break :decl_name try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{ decl.name, lib_name }); + break :decl_name try std.fmt.allocPrintZ(gpa, "{s}|{s}", .{ + decl_name, lib_name, + }); } } } - break :decl_name std.mem.span(decl.name); + + break :decl_name decl_name; }; defer if (free_decl_name) gpa.free(decl_name); llvm_global.setValueName(decl_name); if (self.getLlvmGlobal(decl_name)) |other_global| { if (other_global != llvm_global) { - log.debug("updateDeclExports isExtern()=true setValueName({s}) conflict", .{decl.name}); try self.extern_collisions.put(gpa, decl_index, {}); } } @@ -1298,11 +1300,11 @@ pub const Object = struct { if (self.di_map.get(decl)) |di_node| { if (try decl.isFunction(mod)) { const di_func = @ptrCast(*llvm.DISubprogram, di_node); - const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name)); + const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len); di_func.replaceLinkageName(linkage_name); } else { const di_global = @ptrCast(*llvm.DIGlobalVariable, di_node); - const linkage_name = llvm.MDString.get(self.context, decl.name, std.mem.len(decl.name)); + const linkage_name = llvm.MDString.get(self.context, decl_name.ptr, decl_name.len); di_global.replaceLinkageName(linkage_name); } } @@ -1317,7 +1319,7 @@ pub const Object = struct { } } } else if (exports.len != 0) { - const exp_name = exports[0].options.name; + const exp_name = mod.intern_pool.stringToSlice(exports[0].name); llvm_global.setValueName2(exp_name.ptr, exp_name.len); llvm_global.setUnnamedAddr(.False); if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport); @@ -1332,21 +1334,19 @@ pub const Object = struct { di_global.replaceLinkageName(linkage_name); } } - switch (exports[0].options.linkage) { + switch (exports[0].linkage) { .Internal => unreachable, .Strong => llvm_global.setLinkage(.External), .Weak => llvm_global.setLinkage(.WeakODR), .LinkOnce => llvm_global.setLinkage(.LinkOnceODR), } - switch (exports[0].options.visibility) { + switch (exports[0].visibility) { .default => llvm_global.setVisibility(.Default), .hidden => llvm_global.setVisibility(.Hidden), .protected => llvm_global.setVisibility(.Protected), } - if (exports[0].options.section) |section| { - const section_z = try gpa.dupeZ(u8, section); - defer gpa.free(section_z); - llvm_global.setSection(section_z); + if (mod.intern_pool.stringToSliceUnwrap(exports[0].section)) |section| { + llvm_global.setSection(section); } if (decl.val.getVariable(mod)) |variable| { if (variable.is_threadlocal) { @@ -1356,13 +1356,12 @@ pub const Object = struct { // If a Decl is exported more than one time (which is rare), // we add aliases for all but the first export. - // TODO LLVM C API does not support deleting aliases. We need to - // patch it to support this or figure out how to wrap the C++ API ourselves. + // TODO LLVM C API does not support deleting aliases. + // The planned solution to this is https://github.com/ziglang/zig/issues/13265 // Until then we iterate over existing aliases and make them point // to the correct decl, or otherwise add a new alias. Old aliases are leaked. for (exports[1..]) |exp| { - const exp_name_z = try gpa.dupeZ(u8, exp.options.name); - defer gpa.free(exp_name_z); + const exp_name_z = mod.intern_pool.stringToSlice(exp.name); if (self.llvm_module.getNamedGlobalAlias(exp_name_z.ptr, exp_name_z.len)) |alias| { alias.setAliasee(llvm_global); @@ -1376,8 +1375,7 @@ pub const Object = struct { } } } else { - const fqn = try decl.getFullyQualifiedName(mod); - defer gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); llvm_global.setValueName2(fqn.ptr, fqn.len); llvm_global.setLinkage(.Internal); if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default); @@ -2092,8 +2090,7 @@ pub const Object = struct { const field_offset = std.mem.alignForwardGeneric(u64, offset, field_align); offset = field_offset + field_size; - const field_name = try gpa.dupeZ(u8, fields.keys()[field_and_index.index]); - defer gpa.free(field_name); + const field_name = mod.intern_pool.stringToSlice(fields.keys()[field_and_index.index]); try di_fields.append(gpa, dib.createMemberType( fwd_decl.toScope(), @@ -2200,12 +2197,9 @@ pub const Object = struct { const field_size = field.ty.abiSize(mod); const field_align = field.normalAlignment(mod); - const field_name_copy = try gpa.dupeZ(u8, field_name); - defer gpa.free(field_name_copy); - di_fields.appendAssumeCapacity(dib.createMemberType( fwd_decl.toScope(), - field_name_copy, + mod.intern_pool.stringToSlice(field_name), null, // file 0, // line field_size * 8, // size in bits @@ -2327,7 +2321,7 @@ pub const Object = struct { if (fn_info.return_type.toType().isError(mod) and o.module.comp.bin_file.options.error_return_tracing) { - const ptr_ty = try mod.singleMutPtrType(o.getStackTraceType()); + const ptr_ty = try mod.singleMutPtrType(try o.getStackTraceType()); try param_di_types.append(try o.lowerDebugType(ptr_ty, .full)); } @@ -2384,7 +2378,7 @@ pub const Object = struct { const fields: [0]*llvm.DIType = .{}; return o.di_builder.?.createStructType( try o.namespaceToDebugScope(decl.src_namespace), - decl.name, // TODO use fully qualified name + mod.intern_pool.stringToSlice(decl.name), // TODO use fully qualified name try o.getDIFile(o.gpa, mod.namespacePtr(decl.src_namespace).file_scope), decl.src_line + 1, 0, // size in bits @@ -2399,18 +2393,18 @@ pub const Object = struct { ); } - fn getStackTraceType(o: *Object) Type { + fn getStackTraceType(o: *Object) Allocator.Error!Type { const mod = o.module; const std_pkg = mod.main_pkg.table.get("std").?; const std_file = (mod.importPkg(std_pkg) catch unreachable).file; - const builtin_str: []const u8 = "builtin"; + const builtin_str = try mod.intern_pool.getOrPutString(mod.gpa, "builtin"); const std_namespace = mod.namespacePtr(mod.declPtr(std_file.root_decl.unwrap().?).src_namespace); const builtin_decl = std_namespace.decls .getKeyAdapted(builtin_str, Module.DeclAdapter{ .mod = mod }).?; - const stack_trace_str: []const u8 = "StackTrace"; + const stack_trace_str = try mod.intern_pool.getOrPutString(mod.gpa, "StackTrace"); // buffer is only used for int_type, `builtin` is a struct. const builtin_ty = mod.declPtr(builtin_decl).val.toType(); const builtin_namespace = builtin_ty.getNamespace(mod).?; @@ -2452,16 +2446,13 @@ pub const DeclGen = struct { const decl_index = dg.decl_index; assert(decl.has_tv); - log.debug("gen: {s} type: {}, value: {}", .{ - decl.name, decl.ty.fmtDebug(), decl.val.fmtDebug(), - }); if (decl.val.getExternFunc(mod)) |extern_func| { _ = try dg.resolveLlvmFunction(extern_func.decl); } else { const target = mod.getTarget(); var global = try dg.resolveGlobalDecl(decl_index); global.setAlignment(decl.getAlignment(mod)); - if (decl.@"linksection") |section| global.setSection(section); + if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| global.setSection(s); assert(decl.has_tv); const init_val = if (decl.val.getVariable(mod)) |variable| init_val: { break :init_val variable.init; @@ -2495,7 +2486,8 @@ pub const DeclGen = struct { new_global.setLinkage(global.getLinkage()); new_global.setUnnamedAddr(global.getUnnamedAddress()); new_global.setAlignment(global.getAlignment()); - if (decl.@"linksection") |section| new_global.setSection(section); + if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| + new_global.setSection(s); new_global.setInitializer(llvm_init); // TODO: How should this work then the address space of a global changed? global.replaceAllUsesWith(new_global); @@ -2513,7 +2505,7 @@ pub const DeclGen = struct { const is_internal_linkage = !dg.module.decl_exports.contains(decl_index); const di_global = dib.createGlobalVariableExpression( di_file.toScope(), - decl.name, + mod.intern_pool.stringToSlice(decl.name), global.getValueName(), di_file, line_number, @@ -2544,8 +2536,7 @@ pub const DeclGen = struct { const fn_type = try dg.lowerType(zig_fn_type); - const fqn = try decl.getFullyQualifiedName(mod); - defer dg.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const llvm_addrspace = toLlvmAddressSpace(decl.@"addrspace", target); const llvm_fn = dg.llvmModule().addFunctionInAddressSpace(fqn, fn_type, llvm_addrspace); @@ -2557,7 +2548,7 @@ pub const DeclGen = struct { llvm_fn.setUnnamedAddr(.True); } else { if (target.isWasm()) { - dg.addFnAttrString(llvm_fn, "wasm-import-name", std.mem.sliceTo(decl.name, 0)); + dg.addFnAttrString(llvm_fn, "wasm-import-name", mod.intern_pool.stringToSlice(decl.name)); if (mod.intern_pool.stringToSliceUnwrap(decl.getOwnedExternFunc(mod).?.lib_name)) |lib_name| { if (!std.mem.eql(u8, lib_name, "c")) { dg.addFnAttrString(llvm_fn, "wasm-import-module", lib_name); @@ -2699,8 +2690,7 @@ pub const DeclGen = struct { const mod = dg.module; const decl = mod.declPtr(decl_index); - const fqn = try decl.getFullyQualifiedName(mod); - defer dg.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const target = mod.getTarget(); @@ -2716,7 +2706,7 @@ pub const DeclGen = struct { // This is needed for declarations created by `@extern`. if (decl.isExtern(mod)) { - llvm_global.setValueName(decl.name); + llvm_global.setValueName(mod.intern_pool.stringToSlice(decl.name)); llvm_global.setUnnamedAddr(.False); llvm_global.setLinkage(.External); if (decl.val.getVariable(mod)) |variable| { @@ -2811,8 +2801,7 @@ pub const DeclGen = struct { if (gop.found_existing) return gop.value_ptr.*; const opaque_type = mod.intern_pool.indexToKey(t.toIntern()).opaque_type; - const name = try mod.opaqueFullyQualifiedName(opaque_type); - defer gpa.free(name); + const name = mod.intern_pool.stringToSlice(try mod.opaqueFullyQualifiedName(opaque_type)); const llvm_struct_ty = dg.context.structCreateNamed(name); gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls @@ -2963,8 +2952,7 @@ pub const DeclGen = struct { return int_llvm_ty; } - const name = try struct_obj.getFullyQualifiedName(mod); - defer gpa.free(name); + const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(mod)); const llvm_struct_ty = dg.context.structCreateNamed(name); gop.value_ptr.* = llvm_struct_ty; // must be done before any recursive calls @@ -3040,8 +3028,7 @@ pub const DeclGen = struct { return enum_tag_llvm_ty; } - const name = try union_obj.getFullyQualifiedName(mod); - defer gpa.free(name); + const name = mod.intern_pool.stringToSlice(try union_obj.getFullyQualifiedName(mod)); const llvm_union_ty = dg.context.structCreateNamed(name); gop.value_ptr.* = llvm_union_ty; // must be done before any recursive calls @@ -3119,7 +3106,7 @@ pub const DeclGen = struct { if (fn_info.return_type.toType().isError(mod) and mod.comp.bin_file.options.error_return_tracing) { - const ptr_ty = try mod.singleMutPtrType(dg.object.getStackTraceType()); + const ptr_ty = try mod.singleMutPtrType(try dg.object.getStackTraceType()); try llvm_params.append(try dg.lowerType(ptr_ty)); } @@ -3266,9 +3253,8 @@ pub const DeclGen = struct { }, .err => |err| { const llvm_ty = try dg.lowerType(Type.anyerror); - const name = mod.intern_pool.stringToSlice(err.name); - const kv = try mod.getErrorValue(name); - return llvm_ty.constInt(kv.value, .False); + const int = try mod.getErrorValue(err.name); + return llvm_ty.constInt(int, .False); }, .error_union => |error_union| { const err_tv: TypedValue = switch (error_union.val) { @@ -5960,8 +5946,7 @@ pub const FuncGen = struct { .base_line = self.base_line, }); - const fqn = try decl.getFullyQualifiedName(mod); - defer self.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const is_internal_linkage = !mod.decl_exports.contains(decl_index); const fn_ty = try mod.funcType(.{ @@ -5981,7 +5966,7 @@ pub const FuncGen = struct { }); const subprogram = dib.createFunction( di_file.toScope(), - decl.name, + mod.intern_pool.stringToSlice(decl.name), fqn, di_file, line_number, @@ -8629,9 +8614,8 @@ pub const FuncGen = struct { const end_block = self.context.appendBasicBlock(self.llvm_func, "End"); const switch_instr = self.builder.buildSwitch(operand, invalid_block, @intCast(c_uint, names.len)); - for (names) |name_ip| { - const name = mod.intern_pool.stringToSlice(name_ip); - const err_int = mod.global_error_set.get(name).?; + for (names) |name| { + const err_int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); const this_tag_int_value = try self.dg.lowerValue(.{ .ty = Type.err_int, .val = try mod.intValue(Type.err_int, err_int), @@ -8681,8 +8665,7 @@ pub const FuncGen = struct { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); - defer self.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod)); const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_is_named_enum_value_{s}", .{fqn}); const param_types = [_]*llvm.Type{try self.dg.lowerType(enum_type.tag_ty.toType())}; @@ -8754,8 +8737,7 @@ pub const FuncGen = struct { defer arena_allocator.deinit(); const arena = arena_allocator.allocator(); - const fqn = try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod); - defer self.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try mod.declPtr(enum_type.decl).getFullyQualifiedName(mod)); const llvm_fn_name = try std.fmt.allocPrintZ(arena, "__zig_tag_name_{s}", .{fqn}); const slice_ty = Type.slice_const_u8_sentinel_0; diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 85caec94902fa6229bad07589fb1feae1aec3c68..4fd91aded4bc5849fca3e6478fa6567463734107 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -593,7 +593,6 @@ pub const DeclGen = struct { .extern_func => unreachable, // TODO else => { const result_id = dg.spv.allocId(); - log.debug("addDeclRef: id = {}, index = {}, name = {s}", .{ result_id.id, @enumToInt(spv_decl_index), decl.name }); try self.decl_deps.put(spv_decl_index, {}); @@ -664,9 +663,8 @@ pub const DeclGen = struct { => unreachable, // non-runtime values .int => try self.addInt(ty, val), .err => |err| { - const name = mod.intern_pool.stringToSlice(err.name); - const kv = try mod.getErrorValue(name); - try self.addConstInt(u16, @intCast(u16, kv.value)); + const int = try mod.getErrorValue(err.name); + try self.addConstInt(u16, @intCast(u16, int)); }, .error_union => |error_union| { const payload_ty = ty.errorUnionPayload(mod); @@ -1288,8 +1286,7 @@ pub const DeclGen = struct { member_index += 1; } - const name = try struct_obj.getFullyQualifiedName(self.module); - defer self.module.gpa.free(name); + const name = mod.intern_pool.stringToSlice(try struct_obj.getFullyQualifiedName(self.module)); return try self.spv.resolve(.{ .struct_type = .{ .name = try self.spv.resolveString(name), @@ -1500,7 +1497,6 @@ pub const DeclGen = struct { const spv_decl_index = try self.resolveDecl(self.decl_index); const decl_id = self.spv.declPtr(spv_decl_index).result_id; - log.debug("genDecl: id = {}, index = {}, name = {s}", .{ decl_id.id, @enumToInt(spv_decl_index), decl.name }); if (decl.val.getFunction(mod)) |_| { assert(decl.ty.zigTypeTag(mod) == .Fn); @@ -1542,8 +1538,7 @@ pub const DeclGen = struct { try self.func.body.emit(self.spv.gpa, .OpFunctionEnd, {}); try self.spv.addFunction(spv_decl_index, self.func); - const fqn = try decl.getFullyQualifiedName(self.module); - defer self.module.gpa.free(fqn); + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(self.module)); try self.spv.sections.debug_names.emit(self.gpa, .OpName, .{ .target = decl_id, diff --git a/src/link.zig b/src/link.zig index a44a7387e9e6dde8c8ad43fa935fcfb8277480cf..e43153f0b1fbbb4a99248ad2805a7ea0c05e1106 100644 --- a/src/link.zig +++ b/src/link.zig @@ -502,8 +502,6 @@ pub const File = struct { /// of the final binary. pub fn lowerUnnamedConst(base: *File, tv: TypedValue, decl_index: Module.Decl.Index) UpdateDeclError!u32 { if (build_options.only_c) @compileError("unreachable"); - const decl = base.options.module.?.declPtr(decl_index); - log.debug("lowerUnnamedConst {*} ({s})", .{ decl, decl.name }); switch (base.tag) { // zig fmt: off .coff => return @fieldParentPtr(Coff, "base", base).lowerUnnamedConst(tv, decl_index), @@ -543,7 +541,6 @@ pub const File = struct { /// May be called before or after updateDeclExports for any given Decl. pub fn updateDecl(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { const decl = module.declPtr(decl_index); - log.debug("updateDecl {*} ({s}), type={}", .{ decl, decl.name, decl.ty.fmt(module) }); assert(decl.has_tv); if (build_options.only_c) { assert(base.tag == .c); @@ -566,10 +563,6 @@ pub const File = struct { /// May be called before or after updateDeclExports for any given Decl. pub fn updateFunc(base: *File, module: *Module, func_index: Module.Fn.Index, air: Air, liveness: Liveness) UpdateDeclError!void { const func = module.funcPtr(func_index); - const owner_decl = module.declPtr(func.owner_decl); - log.debug("updateFunc {*} ({s}), type={}", .{ - owner_decl, owner_decl.name, owner_decl.ty.fmt(module), - }); if (build_options.only_c) { assert(base.tag == .c); return @fieldParentPtr(C, "base", base).updateFunc(module, func, air, liveness); @@ -590,9 +583,6 @@ pub const File = struct { pub fn updateDeclLineNumber(base: *File, module: *Module, decl_index: Module.Decl.Index) UpdateDeclError!void { const decl = module.declPtr(decl_index); - log.debug("updateDeclLineNumber {*} ({s}), line={}", .{ - decl, decl.name, decl.src_line + 1, - }); assert(decl.has_tv); if (build_options.only_c) { assert(base.tag == .c); @@ -868,7 +858,6 @@ pub const File = struct { exports: []const *Module.Export, ) UpdateDeclExportsError!void { const decl = module.declPtr(decl_index); - log.debug("updateDeclExports {*} ({s})", .{ decl, decl.name }); assert(decl.has_tv); if (build_options.only_c) { assert(base.tag == .c); diff --git a/src/link/C.zig b/src/link/C.zig index c871d8a02af94ae070e2e839dd839b98293dd2e1..8bfaf1553ce2f86589734ab904764745bba155cc 100644 --- a/src/link/C.zig +++ b/src/link/C.zig @@ -6,6 +6,7 @@ const fs = std.fs; const C = @This(); const Module = @import("../Module.zig"); +const InternPool = @import("../InternPool.zig"); const Compilation = @import("../Compilation.zig"); const codegen = @import("../codegen/c.zig"); const link = @import("../link.zig"); @@ -289,11 +290,11 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo } { - var export_names = std.StringHashMapUnmanaged(void){}; + var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{}; defer export_names.deinit(gpa); try export_names.ensureTotalCapacity(gpa, @intCast(u32, module.decl_exports.entries.len)); for (module.decl_exports.values()) |exports| for (exports.items) |@"export"| - try export_names.put(gpa, @"export".options.name, {}); + try export_names.put(gpa, @"export".name, {}); while (f.remaining_decls.popOrNull()) |kv| { const decl_index = kv.key; @@ -553,7 +554,7 @@ fn flushDecl( self: *C, f: *Flush, decl_index: Module.Decl.Index, - export_names: std.StringHashMapUnmanaged(void), + export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void), ) FlushDeclError!void { const gpa = self.base.allocator; const mod = self.base.options.module.?; @@ -571,7 +572,7 @@ fn flushDecl( try self.flushLazyFns(f, decl_block.lazy_fns); try f.all_buffers.ensureUnusedCapacity(gpa, 1); - if (!(decl.isExtern(mod) and export_names.contains(mem.span(decl.name)))) + if (!(decl.isExtern(mod) and export_names.contains(decl.name))) f.appendBufAssumeCapacity(decl_block.fwd_decl.items); } diff --git a/src/link/Coff.zig b/src/link/Coff.zig index 8b76e8dd69a78e5387a8724b7fd0f82f05e2b86b..fec6a86b91339254ec3fc46a5005161fb735b53a 100644 --- a/src/link/Coff.zig +++ b/src/link/Coff.zig @@ -1097,8 +1097,7 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In const atom_index = try self.createAtom(); const sym_name = blk: { - const decl_name = try decl.getFullyQualifiedName(mod); - defer gpa.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const index = unnamed_consts.items.len; break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); @@ -1324,12 +1323,10 @@ fn getDeclOutputSection(self: *Coff, decl_index: Module.Decl.Index) u16 { } fn updateDeclCode(self: *Coff, decl_index: Module.Decl.Index, code: []u8, complex_type: coff.ComplexType) !void { - const gpa = self.base.allocator; const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); - const decl_name = try decl.getFullyQualifiedName(mod); - defer gpa.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); const required_alignment = decl.getAlignment(mod); @@ -1420,6 +1417,8 @@ pub fn updateDeclExports( @panic("Attempted to compile for object format that was disabled by build configuration"); } + const ip = &mod.intern_pool; + if (build_options.have_llvm) { // Even in the case of LLVM, we need to notice certain exported symbols in order to // detect the default subsystem. @@ -1431,20 +1430,20 @@ pub fn updateDeclExports( else => std.builtin.CallingConvention.C, }; const decl_cc = exported_decl.ty.fnCallingConvention(mod); - if (decl_cc == .C and mem.eql(u8, exp.options.name, "main") and + if (decl_cc == .C and ip.stringEqlSlice(exp.name, "main") and self.base.options.link_libc) { mod.stage1_flags.have_c_main = true; } else if (decl_cc == winapi_cc and self.base.options.target.os.tag == .windows) { - if (mem.eql(u8, exp.options.name, "WinMain")) { + if (ip.stringEqlSlice(exp.name, "WinMain")) { mod.stage1_flags.have_winmain = true; - } else if (mem.eql(u8, exp.options.name, "wWinMain")) { + } else if (ip.stringEqlSlice(exp.name, "wWinMain")) { mod.stage1_flags.have_wwinmain = true; - } else if (mem.eql(u8, exp.options.name, "WinMainCRTStartup")) { + } else if (ip.stringEqlSlice(exp.name, "WinMainCRTStartup")) { mod.stage1_flags.have_winmain_crt_startup = true; - } else if (mem.eql(u8, exp.options.name, "wWinMainCRTStartup")) { + } else if (ip.stringEqlSlice(exp.name, "wWinMainCRTStartup")) { mod.stage1_flags.have_wwinmain_crt_startup = true; - } else if (mem.eql(u8, exp.options.name, "DllMainCRTStartup")) { + } else if (ip.stringEqlSlice(exp.name, "DllMainCRTStartup")) { mod.stage1_flags.have_dllmain_crt_startup = true; } } @@ -1453,9 +1452,6 @@ pub fn updateDeclExports( if (self.llvm_object) |llvm_object| return llvm_object.updateDeclExports(mod, decl_index, exports); } - const tracy = trace(@src()); - defer tracy.end(); - const gpa = self.base.allocator; const decl = mod.declPtr(decl_index); @@ -1465,12 +1461,13 @@ pub fn updateDeclExports( const decl_metadata = self.decls.getPtr(decl_index).?; for (exports) |exp| { - log.debug("adding new export '{s}'", .{exp.options.name}); + const exp_name = mod.intern_pool.stringToSlice(exp.name); + log.debug("adding new export '{s}'", .{exp_name}); - if (exp.options.section) |section_name| { + if (mod.intern_pool.stringToSliceUnwrap(exp.section)) |section_name| { if (!mem.eql(u8, section_name, ".text")) { try mod.failed_exports.putNoClobber( - mod.gpa, + gpa, exp, try Module.ErrorMsg.create( gpa, @@ -1483,9 +1480,9 @@ pub fn updateDeclExports( } } - if (exp.options.linkage == .LinkOnce) { + if (exp.linkage == .LinkOnce) { try mod.failed_exports.putNoClobber( - mod.gpa, + gpa, exp, try Module.ErrorMsg.create( gpa, @@ -1497,19 +1494,19 @@ pub fn updateDeclExports( continue; } - const sym_index = decl_metadata.getExport(self, exp.options.name) orelse blk: { + const sym_index = decl_metadata.getExport(self, exp_name) orelse blk: { const sym_index = try self.allocateSymbol(); try decl_metadata.exports.append(gpa, sym_index); break :blk sym_index; }; const sym_loc = SymbolWithLoc{ .sym_index = sym_index, .file = null }; const sym = self.getSymbolPtr(sym_loc); - try self.setSymbolName(sym, exp.options.name); + try self.setSymbolName(sym, exp_name); sym.value = decl_sym.value; sym.section_number = @intToEnum(coff.SectionNumber, self.text_section_index.? + 1); sym.type = .{ .complex_type = .FUNCTION, .base_type = .NULL }; - switch (exp.options.linkage) { + switch (exp.linkage) { .Strong => { sym.storage_class = .EXTERNAL; }, @@ -1522,9 +1519,15 @@ pub fn updateDeclExports( } } -pub fn deleteDeclExport(self: *Coff, decl_index: Module.Decl.Index, name: []const u8) void { +pub fn deleteDeclExport( + self: *Coff, + decl_index: Module.Decl.Index, + name_ip: InternPool.NullTerminatedString, +) void { if (self.llvm_object) |_| return; const metadata = self.decls.getPtr(decl_index) orelse return; + const mod = self.base.options.module.?; + const name = mod.intern_pool.stringToSlice(name_ip); const sym_index = metadata.getExportPtr(self, name) orelse return; const gpa = self.base.allocator; @@ -2540,6 +2543,7 @@ const ImportTable = @import("Coff/ImportTable.zig"); const Liveness = @import("../Liveness.zig"); const LlvmObject = @import("../codegen/llvm.zig").Object; const Module = @import("../Module.zig"); +const InternPool = @import("../InternPool.zig"); const Object = @import("Coff/Object.zig"); const Relocation = @import("Coff/Relocation.zig"); const TableSection = @import("table_section.zig").TableSection; diff --git a/src/link/Dwarf.zig b/src/link/Dwarf.zig index 9d8076f592996c689d32f4b99353ca4d02c1d2d4..b9b7772260bdbf57f3aaaf6003a217f9d805bb52 100644 --- a/src/link/Dwarf.zig +++ b/src/link/Dwarf.zig @@ -358,8 +358,9 @@ pub const DeclState = struct { struct_obj.fields.keys(), struct_obj.fields.values(), 0.., - ) |field_name, field, field_index| { + ) |field_name_ip, field, field_index| { if (!field.ty.hasRuntimeBits(mod)) continue; + const field_name = mod.intern_pool.stringToSlice(field_name_ip); // DW.AT.member try dbg_info_buffer.ensureUnusedCapacity(field_name.len + 2); dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.struct_member)); @@ -469,7 +470,8 @@ pub const DeclState = struct { // DW.AT.member try dbg_info_buffer.append(@enumToInt(AbbrevKind.struct_member)); // DW.AT.name, DW.FORM.string - try dbg_info_buffer.writer().print("{s}\x00", .{field_name}); + try dbg_info_buffer.appendSlice(mod.intern_pool.stringToSlice(field_name)); + try dbg_info_buffer.append(0); // DW.AT.type, DW.FORM.ref4 const index = dbg_info_buffer.items.len; try dbg_info_buffer.resize(index + 4); @@ -949,8 +951,7 @@ pub fn initDeclState(self: *Dwarf, mod: *Module, decl_index: Module.Decl.Index) defer tracy.end(); const decl = mod.declPtr(decl_index); - const decl_name = try decl.getFullyQualifiedName(mod); - defer self.allocator.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); log.debug("initDeclState {s}{*}", .{ decl_name, decl }); @@ -1273,7 +1274,6 @@ pub fn commitDeclState( } } - log.debug("updateDeclDebugInfoAllocation for '{s}'", .{decl.name}); try self.updateDeclDebugInfoAllocation(di_atom_index, @intCast(u32, dbg_info_buffer.items.len)); while (decl_state.abbrev_relocs.popOrNull()) |reloc| { @@ -1345,7 +1345,6 @@ pub fn commitDeclState( } } - log.debug("writeDeclDebugInfo for '{s}", .{decl.name}); try self.writeDeclDebugInfo(di_atom_index, dbg_info_buffer.items); } @@ -2523,15 +2522,7 @@ pub fn flushModule(self: *Dwarf, module: *Module) !void { // TODO: don't create a zig type for this, just make the dwarf info // without touching the zig type system. - const names = try arena.alloc(InternPool.NullTerminatedString, module.global_error_set.count()); - { - var it = module.global_error_set.keyIterator(); - var i: usize = 0; - while (it.next()) |key| : (i += 1) { - names[i] = module.intern_pool.getString(key.*).unwrap().?; - } - } - + const names = try arena.dupe(InternPool.NullTerminatedString, module.global_error_set.keys()); std.mem.sort(InternPool.NullTerminatedString, names, {}, InternPool.NullTerminatedString.indexLessThan); const error_ty = try module.intern(.{ .error_set_type = .{ .names = names } }); @@ -2682,8 +2673,8 @@ fn addDbgInfoErrorSet( const error_names = ty.errorSetNames(mod); for (error_names) |error_name_ip| { + const int = try mod.getErrorValue(error_name_ip); const error_name = mod.intern_pool.stringToSlice(error_name_ip); - const kv = mod.getErrorValue(error_name) catch unreachable; // DW.AT.enumerator try dbg_info_buffer.ensureUnusedCapacity(error_name.len + 2 + @sizeOf(u64)); dbg_info_buffer.appendAssumeCapacity(@enumToInt(AbbrevKind.enum_variant)); @@ -2691,7 +2682,7 @@ fn addDbgInfoErrorSet( dbg_info_buffer.appendSliceAssumeCapacity(error_name); dbg_info_buffer.appendAssumeCapacity(0); // DW.AT.const_value, DW.FORM.data8 - mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), kv.value, target_endian); + mem.writeInt(u64, dbg_info_buffer.addManyAsArrayAssumeCapacity(8), int, target_endian); } // DW.AT.enumeration_type delimit children diff --git a/src/link/Elf.zig b/src/link/Elf.zig index e4fa07620db1b4d5f0567c1640e6a4bac79182ea..5ac90d4cae17c2c9211341968e1462debfa7c32c 100644 --- a/src/link/Elf.zig +++ b/src/link/Elf.zig @@ -28,6 +28,7 @@ const File = link.File; const Liveness = @import("../Liveness.zig"); const LlvmObject = @import("../codegen/llvm.zig").Object; const Module = @import("../Module.zig"); +const InternPool = @import("../InternPool.zig"); const Package = @import("../Package.zig"); const StringTable = @import("strtab.zig").StringTable; const TableSection = @import("table_section.zig").TableSection; @@ -2480,8 +2481,7 @@ fn updateDeclCode(self: *Elf, decl_index: Module.Decl.Index, code: []const u8, s const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); - const decl_name = try decl.getFullyQualifiedName(mod); - defer self.base.allocator.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); log.debug("updateDeclCode {s}{*}", .{ decl_name, decl }); const required_alignment = decl.getAlignment(mod); @@ -2802,8 +2802,7 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module const decl = mod.declPtr(decl_index); const name_str_index = blk: { - const decl_name = try decl.getFullyQualifiedName(mod); - defer gpa.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const index = unnamed_consts.items.len; const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); defer gpa.free(name); @@ -2880,7 +2879,8 @@ pub fn updateDeclExports( try self.global_symbols.ensureUnusedCapacity(gpa, exports.len); for (exports) |exp| { - if (exp.options.section) |section_name| { + const exp_name = mod.intern_pool.stringToSlice(exp.name); + if (mod.intern_pool.stringToSliceUnwrap(exp.section)) |section_name| { if (!mem.eql(u8, section_name, ".text")) { try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1); mod.failed_exports.putAssumeCapacityNoClobber( @@ -2890,11 +2890,11 @@ pub fn updateDeclExports( continue; } } - const stb_bits: u8 = switch (exp.options.linkage) { + const stb_bits: u8 = switch (exp.linkage) { .Internal => elf.STB_LOCAL, .Strong => blk: { const entry_name = self.base.options.entry orelse "_start"; - if (mem.eql(u8, exp.options.name, entry_name)) { + if (mem.eql(u8, exp_name, entry_name)) { self.entry_addr = decl_sym.st_value; } break :blk elf.STB_GLOBAL; @@ -2910,10 +2910,10 @@ pub fn updateDeclExports( }, }; const stt_bits: u8 = @truncate(u4, decl_sym.st_info); - if (decl_metadata.getExport(self, exp.options.name)) |i| { + if (decl_metadata.getExport(self, exp_name)) |i| { const sym = &self.global_symbols.items[i]; sym.* = .{ - .st_name = try self.shstrtab.insert(gpa, exp.options.name), + .st_name = try self.shstrtab.insert(gpa, exp_name), .st_info = (stb_bits << 4) | stt_bits, .st_other = 0, .st_shndx = shdr_index, @@ -2927,7 +2927,7 @@ pub fn updateDeclExports( }; try decl_metadata.exports.append(gpa, @intCast(u32, i)); self.global_symbols.items[i] = .{ - .st_name = try self.shstrtab.insert(gpa, exp.options.name), + .st_name = try self.shstrtab.insert(gpa, exp_name), .st_info = (stb_bits << 4) | stt_bits, .st_other = 0, .st_shndx = shdr_index, @@ -2944,8 +2944,7 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In defer tracy.end(); const decl = mod.declPtr(decl_index); - const decl_name = try decl.getFullyQualifiedName(mod); - defer self.base.allocator.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); @@ -2955,11 +2954,15 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: Module.Decl.In } } -pub fn deleteDeclExport(self: *Elf, decl_index: Module.Decl.Index, name: []const u8) void { +pub fn deleteDeclExport( + self: *Elf, + decl_index: Module.Decl.Index, + name: InternPool.NullTerminatedString, +) void { if (self.llvm_object) |_| return; const metadata = self.decls.getPtr(decl_index) orelse return; - const sym_index = metadata.getExportPtr(self, name) orelse return; - log.debug("deleting export '{s}'", .{name}); + const mod = self.base.options.module.?; + const sym_index = metadata.getExportPtr(self, mod.intern_pool.stringToSlice(name)) orelse return; self.global_symbol_free_list.append(self.base.allocator, sym_index.*) catch {}; self.global_symbols.items[sym_index.*].st_info = 0; sym_index.* = 0; diff --git a/src/link/MachO.zig b/src/link/MachO.zig index f7f975f920f347e2aa9b0b2c665531dd267263d2..70993e8dc6d8ce858b44c62618c064f0645a81a2 100644 --- a/src/link/MachO.zig +++ b/src/link/MachO.zig @@ -40,6 +40,7 @@ const Liveness = @import("../Liveness.zig"); const LlvmObject = @import("../codegen/llvm.zig").Object; const Md5 = std.crypto.hash.Md5; const Module = @import("../Module.zig"); +const InternPool = @import("../InternPool.zig"); const Relocation = @import("MachO/Relocation.zig"); const StringTable = @import("strtab.zig").StringTable; const TableSection = @import("table_section.zig").TableSection; @@ -1921,8 +1922,7 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu const unnamed_consts = gop.value_ptr; const decl = mod.declPtr(decl_index); - const decl_name = try decl.getFullyQualifiedName(mod); - defer gpa.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const name_str_index = blk: { const index = unnamed_consts.items.len; @@ -2206,8 +2206,7 @@ fn updateThreadlocalVariable(self: *MachO, module: *Module, decl_index: Module.D const required_alignment = decl.getAlignment(mod); - const decl_name = try decl.getFullyQualifiedName(module); - defer gpa.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(module)); const init_sym_name = try std.fmt.allocPrint(gpa, "{s}$tlv$init", .{decl_name}); defer gpa.free(init_sym_name); @@ -2306,8 +2305,7 @@ fn updateDeclCode(self: *MachO, decl_index: Module.Decl.Index, code: []u8) !u64 const required_alignment = decl.getAlignment(mod); - const decl_name = try decl.getFullyQualifiedName(mod); - defer gpa.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const decl_metadata = self.decls.get(decl_index).?; const atom_index = decl_metadata.atom; @@ -2403,12 +2401,14 @@ pub fn updateDeclExports( const decl_metadata = self.decls.getPtr(decl_index).?; for (exports) |exp| { - const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{exp.options.name}); + const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{ + mod.intern_pool.stringToSlice(exp.name), + }); defer gpa.free(exp_name); log.debug("adding new export '{s}'", .{exp_name}); - if (exp.options.section) |section_name| { + if (mod.intern_pool.stringToSliceUnwrap(exp.section)) |section_name| { if (!mem.eql(u8, section_name, "__text")) { try mod.failed_exports.putNoClobber( mod.gpa, @@ -2424,7 +2424,7 @@ pub fn updateDeclExports( } } - if (exp.options.linkage == .LinkOnce) { + if (exp.linkage == .LinkOnce) { try mod.failed_exports.putNoClobber( mod.gpa, exp, @@ -2453,7 +2453,7 @@ pub fn updateDeclExports( .n_value = decl_sym.n_value, }; - switch (exp.options.linkage) { + switch (exp.linkage) { .Internal => { // Symbol should be hidden, or in MachO lingo, private extern. // We should also mark the symbol as Weak: n_desc == N_WEAK_DEF. @@ -2488,12 +2488,17 @@ pub fn updateDeclExports( } } -pub fn deleteDeclExport(self: *MachO, decl_index: Module.Decl.Index, name: []const u8) Allocator.Error!void { +pub fn deleteDeclExport( + self: *MachO, + decl_index: Module.Decl.Index, + name: InternPool.NullTerminatedString, +) Allocator.Error!void { if (self.llvm_object) |_| return; const metadata = self.decls.getPtr(decl_index) orelse return; const gpa = self.base.allocator; - const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{name}); + const mod = self.base.options.module.?; + const exp_name = try std.fmt.allocPrint(gpa, "_{s}", .{mod.intern_pool.stringToSlice(name)}); defer gpa.free(exp_name); const sym_index = metadata.getExportPtr(self, exp_name) orelse return; diff --git a/src/link/Plan9.zig b/src/link/Plan9.zig index 0803b6beef2ffa8f34113e3f2ec1a48fef4b0dce..5cf2add528d5c418f7d76296ef5cd73d907f08fd 100644 --- a/src/link/Plan9.zig +++ b/src/link/Plan9.zig @@ -287,7 +287,6 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: Module.Fn.Index, air: self.freeUnnamedConsts(decl_index); _ = try self.seeDecl(decl_index); - log.debug("codegen decl {*} ({s})", .{ decl, decl.name }); var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); @@ -345,8 +344,7 @@ pub fn lowerUnnamedConst(self: *Plan9, tv: TypedValue, decl_index: Module.Decl.I } const unnamed_consts = gop.value_ptr; - const decl_name = try decl.getFullyQualifiedName(mod); - defer self.base.allocator.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); const index = unnamed_consts.items.len; // name is freed when the unnamed const is freed @@ -403,8 +401,6 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: Module.Decl.Index) !vo _ = try self.seeDecl(decl_index); - log.debug("codegen decl {*} ({s}) ({d})", .{ decl, decl.name, decl_index }); - var code_buffer = std.ArrayList(u8).init(self.base.allocator); defer code_buffer.deinit(); const decl_val = if (decl.val.getVariable(mod)) |variable| variable.init.toValue() else decl.val; @@ -435,7 +431,6 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { const mod = self.base.options.module.?; const decl = mod.declPtr(decl_index); const is_fn = (decl.ty.zigTypeTag(mod) == .Fn); - log.debug("update the symbol table and got for decl {*} ({s})", .{ decl, decl.name }); const sym_t: aout.Sym.Type = if (is_fn) .t else .d; const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); @@ -446,7 +441,7 @@ fn updateFinish(self: *Plan9, decl_index: Module.Decl.Index) !void { const sym: aout.Sym = .{ .value = undefined, // the value of stuff gets filled in in flushModule .type = decl_block.type, - .name = mem.span(decl.name), + .name = mod.intern_pool.stringToSlice(decl.name), }; if (decl_block.sym_index) |s| { @@ -567,10 +562,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No var it = fentry.value_ptr.functions.iterator(); while (it.next()) |entry| { const decl_index = entry.key_ptr.*; - const decl = mod.declPtr(decl_index); const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); const out = entry.value_ptr.*; - log.debug("write text decl {*} ({s}), lines {d} to {d}", .{ decl, decl.name, out.start_line + 1, out.end_line }); { // connect the previous decl to the next const delta_line = @intCast(i32, out.start_line) - @intCast(i32, linecount); @@ -616,10 +609,8 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No var it = self.data_decl_table.iterator(); while (it.next()) |entry| { const decl_index = entry.key_ptr.*; - const decl = mod.declPtr(decl_index); const decl_block = self.getDeclBlockPtr(self.decls.get(decl_index).?.index); const code = entry.value_ptr.*; - log.debug("write data decl {*} ({s})", .{ decl, decl.name }); foff += code.len; iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len }; @@ -695,15 +686,12 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No const source_decl = mod.declPtr(source_decl_index); for (kv.value_ptr.items) |reloc| { const target_decl_index = reloc.target; - const target_decl = mod.declPtr(target_decl_index); const target_decl_block = self.getDeclBlock(self.decls.get(target_decl_index).?.index); const target_decl_offset = target_decl_block.offset.?; const offset = reloc.offset; const addend = reloc.addend; - log.debug("relocating the address of '{s}' + {d} into '{s}' + {d}", .{ target_decl.name, addend, source_decl.name, offset }); - const code = blk: { const is_fn = source_decl.ty.zigTypeTag(mod) == .Fn; if (is_fn) { @@ -737,8 +725,9 @@ fn addDeclExports( const decl_block = self.getDeclBlock(metadata.index); for (exports) |exp| { + const exp_name = mod.intern_pool.stringToSlice(exp.name); // plan9 does not support custom sections - if (exp.options.section) |section_name| { + if (mod.intern_pool.stringToSliceUnwrap(exp.section)) |section_name| { if (!mem.eql(u8, section_name, ".text") or !mem.eql(u8, section_name, ".data")) { try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( self.base.allocator, @@ -752,10 +741,10 @@ fn addDeclExports( const sym = .{ .value = decl_block.offset.?, .type = decl_block.type.toGlobal(), - .name = exp.options.name, + .name = exp_name, }; - if (metadata.getExport(self, exp.options.name)) |i| { + if (metadata.getExport(self, exp_name)) |i| { self.syms.items[i] = sym; } else { try self.syms.append(self.base.allocator, sym); @@ -956,7 +945,10 @@ pub fn writeSym(self: *Plan9, w: anytype, sym: aout.Sym) !void { try w.writeAll(sym.name); try w.writeByte(0); } + pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { + const mod = self.base.options.module.?; + const ip = &mod.intern_pool; const writer = buf.writer(); // write the f symbols { @@ -980,7 +972,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const sym = self.syms.items[decl_block.sym_index.?]; try self.writeSym(writer, sym); if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { - for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { + for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.name))) |exp_i| { try self.writeSym(writer, self.syms.items[exp_i]); }; } @@ -1006,7 +998,7 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void { const sym = self.syms.items[decl_block.sym_index.?]; try self.writeSym(writer, sym); if (self.base.options.module.?.decl_exports.get(decl_index)) |exports| { - for (exports.items) |e| if (decl_metadata.getExport(self, e.options.name)) |exp_i| { + for (exports.items) |e| if (decl_metadata.getExport(self, ip.stringToSlice(e.name))) |exp_i| { const s = self.syms.items[exp_i]; if (mem.eql(u8, s.name, "_start")) self.entry_val = s.value; diff --git a/src/link/SpirV.zig b/src/link/SpirV.zig index 89d6be1ec8da012aa1a79fe899e044ec4065a9a4..fbde464c54571a8ef396e06d0959dfd9a0d27117 100644 --- a/src/link/SpirV.zig +++ b/src/link/SpirV.zig @@ -147,7 +147,7 @@ pub fn updateDeclExports( const spv_decl_index = entry.value_ptr.*; for (exports) |exp| { - try self.spv.declareEntryPoint(spv_decl_index, exp.options.name); + try self.spv.declareEntryPoint(spv_decl_index, mod.intern_pool.stringToSlice(exp.name)); } } @@ -190,7 +190,8 @@ pub fn flushModule(self: *SpirV, comp: *Compilation, prog_node: *std.Progress.No var error_info = std.ArrayList(u8).init(self.spv.arena); try error_info.appendSlice("zig_errors"); const module = self.base.options.module.?; - for (module.error_name_list.items) |name| { + for (module.global_error_set.keys()) |name_nts| { + const name = module.intern_pool.stringToSlice(name_nts); // Errors can contain pretty much any character - to encode them in a string we must escape // them somehow. Easiest here is to use some established scheme, one which also preseves the // name if it contains no strange characters is nice for debugging. URI encoding fits the bill. diff --git a/src/link/Wasm.zig b/src/link/Wasm.zig index 96de121ffb4f3c7359f05453292dd849fd69c970..d57543542a7cfbe3967a123409d289e7c6353f51 100644 --- a/src/link/Wasm.zig +++ b/src/link/Wasm.zig @@ -1416,7 +1416,7 @@ pub fn updateDecl(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.Index) !voi if (decl.isExtern(mod)) { const variable = decl.getOwnedVariable(mod).?; - const name = mem.sliceTo(decl.name, 0); + const name = mod.intern_pool.stringToSlice(decl.name); const lib_name = mod.intern_pool.stringToSliceUnwrap(variable.lib_name); return wasm.addOrUpdateImport(name, atom.sym_index, lib_name, null); } @@ -1453,8 +1453,7 @@ pub fn updateDeclLineNumber(wasm: *Wasm, mod: *Module, decl_index: Module.Decl.I defer tracy.end(); const decl = mod.declPtr(decl_index); - const decl_name = try decl.getFullyQualifiedName(mod); - defer wasm.base.allocator.free(decl_name); + const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); log.debug("updateDeclLineNumber {s}{*}", .{ decl_name, decl }); try dw.updateDeclLineNumber(mod, decl_index); @@ -1467,8 +1466,7 @@ fn finishUpdateDecl(wasm: *Wasm, decl_index: Module.Decl.Index, code: []const u8 const atom_index = wasm.decls.get(decl_index).?; const atom = wasm.getAtomPtr(atom_index); const symbol = &wasm.symbols.items[atom.sym_index]; - const full_name = try decl.getFullyQualifiedName(mod); - defer wasm.base.allocator.free(full_name); + const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); symbol.name = try wasm.string_table.put(wasm.base.allocator, full_name); try atom.code.appendSlice(wasm.base.allocator, code); try wasm.resolved_symbols.put(wasm.base.allocator, atom.symbolLoc(), {}); @@ -1535,9 +1533,10 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In const parent_atom = wasm.getAtomPtr(parent_atom_index); const local_index = parent_atom.locals.items.len; try parent_atom.locals.append(wasm.base.allocator, atom_index); - const fqdn = try decl.getFullyQualifiedName(mod); - defer wasm.base.allocator.free(fqdn); - const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ fqdn, local_index }); + const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); + const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ + fqn, local_index, + }); defer wasm.base.allocator.free(name); var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); defer value_bytes.deinit(); @@ -1690,11 +1689,12 @@ pub fn updateDeclExports( const decl = mod.declPtr(decl_index); const atom_index = try wasm.getOrCreateAtomForDecl(decl_index); const atom = wasm.getAtom(atom_index); + const gpa = mod.gpa; for (exports) |exp| { - if (exp.options.section) |section| { - try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( - mod.gpa, + if (mod.intern_pool.stringToSliceUnwrap(exp.section)) |section| { + try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( + gpa, decl.srcLoc(mod), "Unimplemented: ExportOptions.section '{s}'", .{section}, @@ -1702,24 +1702,24 @@ pub fn updateDeclExports( continue; } - const export_name = try wasm.string_table.put(wasm.base.allocator, exp.options.name); + const export_name = try wasm.string_table.put(wasm.base.allocator, mod.intern_pool.stringToSlice(exp.name)); if (wasm.globals.getPtr(export_name)) |existing_loc| { if (existing_loc.index == atom.sym_index) continue; const existing_sym: Symbol = existing_loc.getSymbol(wasm).*; - const exp_is_weak = exp.options.linkage == .Internal or exp.options.linkage == .Weak; + const exp_is_weak = exp.linkage == .Internal or exp.linkage == .Weak; // When both the to-be-exported symbol and the already existing symbol // are strong symbols, we have a linker error. // In the other case we replace one with the other. if (!exp_is_weak and !existing_sym.isWeak()) { - try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create( - mod.gpa, + try mod.failed_exports.put(gpa, exp, try Module.ErrorMsg.create( + gpa, decl.srcLoc(mod), \\LinkError: symbol '{s}' defined multiple times \\ first definition in '{s}' \\ next definition in '{s}' , - .{ exp.options.name, wasm.name, wasm.name }, + .{ mod.intern_pool.stringToSlice(exp.name), wasm.name, wasm.name }, )); continue; } else if (exp_is_weak) { @@ -1736,7 +1736,7 @@ pub fn updateDeclExports( const exported_atom = wasm.getAtom(exported_atom_index); const sym_loc = exported_atom.symbolLoc(); const symbol = sym_loc.getSymbol(wasm); - switch (exp.options.linkage) { + switch (exp.linkage) { .Internal => { symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); }, @@ -1745,8 +1745,8 @@ pub fn updateDeclExports( }, .Strong => {}, // symbols are strong by default .LinkOnce => { - try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create( - mod.gpa, + try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create( + gpa, decl.srcLoc(mod), "Unimplemented: LinkOnce", .{}, @@ -1755,7 +1755,7 @@ pub fn updateDeclExports( }, } // Ensure the symbol will be exported using the given name - if (!mem.eql(u8, exp.options.name, sym_loc.getName(wasm))) { + if (!mod.intern_pool.stringEqlSlice(exp.name, sym_loc.getName(wasm))) { try wasm.export_names.put(wasm.base.allocator, sym_loc, export_name); } @@ -1769,7 +1769,7 @@ pub fn updateDeclExports( // if the symbol was previously undefined, remove it as an import _ = wasm.imports.remove(sym_loc); - _ = wasm.undefs.swapRemove(exp.options.name); + _ = wasm.undefs.swapRemove(mod.intern_pool.stringToSlice(exp.name)); } } @@ -2987,7 +2987,8 @@ fn populateErrorNameTable(wasm: *Wasm) !void { // Addend for each relocation to the table var addend: u32 = 0; const mod = wasm.base.options.module.?; - for (mod.error_name_list.items) |error_name| { + for (mod.global_error_set.keys()) |error_name_nts| { + const error_name = mod.intern_pool.stringToSlice(error_name_nts); const len = @intCast(u32, error_name.len + 1); // names are 0-termianted const slice_ty = Type.slice_const_u8_sentinel_0; diff --git a/src/print_air.zig b/src/print_air.zig index 8da80e1360cca46a2c3dcc0c2311a50b54dc3e41..eb104772920ae28dc5f5b0b9700ad56aae76162b 100644 --- a/src/print_air.zig +++ b/src/print_air.zig @@ -685,8 +685,9 @@ const Writer = struct { fn writeDbgInline(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { const ty_fn = w.air.instructions.items(.data)[inst].ty_fn; const func_index = ty_fn.func; + const ip = &w.module.intern_pool; const owner_decl = w.module.declPtr(w.module.funcPtr(func_index).owner_decl); - try s.print("{s}", .{owner_decl.name}); + try s.print("{s}", .{ip.stringToSlice(owner_decl.name)}); } fn writeDbgVar(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void { diff --git a/src/type.zig b/src/type.zig index 61c9377b1dadb2c888e9d6deb59b94a57f9bdab9..43aaf3c786928cd734e705481eb701b86279b019 100644 --- a/src/type.zig +++ b/src/type.zig @@ -2546,7 +2546,7 @@ pub const Type = struct { defer mod.gpa.free(field_vals); for (field_vals, s.fields.values()) |*field_val, field| { if (field.is_comptime) { - field_val.* = try field.default_val.intern(field.ty, mod); + field_val.* = field.default_val; continue; } if (try field.ty.onePossibleValue(mod)) |field_opv| { @@ -2977,18 +2977,14 @@ pub const Type = struct { return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names.len; } - pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) [:0]const u8 { - const ip = &mod.intern_pool; - const field_name = ip.indexToKey(ty.toIntern()).enum_type.names[field_index]; - return ip.stringToSlice(field_name); + pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { + return mod.intern_pool.indexToKey(ty.toIntern()).enum_type.names[field_index]; } - pub fn enumFieldIndex(ty: Type, field_name: []const u8, mod: *Module) ?u32 { + pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 { const ip = &mod.intern_pool; const enum_type = ip.indexToKey(ty.toIntern()).enum_type; - // If the string is not interned, then the field certainly is not present. - const field_name_interned = ip.getString(field_name).unwrap() orelse return null; - return enum_type.nameIndex(ip, field_name_interned); + return enum_type.nameIndex(ip, field_name); } /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or @@ -3017,19 +3013,16 @@ pub const Type = struct { } } - pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) []const u8 { - switch (mod.intern_pool.indexToKey(ty.toIntern())) { + pub fn structFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString { + return switch (mod.intern_pool.indexToKey(ty.toIntern())) { .struct_type => |struct_type| { const struct_obj = mod.structPtrUnwrap(struct_type.index).?; assert(struct_obj.haveFieldTypes()); return struct_obj.fields.keys()[field_index]; }, - .anon_struct_type => |anon_struct| { - const name = anon_struct.names[field_index]; - return mod.intern_pool.stringToSlice(name); - }, + .anon_struct_type => |anon_struct| anon_struct.names[field_index], else => unreachable, - } + }; } pub fn structFieldCount(ty: Type, mod: *Module) usize { @@ -3082,7 +3075,10 @@ pub const Type = struct { switch (mod.intern_pool.indexToKey(ty.toIntern())) { .struct_type => |struct_type| { const struct_obj = mod.structPtrUnwrap(struct_type.index).?; - return struct_obj.fields.values()[index].default_val; + const val = struct_obj.fields.values()[index].default_val; + // TODO: avoid using `unreachable` to indicate this. + if (val == .none) return Value.@"unreachable"; + return val.toValue(); }, .anon_struct_type => |anon_struct| { const val = anon_struct.values[index]; @@ -3100,7 +3096,7 @@ pub const Type = struct { const struct_obj = mod.structPtrUnwrap(struct_type.index).?; const field = struct_obj.fields.values()[index]; if (field.is_comptime) { - return field.default_val; + return field.default_val.toValue(); } else { return field.ty.onePossibleValue(mod); } diff --git a/src/value.zig b/src/value.zig index 6a19678d7152a129d56be9adfac301a250d04bdb..2c38852bf575d6e2cf695a430c68afd0fb62765e 100644 --- a/src/value.zig +++ b/src/value.zig @@ -24,9 +24,6 @@ pub const Value = struct { /// This union takes advantage of the fact that the first page of memory /// is unmapped, giving us 4096 possible enum tags that have no payload. legacy: extern union { - /// If the tag value is less than Tag.no_payload_count, then no pointer - /// dereference is needed. - tag_if_small_enough: Tag, ptr_otherwise: *Payload, }, @@ -64,8 +61,6 @@ pub const Value = struct { /// An instance of a union. @"union", - pub const no_payload_count = 0; - pub fn Type(comptime t: Tag) type { return switch (t) { .eu_payload, @@ -96,16 +91,7 @@ pub const Value = struct { } }; - pub fn initTag(small_tag: Tag) Value { - assert(@enumToInt(small_tag) < Tag.no_payload_count); - return Value{ - .ip_index = .none, - .legacy = .{ .tag_if_small_enough = small_tag }, - }; - } - pub fn initPayload(payload: *Payload) Value { - assert(@enumToInt(payload.tag) >= Tag.no_payload_count); return Value{ .ip_index = .none, .legacy = .{ .ptr_otherwise = payload }, @@ -114,11 +100,7 @@ pub const Value = struct { pub fn tag(self: Value) Tag { assert(self.ip_index == .none); - if (@enumToInt(self.legacy.tag_if_small_enough) < Tag.no_payload_count) { - return self.legacy.tag_if_small_enough; - } else { - return self.legacy.ptr_otherwise.tag; - } + return self.legacy.ptr_otherwise.tag; } /// Prefer `castTag` to this. @@ -129,12 +111,7 @@ pub const Value = struct { if (@hasField(T, "base_tag")) { return self.castTag(T.base_tag); } - if (@enumToInt(self.legacy.tag_if_small_enough) < Tag.no_payload_count) { - return null; - } inline for (@typeInfo(Tag).Enum.fields) |field| { - if (field.value < Tag.no_payload_count) - continue; const t = @intToEnum(Tag, field.value); if (self.legacy.ptr_otherwise.tag == t) { if (T == t.Type()) { @@ -149,9 +126,6 @@ pub const Value = struct { pub fn castTag(self: Value, comptime t: Tag) ?*t.Type() { if (self.ip_index != .none) return null; - if (@enumToInt(self.legacy.tag_if_small_enough) < Tag.no_payload_count) - return null; - if (self.legacy.ptr_otherwise.tag == t) return @fieldParentPtr(t.Type(), "base", self.legacy.ptr_otherwise); @@ -164,12 +138,7 @@ pub const Value = struct { if (self.ip_index != .none) { return Value{ .ip_index = self.ip_index, .legacy = undefined }; } - if (@enumToInt(self.legacy.tag_if_small_enough) < Tag.no_payload_count) { - return Value{ - .ip_index = .none, - .legacy = .{ .tag_if_small_enough = self.legacy.tag_if_small_enough }, - }; - } else switch (self.legacy.ptr_otherwise.tag) { + switch (self.legacy.ptr_otherwise.tag) { .bytes => { const bytes = self.castTag(.bytes).?.data; const new_payload = try arena.create(Payload.Bytes); @@ -312,6 +281,30 @@ pub const Value = struct { } }; } + /// Asserts that the value is representable as an array of bytes. + /// Returns the value as a null-terminated string stored in the InternPool. + pub fn toIpString(val: Value, ty: Type, mod: *Module) !InternPool.NullTerminatedString { + const ip = &mod.intern_pool; + return switch (mod.intern_pool.indexToKey(val.toIntern())) { + .enum_literal => |enum_literal| enum_literal, + .ptr => |ptr| switch (ptr.len) { + .none => unreachable, + else => try arrayToIpString(val, ptr.len.toValue().toUnsignedInt(mod), mod), + }, + .aggregate => |aggregate| switch (aggregate.storage) { + .bytes => |bytes| try ip.getOrPutString(mod.gpa, bytes), + .elems => try arrayToIpString(val, ty.arrayLen(mod), mod), + .repeated_elem => |elem| { + const byte = @intCast(u8, elem.toValue().toUnsignedInt(mod)); + const len = @intCast(usize, ty.arrayLen(mod)); + try ip.string_bytes.appendNTimes(mod.gpa, byte, len); + return ip.getOrPutTrailingString(mod.gpa, len); + }, + }, + else => unreachable, + }; + } + /// Asserts that the value is representable as an array of bytes. /// Copies the value into a freshly allocated slice of memory, which is owned by the caller. pub fn toAllocatedBytes(val: Value, ty: Type, allocator: Allocator, mod: *Module) ![]u8 { @@ -319,11 +312,11 @@ pub const Value = struct { .enum_literal => |enum_literal| allocator.dupe(u8, mod.intern_pool.stringToSlice(enum_literal)), .ptr => |ptr| switch (ptr.len) { .none => unreachable, - else => arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), + else => try arrayToAllocatedBytes(val, ptr.len.toValue().toUnsignedInt(mod), allocator, mod), }, .aggregate => |aggregate| switch (aggregate.storage) { .bytes => |bytes| try allocator.dupe(u8, bytes), - .elems => arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), + .elems => try arrayToAllocatedBytes(val, ty.arrayLen(mod), allocator, mod), .repeated_elem => |elem| { const byte = @intCast(u8, elem.toValue().toUnsignedInt(mod)); const result = try allocator.alloc(u8, @intCast(usize, ty.arrayLen(mod))); @@ -344,6 +337,23 @@ pub const Value = struct { return result; } + fn arrayToIpString(val: Value, len_u64: u64, mod: *Module) !InternPool.NullTerminatedString { + const gpa = mod.gpa; + const ip = &mod.intern_pool; + const len = @intCast(usize, len_u64); + try ip.string_bytes.ensureUnusedCapacity(gpa, len); + for (0..len) |i| { + // I don't think elemValue has the possibility to affect ip.string_bytes. Let's + // assert just to be sure. + const prev = ip.string_bytes.items.len; + const elem_val = try val.elemValue(mod, i); + assert(ip.string_bytes.items.len == prev); + const byte = @intCast(u8, elem_val.toUnsignedInt(mod)); + ip.string_bytes.appendAssumeCapacity(byte); + } + return ip.getOrPutTrailingString(gpa, len); + } + pub fn intern(val: Value, ty: Type, mod: *Module) Allocator.Error!InternPool.Index { if (val.ip_index != .none) return (try mod.getCoerced(val, ty)).toIntern(); switch (val.tag()) { @@ -498,7 +508,7 @@ pub const Value = struct { // Assume it is already an integer and return it directly. .simple_type, .int_type => val, .enum_literal => |enum_literal| { - const field_index = ty.enumFieldIndex(ip.stringToSlice(enum_literal), mod).?; + const field_index = ty.enumFieldIndex(enum_literal, mod).?; return switch (ip.indexToKey(ty.toIntern())) { // Assume it is already an integer and return it directly. .simple_type, .int_type => val, @@ -776,7 +786,7 @@ pub const Value = struct { .error_union => |error_union| error_union.val.err_name, else => unreachable, }; - const int = mod.global_error_set.get(mod.intern_pool.stringToSlice(name)).?; + const int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(name).?); std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), endian); }, .Union => switch (ty.containerLayout(mod)) { @@ -1028,10 +1038,10 @@ pub const Value = struct { // TODO revisit this when we have the concept of the error tag type const Int = u16; const int = std.mem.readInt(Int, buffer[0..@sizeOf(Int)], endian); - const name = mod.error_name_list.items[@intCast(usize, int)]; + const name = mod.global_error_set.keys()[@intCast(usize, int)]; return (try mod.intern(.{ .err = .{ .ty = ty.toIntern(), - .name = mod.intern_pool.getString(name).unwrap().?, + .name = name, } })).toValue(); }, .Pointer => { @@ -2155,15 +2165,29 @@ pub const Value = struct { /// unreachable. For error unions, prefer `errorUnionIsPayload` to find out whether /// something is an error or not because it works without having to figure out the /// string. - pub fn getError(self: Value, mod: *const Module) ?[]const u8 { - return mod.intern_pool.stringToSliceUnwrap(switch (mod.intern_pool.indexToKey(self.toIntern())) { - .err => |err| err.name.toOptional(), + pub fn getError(val: Value, mod: *const Module) ?[]const u8 { + return switch (getErrorName(val, mod)) { + .empty => null, + else => |s| mod.intern_pool.stringToSlice(s), + }; + } + + pub fn getErrorName(val: Value, mod: *const Module) InternPool.NullTerminatedString { + return switch (mod.intern_pool.indexToKey(val.toIntern())) { + .err => |err| err.name, .error_union => |error_union| switch (error_union.val) { - .err_name => |err_name| err_name.toOptional(), - .payload => .none, + .err_name => |err_name| err_name, + .payload => .empty, }, else => unreachable, - }); + }; + } + + pub fn getErrorInt(val: Value, mod: *const Module) Module.ErrorInt { + return switch (getErrorName(val, mod)) { + .empty => 0, + else => |s| @intCast(Module.ErrorInt, mod.global_error_set.getIndex(s).?), + }; } /// Assumes the type is an error union. Returns true if and only if the value is @@ -4225,7 +4249,7 @@ pub const Value = struct { var fields: [tags.len]std.builtin.Type.StructField = undefined; for (&fields, tags) |*field, t| field.* = .{ .name = t.name, - .type = *if (t.value < Tag.no_payload_count) void else @field(Tag, t.name).Type(), + .type = *@field(Tag, t.name).Type(), .default_value = null, .is_comptime = false, .alignment = 0,