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.
This commit is contained in:
Luuk de Gram 2022-06-25 18:36:56 +02:00
parent e32a5ba78b
commit 140bac6395
No known key found for this signature in database
GPG Key ID: A8CFE58E4DC7D664

View File

@ -1255,6 +1255,9 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
}
fn allocateAtoms(self: *Wasm) !void {
// first sort the data segments
try sortDataSegments(self);
var it = self.atoms.iterator();
while (it.next()) |entry| {
const segment = &self.segments.items[entry.key_ptr.*];
@ -1278,6 +1281,36 @@ fn allocateAtoms(self: *Wasm) !void {
}
}
fn sortDataSegments(self: *Wasm) !void {
var new_mapping: std.StringArrayHashMapUnmanaged(u32) = .{};
try new_mapping.ensureUnusedCapacity(self.base.allocator, self.data_segments.count());
errdefer new_mapping.deinit(self.base.allocator);
const keys = try self.base.allocator.dupe([]const u8, self.data_segments.keys());
defer self.base.allocator.free(keys);
const SortContext = struct {
fn sort(_: void, lhs: []const u8, rhs: []const u8) bool {
return order(lhs) <= order(rhs);
}
fn order(name: []const u8) u8 {
if (mem.startsWith(u8, name, ".rodata")) return 0;
if (mem.startsWith(u8, name, ".data")) return 1;
if (mem.startsWith(u8, name, ".text")) return 2;
return 3;
}
};
std.sort.sort([]const u8, keys, {}, SortContext.sort);
for (keys) |key| {
const segment_index = self.data_segments.get(key).?;
new_mapping.putAssumeCapacity(key, segment_index);
}
self.data_segments.deinit(self.base.allocator);
self.data_segments = new_mapping;
}
fn setupImports(self: *Wasm) !void {
log.debug("Merging imports", .{});
var discarded_it = self.discarded.keyIterator();
@ -2337,8 +2370,13 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void {
}
}
// data segments are already 'ordered'
for (self.data_segments.keys()) |key, index| {
segments.appendAssumeCapacity(.{ .index = @intCast(u32, index), .name = key });
var data_segment_index: u32 = 0;
for (self.data_segments.keys()) |key| {
// bss section is not emitted when this condition holds true, so we also
// do not output a name for it.
if (!self.base.options.import_memory and std.mem.eql(u8, key, ".bss")) continue;
segments.appendAssumeCapacity(.{ .index = data_segment_index, .name = key });
data_segment_index += 1;
}
std.sort.sort(Name, funcs.values(), {}, Name.lessThan);