authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-01-22 07:12:26+01:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2024-02-29 15:23:04+01:00
loga028b10b9f8213f5f31c06b57cd18f9852f0df13
tree42552ffd48fab110bae379ddcf98160501b935eb
parent4d14374a668f6caca7490a136030dbc73507f233
signaturelock-open Commit is signed but in an unrecognized format.

wasm: update `freeDecl` and `finishDecl`

We now parse the decls right away into atoms and allocate the corresponding linker-object, such as segment and function, rather than waiting until `flushModule`.

3 files changed, 98 insertions(+), 15 deletions(-)

src/link/Wasm.zig-1
...@@ -585,7 +585,6 @@ pub fn file(wasm: *const Wasm, index: File.Index) ?File {...@@ -585,7 +585,6 @@ pub fn file(wasm: *const Wasm, index: File.Index) ?File {
585 if (index == .null) return null;585 if (index == .null) return null;
586 const tag = wasm.files.items(.tags)[@intFromEnum(index)];586 const tag = wasm.files.items(.tags)[@intFromEnum(index)];
587 return switch (tag) {587 return switch (tag) {
588 .null => null,
589 .zig_object => .{ .zig_object = &wasm.files.items(.data)[@intFromEnum(index)].zig_object },588 .zig_object => .{ .zig_object = &wasm.files.items(.data)[@intFromEnum(index)].zig_object },
590 .object => .{ .object = &wasm.files.items(.data)[@intFromEnum(index)].object },589 .object => .{ .object = &wasm.files.items(.data)[@intFromEnum(index)].object },
591 };590 };
src/link/Wasm/ZigObject.zig+98-13
...@@ -29,6 +29,8 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{},...@@ -29,6 +29,8 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{},
29symbols_free_list: std.ArrayListUnmanaged(u32) = .{},29symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
30/// Extra metadata about the linking section, such as alignment of segments and their name.30/// Extra metadata about the linking section, such as alignment of segments and their name.
31segment_info: std.ArrayListUnmanaged(types.Segment) = .{},31segment_info: std.ArrayListUnmanaged(types.Segment) = .{},
32/// List of indexes which contain a free slot in the `segment_info` list.
33segment_free_list: std.ArrayListUnmanaged(u32) = .{},
32/// File encapsulated string table, used to deduplicate strings within the generated file.34/// File encapsulated string table, used to deduplicate strings within the generated file.
33string_table: StringTable = .{},35string_table: StringTable = .{},
34/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.36/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
...@@ -145,6 +147,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {...@@ -145,6 +147,7 @@ pub fn deinit(zig_object: *ZigObject, wasm_file: *Wasm) void {
145 zig_object.symbols.deinit(gpa);147 zig_object.symbols.deinit(gpa);
146 zig_object.symbols_free_list.deinit(gpa);148 zig_object.symbols_free_list.deinit(gpa);
147 zig_object.segment_info.deinit(gpa);149 zig_object.segment_info.deinit(gpa);
150 zig_object.segment_free_list.deinit(gpa);
148151
149 zig_object.string_table.deinit(gpa);152 zig_object.string_table.deinit(gpa);
150 if (zig_object.dwarf) |*dwarf| {153 if (zig_object.dwarf) |*dwarf| {
...@@ -223,7 +226,7 @@ pub fn updateDecl(...@@ -223,7 +226,7 @@ pub fn updateDecl(
223 },226 },
224 };227 };
225228
226 return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .data);229 return zig_object.finishUpdateDecl(wasm_file, decl_index, code);
227}230}
228231
229pub fn updateFunc(232pub fn updateFunc(
...@@ -263,7 +266,7 @@ pub fn updateFunc(...@@ -263,7 +266,7 @@ pub fn updateFunc(
263 },266 },
264 };267 };
265268
266 return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .function);269 return zig_object.finishUpdateDecl(wasm_file, decl_index, code);
267}270}
268271
269fn finishUpdateDecl(272fn finishUpdateDecl(
...@@ -271,25 +274,89 @@ fn finishUpdateDecl(...@@ -271,25 +274,89 @@ fn finishUpdateDecl(
271 wasm_file: *Wasm,274 wasm_file: *Wasm,
272 decl_index: InternPool.DeclIndex,275 decl_index: InternPool.DeclIndex,
273 code: []const u8,276 code: []const u8,
274 symbol_tag: Symbol.Tag,
275) !void {277) !void {
276 const gpa = wasm_file.base.comp.gpa;278 const gpa = wasm_file.base.comp.gpa;
277 const mod = wasm_file.base.comp.module.?;279 const mod = wasm_file.base.comp.module.?;
278 const decl = mod.declPtr(decl_index);280 const decl = mod.declPtr(decl_index);
279 const atom_index = zig_object.decls.get(decl_index).?;281 const atom_index = zig_object.decls.get(decl_index).?;
280 const atom = wasm_file.getAtomPtr(atom_index);282 const atom = wasm_file.getAtomPtr(atom_index);
281 const sym = zig_object.symbol(atom.getSymbolIndex().?);283 const sym = zig_object.symbol(atom.sym_index);
282 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));284 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
283 sym.name = try zig_object.string_table.insert(gpa, full_name);285 sym.name = try zig_object.string_table.insert(gpa, full_name);
284 sym.tag = symbol_tag;
285 try atom.code.appendSlice(gpa, code);286 try atom.code.appendSlice(gpa, code);
286 try wasm_file.resolved_symbols.put(gpa, atom.symbolLoc(), {});
287
288 atom.size = @intCast(code.len);287 atom.size = @intCast(code.len);
288
289 switch (decl.ty.zigTypeTag(mod)) {
290 .Fn => {
291 try zig_object.functions.put(
292 gpa,
293 atom.sym_index,
294 .{ .type_index = zig_object.atom_types.get(atom_index).? },
295 );
296 sym.tag = .function;
297 },
298 else => {
299 const segment_name: []const u8 = if (decl.getOwnedVariable(mod)) |variable| name: {
300 if (variable.is_const) {
301 break :name ".rodata.";
302 } else if (Value.fromInterned(variable.init).isUndefDeep(mod)) {
303 const decl_namespace = mod.namespacePtr(decl.src_namespace);
304 const optimize_mode = decl_namespace.file_scope.mod.optimize_mode;
305 const is_initialized = switch (optimize_mode) {
306 .Debug, .ReleaseSafe => true,
307 .ReleaseFast, .ReleaseSmall => false,
308 };
309 if (is_initialized) {
310 break :name ".data.";
311 }
312 break :name ".bss.";
313 }
314 // when the decl is all zeroes, we store the atom in the bss segment,
315 // in all other cases it will be in the data segment.
316 for (atom.code.items) |byte| {
317 if (byte != 0) break :name ".data.";
318 }
319 break :name ".bss.";
320 } else ".rodata.";
321 if ((wasm_file.base.isObject() or wasm_file.base.comp.config.import_memory) and
322 std.mem.startsWith(u8, segment_name, ".bss"))
323 {
324 @memset(atom.code.items, 0);
325 }
326 // Will be freed upon freeing of decl or after cleanup of Wasm binary.
327 const full_segment_name = try std.mem.concat(gpa, u8, &.{
328 segment_name,
329 full_name,
330 });
331 errdefer gpa.free(full_segment_name);
332 sym.tag = .data;
333 sym.index = try zig_object.createDataSegment(gpa, full_segment_name, decl.alignment);
334 },
335 }
289 if (code.len == 0) return;336 if (code.len == 0) return;
290 atom.alignment = decl.getAlignment(mod);337 atom.alignment = decl.getAlignment(mod);
291}338}
292339
340fn createDataSegment(
341 zig_object: *ZigObject,
342 gpa: std.mem.Allocator,
343 name: []const u8,
344 alignment: InternPool.Alignment,
345) !u32 {
346 const segment_index: u32 = if (zig_object.segment_free_list.popOrNull()) |index|
347 index
348 else index: {
349 const idx: u32 = @intCast(zig_object.segment_info.items.len);
350 _ = try zig_object.segment_info.addOne(gpa);
351 break :index idx;
352 };
353 zig_object.segment_info.items[segment_index] = .{
354 .alignment = alignment,
355 .flags = 0,
356 .name = name,
357 };
358}
359
293/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.360/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
294/// When the index was not found, a new `Atom` will be created, and its index will be returned.361/// When the index was not found, a new `Atom` will be created, and its index will be returned.
295/// The newly created Atom is empty with default fields as specified by `Atom.empty`.362/// The newly created Atom is empty with default fields as specified by `Atom.empty`.
...@@ -840,20 +907,24 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool...@@ -840,20 +907,24 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool
840 const atom_index = zig_object.decls.get(decl_index).?;907 const atom_index = zig_object.decls.get(decl_index).?;
841 const atom = wasm_file.getAtomPtr(atom_index);908 const atom = wasm_file.getAtomPtr(atom_index);
842 zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};909 zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};
843 _ = zig_object.decls.remove(decl_index);910 std.debug.assert(zig_object.decls.remove(decl_index));
844 zig_object.symbols.items[atom.sym_index].tag = .dead;911 const sym = &zig_object.symbols.items[atom.sym_index];
845 for (atom.locals.items) |local_atom_index| {912 for (atom.locals.items) |local_atom_index| {
846 const local_atom = wasm_file.getAtom(local_atom_index);913 const local_atom = wasm_file.getAtom(local_atom_index);
847 const local_symbol = &zig_object.symbols.items[local_atom.sym_index];914 const local_symbol = &zig_object.symbols.items[local_atom.sym_index];
848 local_symbol.tag = .dead; // also for any local symbol915 std.debug.assert(local_symbol.tag == .data);
849 zig_object.symbols_free_list.append(gpa, local_atom.sym_index) catch {};916 zig_object.symbols_free_list.append(gpa, local_atom.sym_index) catch {};
850 std.denug.assert(wasm_file.symbol_atom.remove(local_atom.symbolLoc()));917 std.debug.assert(wasm_file.symbol_atom.remove(local_atom.symbolLoc()));
918 local_symbol.tag = .dead; // also for any local symbol
919 const segment = &zig_object.segment_info.items[local_atom.sym_index];
920 gpa.free(segment.name);
921 segment.name = &.{}; // Ensure no accidental double free
851 }922 }
852923
853 if (decl.isExtern(mod)) {924 if (decl.isExtern(mod)) {
854 _ = zig_object.imports.remove(atom.getSymbolIndex().?);925 std.debug.assert(zig_object.imports.remove(atom.sym_index));
855 }926 }
856 _ = wasm_file.symbol_atom.remove(atom.symbolLoc());927 std.debug.assert(wasm_file.symbol_atom.remove(atom.symbolLoc()));
857928
858 // if (wasm.dwarf) |*dwarf| {929 // if (wasm.dwarf) |*dwarf| {
859 // dwarf.freeDecl(decl_index);930 // dwarf.freeDecl(decl_index);
...@@ -869,6 +940,20 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool...@@ -869,6 +940,20 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool
869 prev_atom.next = atom.next;940 prev_atom.next = atom.next;
870 atom.prev = null;941 atom.prev = null;
871 }942 }
943
944 sym.tag = .dead;
945 switch (decl.ty.zigTypeTag(mod)) {
946 .Fn => {
947 std.debug.assert(zig_object.functions.remove(atom.sym_index));
948 std.debug.assert(zig_object.atom_types.remove(atom_index));
949 },
950 else => {
951 zig_object.segment_free_list.append(gpa, sym.index) catch {};
952 const segment = &zig_object.segment_info.items[sym.index];
953 gpa.free(segment.name);
954 segment.name = &.{}; // Prevent accidental double free
955 },
956 }
872}957}
873958
874fn getTypeIndex(zig_object: *const ZigObject, func_type: std.wasm.Type) ?u32 {959fn getTypeIndex(zig_object: *const ZigObject, func_type: std.wasm.Type) ?u32 {
src/link/Wasm/file.zig-1
...@@ -114,7 +114,6 @@ pub const File = union(enum) {...@@ -114,7 +114,6 @@ pub const File = union(enum) {
114 }114 }
115115
116 pub const Entry = union(enum) {116 pub const Entry = union(enum) {
117 null: void,
118 zig_object: ZigObject,117 zig_object: ZigObject,
119 object: Object,118 object: Object,
120 };119 };