@@ -1143,9 +1143,29 @@ pub fn addOrUpdateImport(
1143
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
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
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
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
1194
break :result self .code_section_index .? ;
1175
1195
},
1176
1196
.data = > result : {
1177
- // TODO: Add mutables global decls to .bss section instead
1178
1197
const segment_name = try std .mem .concat (self .base .allocator , u8 , &.{
1179
- ".rodata." ,
1198
+ kind . segmentName () ,
1180
1199
self .string_table .get (symbol .name ),
1181
1200
});
1182
1201
errdefer self .base .allocator .free (segment_name );
@@ -1236,6 +1255,9 @@ fn parseAtom(self: *Wasm, atom: *Atom, kind: Kind) !void {
1236
1255
}
1237
1256
1238
1257
fn allocateAtoms (self : * Wasm ) ! void {
1258
+ // first sort the data segments
1259
+ try sortDataSegments (self );
1260
+
1239
1261
var it = self .atoms .iterator ();
1240
1262
while (it .next ()) | entry | {
1241
1263
const segment = & self .segments .items [entry .key_ptr .* ];
@@ -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
1314
fn setupImports (self : * Wasm ) ! void {
1263
1315
log .debug ("Merging imports" , .{});
1264
1316
var discarded_it = self .discarded .keyIterator ();
@@ -1722,8 +1774,8 @@ fn populateErrorNameTable(self: *Wasm) !void {
1722
1774
1723
1775
// link the atoms with the rest of the binary so they can be allocated
1724
1776
// and relocations will be performed.
1725
- try self .parseAtom (atom , .data );
1726
- try self .parseAtom (names_atom , .data );
1777
+ try self .parseAtom (atom , .{ . data = .read_only } );
1778
+ try self .parseAtom (names_atom , .{ . data = .read_only } );
1727
1779
}
1728
1780
1729
1781
pub fn getDebugInfoIndex (self : * Wasm ) ! u32 {
@@ -1866,13 +1918,21 @@ pub fn flushModule(self: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
1866
1918
const atom = & decl .* .link .wasm ;
1867
1919
if (decl .ty .zigTypeTag () == .Fn ) {
1868
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
1929
} else {
1870
- try self .parseAtom (atom , .data );
1930
+ try self .parseAtom (atom , .{ . data = .read_only } );
1871
1931
}
1872
1932
1873
1933
// also parse atoms for a decl's locals
1874
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
2227
while (it .next ()) | entry | {
2168
2228
// do not output 'bss' section unless we import memory and therefore
2169
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
2231
segment_count += 1 ;
2172
2232
const atom_index = entry .value_ptr .* ;
2173
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
2370
}
2311
2371
}
2312
2372
// data segments are already 'ordered'
2313
- for (self .data_segments .keys ()) | key , index | {
2314
- 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 ;
2315
2380
}
2316
2381
2317
2382
std .sort .sort (Name , funcs .values (), {}, Name .lessThan );
0 commit comments