| ... | @@ -123,6 +123,13 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{}, | ... | @@ -123,6 +123,13 @@ symbol_atom: std.AutoHashMapUnmanaged(SymbolLoc, *Atom) = .{}, |
| 123 | /// Note: The value represents the offset into the string table, rather than the actual string. | 123 | /// Note: The value represents the offset into the string table, rather than the actual string. |
| 124 | export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, | 124 | export_names: std.AutoHashMapUnmanaged(SymbolLoc, u32) = .{}, |
| 125 | | 125 | |
| | 126 | /// Represents the symbol index of the error name table |
| | 127 | /// When this is `null`, no code references an error using runtime `@errorName`. |
| | 128 | /// During initializion, a symbol with corresponding atom will be created that is |
| | 129 | /// used to perform relocations to the pointer of this table. |
| | 130 | /// The actual table is populated during `flush`. |
| | 131 | error_table_symbol: ?u32 = null, |
| | 132 | |
| 126 | pub const Segment = struct { | 133 | pub const Segment = struct { |
| 127 | alignment: u32, | 134 | alignment: u32, |
| 128 | size: u32, | 135 | size: u32, |
| ... | @@ -1322,6 +1329,123 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32 | ... | @@ -1322,6 +1329,123 @@ pub fn getMatchingSegment(self: *Wasm, object_index: u16, relocatable_index: u32 |
| 1322 | } | 1329 | } |
| 1323 | } | 1330 | } |
| 1324 | | 1331 | |
| | 1332 | /// Returns the symbol index of the error name table. |
| | 1333 | /// |
| | 1334 | /// When the symbol does not yet exist, it will create a new one instead. |
| | 1335 | pub fn getErrorTableSymbol(self: *Wasm) !u32 { |
| | 1336 | if (self.error_table_symbol) |symbol| { |
| | 1337 | return symbol; |
| | 1338 | } |
| | 1339 | |
| | 1340 | // no error was referenced yet, so create a new symbol and atom for it |
| | 1341 | // and then return said symbol's index. The final table will be populated |
| | 1342 | // during `flush` when we know all possible error names. |
| | 1343 | |
| | 1344 | // As sym_index '0' is reserved, we use it for our stack pointer symbol |
| | 1345 | const symbol_index = self.symbols_free_list.popOrNull() orelse blk: { |
| | 1346 | const index = @intCast(u32, self.symbols.items.len); |
| | 1347 | _ = try self.symbols.addOne(self.base.allocator); |
| | 1348 | break :blk index; |
| | 1349 | }; |
| | 1350 | |
| | 1351 | const sym_name = try self.string_table.put(self.base.allocator, "__zig_err_name_table"); |
| | 1352 | const symbol = &self.symbols.items[symbol_index]; |
| | 1353 | symbol.* = .{ |
| | 1354 | .name = sym_name, |
| | 1355 | .tag = .data, |
| | 1356 | .flags = 0, |
| | 1357 | .index = 0, |
| | 1358 | }; |
| | 1359 | symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 1360 | |
| | 1361 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| | 1362 | |
| | 1363 | const atom = try self.base.allocator.create(Atom); |
| | 1364 | atom.* = Atom.empty; |
| | 1365 | atom.sym_index = symbol_index; |
| | 1366 | atom.alignment = slice_ty.abiAlignment(self.base.options.target); |
| | 1367 | try self.managed_atoms.append(self.base.allocator, atom); |
| | 1368 | const loc = atom.symbolLoc(); |
| | 1369 | try self.resolved_symbols.put(self.base.allocator, loc, {}); |
| | 1370 | try self.symbol_atom.put(self.base.allocator, loc, atom); |
| | 1371 | |
| | 1372 | log.debug("Error name table was created with symbol index: ({d})", .{symbol_index}); |
| | 1373 | self.error_table_symbol = symbol_index; |
| | 1374 | return symbol_index; |
| | 1375 | } |
| | 1376 | |
| | 1377 | /// Populates the error name table, when `error_table_symbol` is not null. |
| | 1378 | /// |
| | 1379 | /// This creates a table that consists of pointers and length to each error name. |
| | 1380 | /// The table is what is being pointed to within the runtime bodies that are generated. |
| | 1381 | fn populateErrorNameTable(self: *Wasm) !void { |
| | 1382 | const symbol_index = self.error_table_symbol orelse return; |
| | 1383 | const atom: *Atom = self.symbol_atom.get(.{ .file = null, .index = symbol_index }).?; |
| | 1384 | // Rather than creating a symbol for each individual error name, |
| | 1385 | // we create a symbol for the entire region of error names. We then calculate |
| | 1386 | // the pointers into the list using addends which are appended to the relocation. |
| | 1387 | const names_atom = try self.base.allocator.create(Atom); |
| | 1388 | names_atom.* = Atom.empty; |
| | 1389 | try self.managed_atoms.append(self.base.allocator, names_atom); |
| | 1390 | const names_symbol_index = self.symbols_free_list.popOrNull() orelse blk: { |
| | 1391 | const index = @intCast(u32, self.symbols.items.len); |
| | 1392 | _ = try self.symbols.addOne(self.base.allocator); |
| | 1393 | break :blk index; |
| | 1394 | }; |
| | 1395 | names_atom.sym_index = names_symbol_index; |
| | 1396 | names_atom.alignment = 1; |
| | 1397 | const sym_name = try self.string_table.put(self.base.allocator, "__zig_err_names"); |
| | 1398 | const names_symbol = &self.symbols.items[names_symbol_index]; |
| | 1399 | names_symbol.* = .{ |
| | 1400 | .name = sym_name, |
| | 1401 | .tag = .data, |
| | 1402 | .flags = 0, |
| | 1403 | .index = 0, |
| | 1404 | }; |
| | 1405 | names_symbol.setFlag(.WASM_SYM_VISIBILITY_HIDDEN); |
| | 1406 | |
| | 1407 | log.debug("Populating error names", .{}); |
| | 1408 | |
| | 1409 | // Addend for each relocation to the table |
| | 1410 | var addend: u32 = 0; |
| | 1411 | const module = self.base.options.module.?; |
| | 1412 | for (module.error_name_list.items) |error_name| { |
| | 1413 | const len = @intCast(u32, error_name.len + 1); // names are 0-termianted |
| | 1414 | |
| | 1415 | const slice_ty = Type.initTag(.const_slice_u8_sentinel_0); |
| | 1416 | const offset = @intCast(u32, atom.code.items.len); |
| | 1417 | // first we create the data for the slice of the name |
| | 1418 | try atom.code.appendNTimes(self.base.allocator, 0, 4); // ptr to name, will be relocated |
| | 1419 | try atom.code.writer(self.base.allocator).writeIntLittle(u32, len - 1); |
| | 1420 | // create relocation to the error name |
| | 1421 | try atom.relocs.append(self.base.allocator, .{ |
| | 1422 | .index = names_symbol_index, |
| | 1423 | .relocation_type = .R_WASM_MEMORY_ADDR_I32, |
| | 1424 | .offset = offset, |
| | 1425 | .addend = addend, |
| | 1426 | }); |
| | 1427 | atom.size += @intCast(u32, slice_ty.abiSize(self.base.options.target)); |
| | 1428 | addend += len; |
| | 1429 | |
| | 1430 | // as we updated the error name table, we now store the actual name within the names atom |
| | 1431 | try names_atom.code.ensureUnusedCapacity(self.base.allocator, len); |
| | 1432 | names_atom.code.appendSliceAssumeCapacity(error_name); |
| | 1433 | names_atom.code.appendAssumeCapacity(0); |
| | 1434 | |
| | 1435 | log.debug("Populated error name: '{s}'", .{error_name}); |
| | 1436 | } |
| | 1437 | names_atom.size = addend; |
| | 1438 | |
| | 1439 | const name_loc = names_atom.symbolLoc(); |
| | 1440 | try self.resolved_symbols.put(self.base.allocator, name_loc, {}); |
| | 1441 | try self.symbol_atom.put(self.base.allocator, name_loc, names_atom); |
| | 1442 | |
| | 1443 | // link the atoms with the rest of the binary so they can be allocated |
| | 1444 | // and relocations will be performed. |
| | 1445 | try self.parseAtom(atom, .data); |
| | 1446 | try self.parseAtom(names_atom, .data); |
| | 1447 | } |
| | 1448 | |
| 1325 | fn resetState(self: *Wasm) void { | 1449 | fn resetState(self: *Wasm) void { |
| 1326 | for (self.segment_info.items) |*segment_info| { | 1450 | for (self.segment_info.items) |*segment_info| { |
| 1327 | self.base.allocator.free(segment_info.name); | 1451 | self.base.allocator.free(segment_info.name); |
| ... | @@ -1373,6 +1497,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { | ... | @@ -1373,6 +1497,9 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 1373 | } | 1497 | } |
| 1374 | } | 1498 | } |
| 1375 | | 1499 | |
| | 1500 | // ensure the error names table is populated when an error name is referenced |
| | 1501 | try self.populateErrorNameTable(); |
| | 1502 | |
| 1376 | // The amount of sections that will be written | 1503 | // The amount of sections that will be written |
| 1377 | var section_count: u32 = 0; | 1504 | var section_count: u32 = 0; |
| 1378 | // Index of the code section. Used to tell relocation table where the section lives. | 1505 | // Index of the code section. Used to tell relocation table where the section lives. |