authorgravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-25 18:36:56+02:00
committergravatar for luuk@degram.devLuuk de Gram <luuk@degram.dev> 2022-06-25 18:36:56+02:00
log140bac6395610a3b9e5d5f92e2b366a27f6dcdc8
tree6ff6d50d21b32c04d47821b1c0695ce548c46704
parente32a5ba78b5e42788cba57720ce88cbfd30d434b
signaturelock-open Commit is signed but in an unrecognized format.

link/wasm: Sort data segments

We now ensure the "bss" section is last, which allows us to not emit this section and let the runtime initialize the memory with 0's instead. This allows for smaller binaries. The order of the other segments is arbitrary and does not matter, this may change in the future.

1 files changed, 40 insertions(+), 2 deletions(-)

src/link/Wasm.zig+40-2
......@@ -1255,6 +1255,9 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
12551255}
12561256
12571257fn allocateAtoms(self: *Wasm) !void {
1258 // first sort the data segments
1259 try sortDataSegments(self);
1260
12581261 var it = self.atoms.iterator();
12591262 while (it.next()) |entry| {
12601263 const segment = &self.segments.items[entry.key_ptr.*];
......@@ -1278,6 +1281,36 @@ fn allocateAtoms(self: *Wasm) !void {
12781281 }
12791282}
12801283
1284fn sortDataSegments(self: *Wasm) !void {
1285 var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};
1286 try new_mapping.ensureUnusedCapacity(self.base.allocator, self.data_segments.count());
1287 errdefer new_mapping.deinit(self.base.allocator);
1288
1289 const keys = try self.base.allocator.dupe([]const u8, self.data_segments.keys());
1290 defer self.base.allocator.free(keys);
1291
1292 const SortContext = struct {
1293 fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {
1294 return order(lhs) <= order(rhs);
1295 }
1296
1297 fn order(name: []const u8) u8 {
1298 if (mem.startsWith(u8, name, ".rodata")) return 0;
1299 if (mem.startsWith(u8, name, ".data")) return 1;
1300 if (mem.startsWith(u8, name, ".text")) return 2;
1301 return 3;
1302 }
1303 };
1304
1305 std.sort.sort([]const u8, keys, {}, SortContext.sort);
1306 for (keys) |key| {
1307 const segment_index = self.data_segments.get(key).?;
1308 new_mapping.putAssumeCapacity(key, segment_index);
1309 }
1310 self.data_segments.deinit(self.base.allocator);
1311 self.data_segments = new_mapping;
1312}
1313
12811314fn setupImports(self: *Wasm) !void {
12821315 log.debug("Merging imports", .{});
12831316 var discarded_it = self.discarded.keyIterator();
......@@ -2337,8 +2370,13 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
23372370 }
23382371 }
23392372 // data segments are already 'ordered'
2340 for (self.data_segments.keys()) |key, index| {
2341 segments.appendAssumeCapacity(.{ .index = @intCast(u32, index), .name = key });
2373 var data_segment_index: u32 = 0;
2374 for (self.data_segments.keys()) |key| {
2375 // bss section is not emitted when this condition holds true, so we also
2376 // do not output a name for it.
2377 if (!self.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
2378 segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
2379 data_segment_index += 1;
23422380 }
23432381
23442382 std.sort.sort(Name, funcs.values(), {}, Name.lessThan);