| ... | @@ -1143,9 +1143,29 @@ pub fn addOrUpdateImport( | ... | @@ -1143,9 +1143,29 @@ pub fn addOrUpdateImport( |
| 1143 | } else @panic("TODO: Implement undefined symbols for non-function declarations"); | 1143 | } else @panic("TODO: Implement undefined symbols for non-function declarations"); |
| 1144 | } | 1144 | } |
| 1145 | | 1145 | |
| | 1146 | /// Kind represents the type of an Atom, which is only |
| | 1147 | /// used to parse a decl into an Atom to define in which section |
| | 1148 | /// or segment it should be placed. |
| 1146 | const Kind = union(enum) { | 1149 | const Kind = union(enum) { |
| 1147 | data: void, | 1150 | /// Represents the segment the data symbol should |
| | 1151 | /// be inserted into. |
| | 1152 | /// TODO: Add TLS segments |
| | 1153 | data: enum { |
| | 1154 | read_only, |
| | 1155 | uninitialized, |
| | 1156 | initialized, |
| | 1157 | }, |
| 1148 | function: FnData, | 1158 | function: FnData, |
| | 1159 | |
| | 1160 | /// Returns the segment name the data kind represents. |
| | 1161 | /// Asserts `kind` has its active tag set to `data`. |
| | 1162 | fn segmentName(kind: Kind) []const u8 { |
| | 1163 | switch (kind.data) { |
| | 1164 | .read_only => return ".rodata.", |
| | 1165 | .uninitialized => return ".bss.", |
| | 1166 | .initialized => return ".data.", |
| | 1167 | } |
| | 1168 | } |
| 1149 | }; | 1169 | }; |
| 1150 | | 1170 | |
| 1151 | /// Parses an Atom and inserts its metadata into the corresponding sections. | 1171 | /// Parses an Atom and inserts its metadata into the corresponding sections. |
| ... | @@ -1174,9 +1194,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { | ... | @@ -1174,9 +1194,8 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1174 | break :result self.code_section_index.?; | 1194 | break :result self.code_section_index.?; |
| 1175 | }, | 1195 | }, |
| 1176 | .data => result: { | 1196 | .data => result: { |
| 1177 | // TODO: Add mutables global decls to .bss section instead | | |
| 1178 | const segment_name = try std.mem.concat(self.base.allocator, u8, &.{ | 1197 | const segment_name = try std.mem.concat(self.base.allocator, u8, &.{ |
| 1179 | ".rodata.", | 1198 | kind.segmentName(), |
| 1180 | self.string_table.get(symbol.name), | 1199 | self.string_table.get(symbol.name), |
| 1181 | }); | 1200 | }); |
| 1182 | errdefer self.base.allocator.free(segment_name); | 1201 | errdefer self.base.allocator.free(segment_name); |
| ... | @@ -1236,6 +1255,9 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { | ... | @@ -1236,6 +1255,9 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void { |
| 1236 | } | 1255 | } |
| 1237 | | 1256 | |
| 1238 | fn allocateAtoms(self: *Wasm) !void { | 1257 | fn allocateAtoms(self: *Wasm) !void { |
| | 1258 | // first sort the data segments |
| | 1259 | try sortDataSegments(self); |
| | 1260 | |
| 1239 | var it = self.atoms.iterator(); | 1261 | var it = self.atoms.iterator(); |
| 1240 | while (it.next()) |entry| { | 1262 | while (it.next()) |entry| { |
| 1241 | const segment = &self.segments.items[entry.key_ptr.*]; | 1263 | const segment = &self.segments.items[entry.key_ptr.*]; |
| ... | @@ -1259,6 +1281,36 @@ fn allocateAtoms(self: *Wasm) !void { | ... | @@ -1259,6 +1281,36 @@ fn allocateAtoms(self: *Wasm) !void { |
| 1259 | } | 1281 | } |
| 1260 | } | 1282 | } |
| 1261 | | 1283 | |
| | 1284 | fn 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 | |
| 1262 | fn setupImports(self: *Wasm) !void { | 1314 | fn setupImports(self: *Wasm) !void { |
| 1263 | log.debug("Merging imports", .{}); | 1315 | log.debug("Merging imports", .{}); |
| 1264 | var discarded_it = self.discarded.keyIterator(); | 1316 | var discarded_it = self.discarded.keyIterator(); |
| ... | @@ -1722,8 +1774,8 @@ fn populateErrorNameTable(self: *Wasm) !void { | ... | @@ -1722,8 +1774,8 @@ fn populateErrorNameTable(self: *Wasm) !void { |
| 1722 | | 1774 | |
| 1723 | // link the atoms with the rest of the binary so they can be allocated | 1775 | // link the atoms with the rest of the binary so they can be allocated |
| 1724 | // and relocations will be performed. | 1776 | // and relocations will be performed. |
| 1725 | try self.parseAtom(atom, .data); | 1777 | try self.parseAtom(atom, .{ .data = .read_only }); |
| 1726 | try self.parseAtom(names_atom, .data); | 1778 | try self.parseAtom(names_atom, .{ .data = .read_only }); |
| 1727 | } | 1779 | } |
| 1728 | | 1780 | |
| 1729 | pub fn getDebugInfoIndex(self: *Wasm) !u32 { | 1781 | pub fn getDebugInfoIndex(self: *Wasm) !u32 { |
| ... | @@ -1866,13 +1918,21 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -1866,13 +1918,21 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 1866 | const atom = &decl.*.link.wasm; | 1918 | const atom = &decl.*.link.wasm; |
| 1867 | if (decl.ty.zigTypeTag() == .Fn) { | 1919 | if (decl.ty.zigTypeTag() == .Fn) { |
| 1868 | try self.parseAtom(atom, .{ .function = decl.fn_link.wasm }); | 1920 | try self.parseAtom(atom, .{ .function = decl.fn_link.wasm }); |
| | 1921 | } else if (decl.getVariable()) |variable| { |
| | 1922 | if (!variable.is_mutable) { |
| | 1923 | try self.parseAtom(atom, .{ .data = .read_only }); |
| | 1924 | } else if (variable.init.isUndefDeep()) { |
| | 1925 | try self.parseAtom(atom, .{ .data = .uninitialized }); |
| | 1926 | } else { |
| | 1927 | try self.parseAtom(atom, .{ .data = .initialized }); |
| | 1928 | } |
| 1869 | } else { | 1929 | } else { |
| 1870 | try self.parseAtom(atom, .data); | 1930 | try self.parseAtom(atom, .{ .data = .read_only }); |
| 1871 | } | 1931 | } |
| 1872 | | 1932 | |
| 1873 | // also parse atoms for a decl's locals | 1933 | // also parse atoms for a decl's locals |
| 1874 | for (atom.locals.items) |*local_atom| { | 1934 | for (atom.locals.items) |*local_atom| { |
| 1875 | try self.parseAtom(local_atom, .data); | 1935 | try self.parseAtom(local_atom, .{ .data = .read_only }); |
| 1876 | } | 1936 | } |
| 1877 | } | 1937 | } |
| 1878 | | 1938 | |
| ... | @@ -2167,7 +2227,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod | ... | @@ -2167,7 +2227,7 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2167 | while (it.next()) |entry| { | 2227 | while (it.next()) |entry| { |
| 2168 | // do not output 'bss' section unless we import memory and therefore | 2228 | // do not output 'bss' section unless we import memory and therefore |
| 2169 | // want to guarantee the data is zero initialized | 2229 | // want to guarantee the data is zero initialized |
| 2170 | if (std.mem.eql(u8, entry.key_ptr.*, ".bss") and !import_memory) continue; | 2230 | if (!import_memory and std.mem.eql(u8, entry.key_ptr.*, ".bss")) continue; |
| 2171 | segment_count += 1; | 2231 | segment_count += 1; |
| 2172 | const atom_index = entry.value_ptr.*; | 2232 | const atom_index = entry.value_ptr.*; |
| 2173 | var atom: *Atom = self.atoms.getPtr(atom_index).?.*.getFirst(); | 2233 | var atom: *Atom = self.atoms.getPtr(atom_index).?.*.getFirst(); |
| ... | @@ -2310,8 +2370,13 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { | ... | @@ -2310,8 +2370,13 @@ fn emitNameSection(self: *Wasm, file: fs.File, arena: Allocator) !void { |
| 2310 | } | 2370 | } |
| 2311 | } | 2371 | } |
| 2312 | // data segments are already 'ordered' | 2372 | // data segments are already 'ordered' |
| 2313 | for (self.data_segments.keys()) |key, index| { | 2373 | var data_segment_index: u32 = 0; |
| 2314 | segments.appendAssumeCapacity(.{ .index = @intCast(u32, index), .name = key }); | 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; |
| 2315 | } | 2380 | } |
| 2316 | | 2381 | |
| 2317 | std.sort.sort(Name, funcs.values(), {}, Name.lessThan); | 2382 | std.sort.sort(Name, funcs.values(), {}, Name.lessThan); |