| ... | @@ -29,6 +29,8 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, | ... | @@ -29,6 +29,8 @@ global_syms: std.AutoHashMapUnmanaged(u32, u32) = .{}, |
| 29 | symbols_free_list: std.ArrayListUnmanaged(u32) = .{}, | 29 | symbols_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. |
| 31 | segment_info: std.ArrayListUnmanaged(types.Segment) = .{}, | 31 | segment_info: std.ArrayListUnmanaged(types.Segment) = .{}, |
| | 32 | /// List of indexes which contain a free slot in the `segment_info` list. |
| | 33 | segment_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. |
| 33 | string_table: StringTable = .{}, | 35 | string_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); |
| 148 | | 151 | |
| 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 | }; |
| 225 | | 228 | |
| 226 | return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .data); | 229 | return zig_object.finishUpdateDecl(wasm_file, decl_index, code); |
| 227 | } | 230 | } |
| 228 | | 231 | |
| 229 | pub fn updateFunc( | 232 | pub fn updateFunc( |
| ... | @@ -263,7 +266,7 @@ pub fn updateFunc( | ... | @@ -263,7 +266,7 @@ pub fn updateFunc( |
| 263 | }, | 266 | }, |
| 264 | }; | 267 | }; |
| 265 | | 268 | |
| 266 | return zig_object.finishUpdateDecl(wasm_file, decl_index, code, .function); | 269 | return zig_object.finishUpdateDecl(wasm_file, decl_index, code); |
| 267 | } | 270 | } |
| 268 | | 271 | |
| 269 | fn finishUpdateDecl( | 272 | fn 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 | } |
| 292 | | 339 | |
| | 340 | fn 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 symbol | 915 | 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 | } |
| 852 | | 923 | |
| 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())); |
| 857 | | 928 | |
| 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 | } |
| 873 | | 958 | |
| 874 | fn getTypeIndex(zig_object: *const ZigObject, func_type: std.wasm.Type) ?u32 { | 959 | fn getTypeIndex(zig_object: *const ZigObject, func_type: std.wasm.Type) ?u32 { |