| ... | ... | @@ -328,6 +328,7 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 328 | 328 | self.symbols_free_list.append(self.base.allocator, atom.sym_index) catch {}; |
| 329 | 329 | atom.deinit(self.base.allocator); |
| 330 | 330 | _ = self.decls.remove(decl); |
| 331 | self.symbols.items[atom.sym_index].tag = .dead; // to ensure it does not end in the names section |
| 331 | 332 | |
| 332 | 333 | if (decl.isExtern()) { |
| 333 | 334 | const import = self.imports.fetchRemove(decl.link.wasm.sym_index).?.value; |
| ... | ... | @@ -336,11 +337,6 @@ pub fn freeDecl(self: *Wasm, decl: *Module.Decl) void { |
| 336 | 337 | else => unreachable, |
| 337 | 338 | } |
| 338 | 339 | } |
| 339 | | |
| 340 | | // maybe remove from function table if needed |
| 341 | | if (decl.ty.zigTypeTag() == .Fn) { |
| 342 | | _ = self.function_table.remove(atom.sym_index); |
| 343 | | } |
| 344 | 340 | } |
| 345 | 341 | |
| 346 | 342 | /// Appends a new entry to the indirect function table |
| ... | ... | @@ -915,6 +911,75 @@ pub fn flushModule(self: *Wasm, comp: *Compilation) !void { |
| 915 | 911 | @intCast(u32, segment_count), |
| 916 | 912 | ); |
| 917 | 913 | } |
| 914 | |
| 915 | // Custom section "name" which contains symbol names |
| 916 | { |
| 917 | const Name = struct { |
| 918 | index: u32, |
| 919 | name: []const u8, |
| 920 | |
| 921 | fn lessThan(context: void, lhs: @This(), rhs: @This()) bool { |
| 922 | _ = context; |
| 923 | return lhs.index < rhs.index; |
| 924 | } |
| 925 | }; |
| 926 | |
| 927 | var funcs = try std.ArrayList(Name).initCapacity(self.base.allocator, self.functions.items.len + self.imported_functions_count); |
| 928 | defer funcs.deinit(); |
| 929 | var globals = try std.ArrayList(Name).initCapacity(self.base.allocator, self.globals.items.len); |
| 930 | defer globals.deinit(); |
| 931 | var segments = try std.ArrayList(Name).initCapacity(self.base.allocator, self.data_segments.count()); |
| 932 | defer segments.deinit(); |
| 933 | |
| 934 | for (self.symbols.items) |symbol| { |
| 935 | switch (symbol.tag) { |
| 936 | .function => funcs.appendAssumeCapacity(.{ .index = symbol.index, .name = std.mem.sliceTo(symbol.name, 0) }), |
| 937 | .global => globals.appendAssumeCapacity(.{ .index = symbol.index, .name = std.mem.sliceTo(symbol.name, 0) }), |
| 938 | else => {}, |
| 939 | } |
| 940 | } |
| 941 | // data segments are already 'ordered' |
| 942 | for (self.data_segments.keys()) |key, index| { |
| 943 | segments.appendAssumeCapacity(.{ .index = @intCast(u32, index), .name = key }); |
| 944 | } |
| 945 | |
| 946 | std.sort.sort(Name, funcs.items, {}, Name.lessThan); |
| 947 | std.sort.sort(Name, globals.items, {}, Name.lessThan); |
| 948 | |
| 949 | const header_offset = try reserveCustomSectionHeader(file); |
| 950 | const writer = file.writer(); |
| 951 | try leb.writeULEB128(writer, @intCast(u32, "name".len)); |
| 952 | try writer.writeAll("name"); |
| 953 | |
| 954 | try self.emitNameSubsection(.function, funcs.items, writer); |
| 955 | try self.emitNameSubsection(.global, globals.items, writer); |
| 956 | try self.emitNameSubsection(.data_segment, segments.items, writer); |
| 957 | |
| 958 | try writeCustomSectionHeader( |
| 959 | file, |
| 960 | header_offset, |
| 961 | @intCast(u32, (try file.getPos()) - header_offset - header_size), |
| 962 | ); |
| 963 | } |
| 964 | } |
| 965 | |
| 966 | fn emitNameSubsection(self: *Wasm, section_id: std.wasm.NameSubsection, names: anytype, writer: anytype) !void { |
| 967 | // We must emit subsection size, so first write to a temporary list |
| 968 | var section_list = std.ArrayList(u8).init(self.base.allocator); |
| 969 | defer section_list.deinit(); |
| 970 | const sub_writer = section_list.writer(); |
| 971 | |
| 972 | try leb.writeULEB128(sub_writer, @intCast(u32, names.len)); |
| 973 | for (names) |name| { |
| 974 | try leb.writeULEB128(sub_writer, name.index); |
| 975 | try leb.writeULEB128(sub_writer, @intCast(u32, name.name.len)); |
| 976 | try sub_writer.writeAll(name.name); |
| 977 | } |
| 978 | |
| 979 | // From now, write to the actual writer |
| 980 | try leb.writeULEB128(writer, @enumToInt(section_id)); |
| 981 | try leb.writeULEB128(writer, @intCast(u32, section_list.items.len)); |
| 982 | try writer.writeAll(section_list.items); |
| 918 | 983 | } |
| 919 | 984 | |
| 920 | 985 | fn emitLimits(writer: anytype, limits: wasm.Limits) !void { |
| ... | ... | @@ -1335,6 +1400,15 @@ fn reserveVecSectionHeader(file: fs.File) !u64 { |
| 1335 | 1400 | return (try file.getPos()) - header_size; |
| 1336 | 1401 | } |
| 1337 | 1402 | |
| 1403 | fn reserveCustomSectionHeader(file: fs.File) !u64 { |
| 1404 | // unlike regular section, we don't emit the count |
| 1405 | const header_size = 1 + 5; |
| 1406 | // TODO: this should be a single lseek(2) call, but fs.File does not |
| 1407 | // currently provide a way to do this. |
| 1408 | try file.seekBy(header_size); |
| 1409 | return (try file.getPos()) - header_size; |
| 1410 | } |
| 1411 | |
| 1338 | 1412 | fn writeVecSectionHeader(file: fs.File, offset: u64, section: wasm.Section, size: u32, items: u32) !void { |
| 1339 | 1413 | var buf: [1 + 5 + 5]u8 = undefined; |
| 1340 | 1414 | buf[0] = @enumToInt(section); |
| ... | ... | @@ -1343,6 +1417,13 @@ fn writeVecSectionHeader(file: fs.File, offset: u64, section: wasm.Section, size |
| 1343 | 1417 | try file.pwriteAll(&buf, offset); |
| 1344 | 1418 | } |
| 1345 | 1419 | |
| 1420 | fn writeCustomSectionHeader(file: fs.File, offset: u64, size: u32) !void { |
| 1421 | var buf: [1 + 5]u8 = undefined; |
| 1422 | buf[0] = 0; // 0 = 'custom' section |
| 1423 | leb.writeUnsignedFixed(5, buf[1..6], size); |
| 1424 | try file.pwriteAll(&buf, offset); |
| 1425 | } |
| 1426 | |
| 1346 | 1427 | /// Searches for an a matching function signature, when not found |
| 1347 | 1428 | /// a new entry will be made. The index of the existing/new signature will be returned. |
| 1348 | 1429 | pub fn putOrGetFuncType(self: *Wasm, func_type: wasm.Type) !u32 { |