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 {
585585 if (index == .null) return null;
586586 const tag = wasm.files.items(.tags)[@intFromEnum(index)];
587587 return switch (tag) {
588 .null => null,
589588 .zig_object => .{ .zig_object = &wasm.files.items(.data)[@intFromEnum(index)].zig_object },
590589 .object => .{ .object = &wasm.files.items(.data)[@intFromEnum(index)].object },
591590 };
src/link/Wasm/ZigObject.zig+98-13
......@@ -29,6 +29,8 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{},
2929symbols_free_list: std.ArrayListUnmanaged(u32) = .{},
3030/// Extra metadata about the linking section, such as alignment of segments and their name.
3131segment_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) = .{},
3234/// File encapsulated string table, used to deduplicate strings within the generated file.
3335string_table: StringTable = .{},
3436/// 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 {
145147 zig_object.symbols.deinit(gpa);
146148 zig_object.symbols_free_list.deinit(gpa);
147149 zig_object.segment_info.deinit(gpa);
150 zig_object.segment_free_list.deinit(gpa);
148151
149152 zig_object.string_table.deinit(gpa);
150153 if (zig_object.dwarf) |*dwarf| {
......@@ -223,7 +226,7 @@ pub fn updateDecl(
223226 },
224227 };
225228
226 return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .data);
229 return zig_object.finishUpdateDecl(wasm_file, decl_index, code);
227230}
228231
229232pub fn updateFunc(
......@@ -263,7 +266,7 @@ pub fn updateFunc(
263266 },
264267 };
265268
266 return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .function);
269 return zig_object.finishUpdateDecl(wasm_file, decl_index, code);
267270}
268271
269272fn finishUpdateDecl(
......@@ -271,25 +274,89 @@ fn finishUpdateDecl(
271274 wasm_file: *Wasm,
272275 decl_index: InternPool.DeclIndex,
273276 code: []const u8,
274 symbol_tag: Symbol.Tag,
275277) !void {
276278 const gpa = wasm_file.base.comp.gpa;
277279 const mod = wasm_file.base.comp.module.?;
278280 const decl = mod.declPtr(decl_index);
279281 const atom_index = zig_object.decls.get(decl_index).?;
280282 const atom = wasm_file.getAtomPtr(atom_index);
281 const sym = zig_object.symbol(atom.getSymbolIndex().?);
283 const sym = zig_object.symbol(atom.sym_index);
282284 const full_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
283285 sym.name = try zig_object.string_table.insert(gpa, full_name);
284 sym.tag = symbol_tag;
285286 try atom.code.appendSlice(gpa, code);
286 try wasm_file.resolved_symbols.put(gpa, atom.symbolLoc(), {});
287
288287 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 }
289336 if (code.len == 0) return;
290337 atom.alignment = decl.getAlignment(mod);
291338}
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
293360/// For a given `InternPool.DeclIndex` returns its corresponding `Atom.Index`.
294361/// When the index was not found, a new `Atom` will be created, and its index will be returned.
295362/// 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
840907 const atom_index = zig_object.decls.get(decl_index).?;
841908 const atom = wasm_file.getAtomPtr(atom_index);
842909 zig_object.symbols_free_list.append(gpa, atom.sym_index) catch {};
843 _ = zig_object.decls.remove(decl_index);
844 zig_object.symbols.items[atom.sym_index].tag = .dead;
910 std.debug.assert(zig_object.decls.remove(decl_index));
911 const sym = &zig_object.symbols.items[atom.sym_index];
845912 for (atom.locals.items) |local_atom_index| {
846913 const local_atom = wasm_file.getAtom(local_atom_index);
847914 const local_symbol = &zig_object.symbols.items[local_atom.sym_index];
848 local_symbol.tag = .dead; // also for any local symbol
915 std.debug.assert(local_symbol.tag == .data);
849916 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
851922 }
852923
853924 if (decl.isExtern(mod)) {
854 _ = zig_object.imports.remove(atom.getSymbolIndex().?);
925 std.debug.assert(zig_object.imports.remove(atom.sym_index));
855926 }
856 _ = wasm_file.symbol_atom.remove(atom.symbolLoc());
927 std.debug.assert(wasm_file.symbol_atom.remove(atom.symbolLoc()));
857928
858929 // if (wasm.dwarf) |*dwarf| {
859930 // dwarf.freeDecl(decl_index);
......@@ -869,6 +940,20 @@ pub fn freeDecl(zig_object: *ZigObject, wasm_file: *Wasm, decl_index: InternPool
869940 prev_atom.next = atom.next;
870941 atom.prev = null;
871942 }
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 }
872957}
873958
874959fn 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) {
114114 }
115115
116116 pub const Entry = union(enum) {
117 null: void,
118117 zig_object: ZigObject,
119118 object: Object,
120119 };