authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-12-20 22:15:21-08:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2025-01-15 15:11:36-08:00
log728103467edba5f3407b1aaa89c9b6dda9432884
treeef64a910bd3240e28496e49a7ee98bb784c8edd8
parentfbbb54bab212e8db251ea7409945d5cecfd732c6

wasm linker: implement indirect function calls


5 files changed, 129 insertions(+), 92 deletions(-)

src/arch/wasm/CodeGen.zig+27-3
...@@ -1021,7 +1021,20 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {...@@ -1021,7 +1021,20 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
1021 .float32 => |val| try cg.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),1021 .float32 => |val| try cg.addInst(.{ .tag = .f32_const, .data = .{ .float32 = val } }),
1022 .float64 => |val| try cg.addFloat64(val),1022 .float64 => |val| try cg.addFloat64(val),
1023 .nav_ref => |nav_ref| {1023 .nav_ref => |nav_ref| {
1024 if (nav_ref.offset == 0) {1024 const wasm = cg.wasm;
1025 const comp = wasm.base.comp;
1026 const zcu = comp.zcu.?;
1027 const ip = &zcu.intern_pool;
1028 const ip_index = ip.getNav(nav_ref.nav_index).status.resolved.val;
1029 if (ip.isFunctionType(ip.typeOf(ip_index))) {
1030 assert(nav_ref.offset == 0);
1031 const gop = try wasm.indirect_function_table.getOrPut(comp.gpa, ip_index);
1032 if (!gop.found_existing) gop.value_ptr.* = {};
1033 try cg.addInst(.{
1034 .tag = .func_ref,
1035 .data = .{ .indirect_function_table_index = @enumFromInt(gop.index) },
1036 });
1037 } else if (nav_ref.offset == 0) {
1025 try cg.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } });1038 try cg.addInst(.{ .tag = .nav_ref, .data = .{ .nav_index = nav_ref.nav_index } });
1026 } else {1039 } else {
1027 try cg.addInst(.{1040 try cg.addInst(.{
...@@ -1037,8 +1050,19 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {...@@ -1037,8 +1050,19 @@ fn emitWValue(cg: *CodeGen, value: WValue) InnerError!void {
1037 },1050 },
1038 .uav_ref => |uav| {1051 .uav_ref => |uav| {
1039 const wasm = cg.wasm;1052 const wasm = cg.wasm;
1040 const is_obj = wasm.base.comp.config.output_mode == .Obj;1053 const comp = wasm.base.comp;
1041 if (uav.offset == 0) {1054 const is_obj = comp.config.output_mode == .Obj;
1055 const zcu = comp.zcu.?;
1056 const ip = &zcu.intern_pool;
1057 if (ip.isFunctionType(ip.typeOf(uav.ip_index))) {
1058 assert(uav.offset == 0);
1059 const gop = try wasm.indirect_function_table.getOrPut(comp.gpa, uav.ip_index);
1060 if (!gop.found_existing) gop.value_ptr.* = {};
1061 try cg.addInst(.{
1062 .tag = .func_ref,
1063 .data = .{ .indirect_function_table_index = @enumFromInt(gop.index) },
1064 });
1065 } else if (uav.offset == 0) {
1042 try cg.addInst(.{1066 try cg.addInst(.{
1043 .tag = .uav_ref,1067 .tag = .uav_ref,
1044 .data = if (is_obj) .{1068 .data = if (is_obj) .{
src/arch/wasm/Emit.zig+23-31
...@@ -76,7 +76,16 @@ pub fn lowerToCode(emit: *Emit) Error!void {...@@ -76,7 +76,16 @@ pub fn lowerToCode(emit: *Emit) Error!void {
76 inst += 1;76 inst += 1;
77 continue :loop tags[inst];77 continue :loop tags[inst];
78 },78 },
7979 .func_ref => {
80 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));
81 if (is_obj) {
82 @panic("TODO");
83 } else {
84 leb.writeUleb128(code.fixedWriter(), @intFromEnum(datas[inst].indirect_function_table_index)) catch unreachable;
85 }
86 inst += 1;
87 continue :loop tags[inst];
88 },
80 .dbg_line => {89 .dbg_line => {
81 inst += 1;90 inst += 1;
82 continue :loop tags[inst];91 continue :loop tags[inst];
...@@ -938,40 +947,23 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff...@@ -938,40 +947,23 @@ fn navRefOff(wasm: *Wasm, code: *std.ArrayListUnmanaged(u8), data: Mir.NavRefOff
938 const gpa = comp.gpa;947 const gpa = comp.gpa;
939 const is_obj = comp.config.output_mode == .Obj;948 const is_obj = comp.config.output_mode == .Obj;
940 const nav_ty = ip.getNav(data.nav_index).typeOf(ip);949 const nav_ty = ip.getNav(data.nav_index).typeOf(ip);
950 assert(!ip.isFunctionType(nav_ty));
941951
942 try code.ensureUnusedCapacity(gpa, 11);952 try code.ensureUnusedCapacity(gpa, 11);
943953
944 if (ip.isFunctionType(nav_ty)) {954 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;
945 code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const));955 code.appendAssumeCapacity(@intFromEnum(opcode));
946 assert(data.offset == 0);956 if (is_obj) {
947 if (is_obj) {957 try wasm.out_relocs.append(gpa, .{
948 try wasm.out_relocs.append(gpa, .{958 .offset = @intCast(code.items.len),
949 .offset = @intCast(code.items.len),959 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
950 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },960 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
951 .tag = .TABLE_INDEX_SLEB,961 .addend = data.offset,
952 .addend = data.offset,962 });
953 });963 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
954 code.appendNTimesAssumeCapacity(0, 5);
955 } else {
956 const function_imports_len: u32 = @intCast(wasm.function_imports.entries.len);
957 const func_index = Wasm.FunctionIndex.fromIpNav(wasm, data.nav_index).?;
958 leb.writeUleb128(code.fixedWriter(), function_imports_len + @intFromEnum(func_index)) catch unreachable;
959 }
960 } else {964 } else {
961 const opcode: std.wasm.Opcode = if (is_wasm32) .i32_const else .i64_const;965 const addr = wasm.navAddr(data.nav_index);
962 code.appendAssumeCapacity(@intFromEnum(opcode));966 leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + data.offset))) catch unreachable;
963 if (is_obj) {
964 try wasm.out_relocs.append(gpa, .{
965 .offset = @intCast(code.items.len),
966 .pointee = .{ .symbol_index = try wasm.navSymbolIndex(data.nav_index) },
967 .tag = if (is_wasm32) .MEMORY_ADDR_LEB else .MEMORY_ADDR_LEB64,
968 .addend = data.offset,
969 });
970 code.appendNTimesAssumeCapacity(0, if (is_wasm32) 5 else 10);
971 } else {
972 const addr = wasm.navAddr(data.nav_index);
973 leb.writeUleb128(code.fixedWriter(), @as(u32, @intCast(@as(i64, addr) + data.offset))) catch unreachable;
974 }
975 }967 }
976}968}
977969
src/arch/wasm/Mir.zig+14-10
...@@ -65,9 +65,7 @@ pub const Inst = struct {...@@ -65,9 +65,7 @@ pub const Inst = struct {
65 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the65 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) which is the
66 /// memory address of a named constant.66 /// memory address of a named constant.
67 ///67 ///
68 /// When this refers to a function, this always lowers to an i32_const68 /// May not refer to a function.
69 /// which is the function index. When emitting an object file, this
70 /// adds a `Wasm.Relocation.Tag.TABLE_INDEX_SLEB` relocation.
71 ///69 ///
72 /// Uses `nav_index`.70 /// Uses `nav_index`.
73 nav_ref,71 nav_ref,
...@@ -75,10 +73,15 @@ pub const Inst = struct {...@@ -75,10 +73,15 @@ pub const Inst = struct {
75 /// memory address of named constant, offset by an integer value.73 /// memory address of named constant, offset by an integer value.
76 /// When emitting an object file, this adds a relocation.74 /// When emitting an object file, this adds a relocation.
77 ///75 ///
78 /// This may not refer to a function.76 /// May not refer to a function.
79 ///77 ///
80 /// Uses `payload` pointing to a `NavRefOff`.78 /// Uses `payload` pointing to a `NavRefOff`.
81 nav_ref_off,79 nav_ref_off,
80 /// Lowers to an i32_const which is the index of the function in the
81 /// table section.
82 ///
83 /// Uses `indirect_function_table_index`.
84 func_ref,
82 /// Inserts debug information about the current line and column85 /// Inserts debug information about the current line and column
83 /// of the source code86 /// of the source code
84 ///87 ///
...@@ -88,12 +91,6 @@ pub const Inst = struct {...@@ -88,12 +91,6 @@ pub const Inst = struct {
88 /// names.91 /// names.
89 /// Uses `tag`.92 /// Uses `tag`.
90 errors_len,93 errors_len,
91 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) containing
92 /// the base address of the table of error code names, with each
93 /// element being a null-terminated slice.
94 ///
95 /// Uses `tag`.
96 error_name_table_ref,
97 /// Represents the end of a function body or an initialization expression94 /// Represents the end of a function body or an initialization expression
98 ///95 ///
99 /// Uses `tag` (no additional data).96 /// Uses `tag` (no additional data).
...@@ -115,6 +112,12 @@ pub const Inst = struct {...@@ -115,6 +112,12 @@ pub const Inst = struct {
115 ///112 ///
116 /// Uses `tag`.113 /// Uses `tag`.
117 @"return" = 0x0F,114 @"return" = 0x0F,
115 /// Lowers to an i32_const (wasm32) or i64_const (wasm64) containing
116 /// the base address of the table of error code names, with each
117 /// element being a null-terminated slice.
118 ///
119 /// Uses `tag`.
120 error_name_table_ref,
118 /// Calls a function using `nav_index`.121 /// Calls a function using `nav_index`.
119 call_nav,122 call_nav,
120 /// Calls a function pointer by its function signature123 /// Calls a function pointer by its function signature
...@@ -612,6 +615,7 @@ pub const Inst = struct {...@@ -612,6 +615,7 @@ pub const Inst = struct {
612 intrinsic: Intrinsic,615 intrinsic: Intrinsic,
613 uav_obj: Wasm.UavsObjIndex,616 uav_obj: Wasm.UavsObjIndex,
614 uav_exe: Wasm.UavsExeIndex,617 uav_exe: Wasm.UavsExeIndex,
618 indirect_function_table_index: Wasm.IndirectFunctionTableIndex,
615619
616 comptime {620 comptime {
617 switch (builtin.mode) {621 switch (builtin.mode) {
src/link/Wasm.zig+36-14
...@@ -235,6 +235,10 @@ global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,...@@ -235,6 +235,10 @@ global_imports: std.AutoArrayHashMapUnmanaged(String, GlobalImportId) = .empty,
235tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,235tables: std.AutoArrayHashMapUnmanaged(TableImport.Resolution, void) = .empty,
236table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport.Index) = .empty,236table_imports: std.AutoArrayHashMapUnmanaged(String, TableImport.Index) = .empty,
237237
238/// All functions that have had their address taken and therefore might be
239/// called via a `call_indirect` function.
240indirect_function_table: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty,
241
238error_name_table_ref_count: u32 = 0,242error_name_table_ref_count: u32 = 0,
239243
240/// Set to true if any `GLOBAL_INDEX` relocation is encountered with244/// Set to true if any `GLOBAL_INDEX` relocation is encountered with
...@@ -260,6 +264,11 @@ error_name_bytes: std.ArrayListUnmanaged(u8) = .empty,...@@ -260,6 +264,11 @@ error_name_bytes: std.ArrayListUnmanaged(u8) = .empty,
260/// is stored. No need to serialize; trivially reconstructed.264/// is stored. No need to serialize; trivially reconstructed.
261error_name_offs: std.ArrayListUnmanaged(u32) = .empty,265error_name_offs: std.ArrayListUnmanaged(u32) = .empty,
262266
267/// Index into `Wasm.indirect_function_table`.
268pub const IndirectFunctionTableIndex = enum(u32) {
269 _,
270};
271
263pub const UavFixup = extern struct {272pub const UavFixup = extern struct {
264 uavs_exe_index: UavsExeIndex,273 uavs_exe_index: UavsExeIndex,
265 /// Index into `string_bytes`.274 /// Index into `string_bytes`.
...@@ -335,17 +344,24 @@ pub const OutputFunctionIndex = enum(u32) {...@@ -335,17 +344,24 @@ pub const OutputFunctionIndex = enum(u32) {
335 return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));344 return @enumFromInt(wasm.function_imports.entries.len + @intFromEnum(index));
336 }345 }
337346
347 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) OutputFunctionIndex {
348 const zcu = wasm.base.comp.zcu.?;
349 const ip = &zcu.intern_pool;
350 return switch (ip.indexToKey(ip_index)) {
351 .@"extern" => |ext| {
352 const name = wasm.getExistingString(ext.name.toSlice(ip)).?;
353 if (wasm.function_imports.getIndex(name)) |i| return @enumFromInt(i);
354 return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name).?);
355 },
356 else => fromResolution(wasm, .fromIpIndex(wasm, ip_index)).?,
357 };
358 }
359
338 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) OutputFunctionIndex {360 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) OutputFunctionIndex {
339 const zcu = wasm.base.comp.zcu.?;361 const zcu = wasm.base.comp.zcu.?;
340 const ip = &zcu.intern_pool;362 const ip = &zcu.intern_pool;
341 const nav = ip.getNav(nav_index);363 const nav = ip.getNav(nav_index);
342 if (nav.toExtern(ip)) |ext| {364 return fromIpIndex(wasm, nav.status.resolved.val);
343 const name = wasm.getExistingString(ext.name.toSlice(ip)).?;
344 if (wasm.function_imports.getIndex(name)) |i| return @enumFromInt(i);
345 return fromFunctionIndex(wasm, FunctionIndex.fromSymbolName(wasm, name).?);
346 } else {
347 return fromFunctionIndex(wasm, FunctionIndex.fromIpNav(wasm, nav_index).?);
348 }
349 }365 }
350366
351 pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex {367 pub fn fromTagNameType(wasm: *const Wasm, tag_type: InternPool.Index) OutputFunctionIndex {
...@@ -894,11 +910,11 @@ pub const FunctionImport = extern struct {...@@ -894,11 +910,11 @@ pub const FunctionImport = extern struct {
894 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution {910 pub fn fromIpNav(wasm: *const Wasm, nav_index: InternPool.Nav.Index) Resolution {
895 const zcu = wasm.base.comp.zcu.?;911 const zcu = wasm.base.comp.zcu.?;
896 const ip = &zcu.intern_pool;912 const ip = &zcu.intern_pool;
897 const nav = ip.getNav(nav_index);913 return fromIpIndex(wasm, ip.getNav(nav_index).status.resolved.val);
898 //log.debug("Resolution.fromIpNav {}({})", .{ nav.fqn.fmt(ip), nav_index });914 }
899 return pack(wasm, .{915
900 .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(nav.status.resolved.val).?),916 pub fn fromIpIndex(wasm: *const Wasm, ip_index: InternPool.Index) Resolution {
901 });917 return pack(wasm, .{ .zcu_func = @enumFromInt(wasm.zcu_funcs.getIndex(ip_index).?) });
902 }918 }
903919
904 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {920 pub fn isNavOrUnresolved(r: Resolution, wasm: *const Wasm) bool {
...@@ -1168,7 +1184,7 @@ pub const TableImport = extern struct {...@@ -1168,7 +1184,7 @@ pub const TableImport = extern struct {
1168 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {1184 pub fn refType(r: Resolution, wasm: *const Wasm) std.wasm.RefType {
1169 return switch (unpack(r)) {1185 return switch (unpack(r)) {
1170 .unresolved => unreachable,1186 .unresolved => unreachable,
1171 .__indirect_function_table => @panic("TODO"),1187 .__indirect_function_table => .funcref,
1172 .object_table => |i| i.ptr(wasm).flags.ref_type.to(),1188 .object_table => |i| i.ptr(wasm).flags.ref_type.to(),
1173 };1189 };
1174 }1190 }
...@@ -1176,7 +1192,11 @@ pub const TableImport = extern struct {...@@ -1176,7 +1192,11 @@ pub const TableImport = extern struct {
1176 pub fn limits(r: Resolution, wasm: *const Wasm) std.wasm.Limits {1192 pub fn limits(r: Resolution, wasm: *const Wasm) std.wasm.Limits {
1177 return switch (unpack(r)) {1193 return switch (unpack(r)) {
1178 .unresolved => unreachable,1194 .unresolved => unreachable,
1179 .__indirect_function_table => @panic("TODO"),1195 .__indirect_function_table => .{
1196 .flags = .{ .has_max = true, .is_shared = false },
1197 .min = @intCast(wasm.indirect_function_table.entries.len + 1),
1198 .max = @intCast(wasm.indirect_function_table.entries.len + 1),
1199 },
1180 .object_table => |i| i.ptr(wasm).limits(),1200 .object_table => |i| i.ptr(wasm).limits(),
1181 };1201 };
1182 }1202 }
...@@ -2370,10 +2390,12 @@ pub fn deinit(wasm: *Wasm) void {...@@ -2370,10 +2390,12 @@ pub fn deinit(wasm: *Wasm) void {
2370 wasm.global_exports.deinit(gpa);2390 wasm.global_exports.deinit(gpa);
2371 wasm.global_imports.deinit(gpa);2391 wasm.global_imports.deinit(gpa);
2372 wasm.table_imports.deinit(gpa);2392 wasm.table_imports.deinit(gpa);
2393 wasm.tables.deinit(gpa);
2373 wasm.symbol_table.deinit(gpa);2394 wasm.symbol_table.deinit(gpa);
2374 wasm.out_relocs.deinit(gpa);2395 wasm.out_relocs.deinit(gpa);
2375 wasm.uav_fixups.deinit(gpa);2396 wasm.uav_fixups.deinit(gpa);
2376 wasm.nav_fixups.deinit(gpa);2397 wasm.nav_fixups.deinit(gpa);
2398 wasm.indirect_function_table.deinit(gpa);
23772399
2378 wasm.string_bytes.deinit(gpa);2400 wasm.string_bytes.deinit(gpa);
2379 wasm.string_table.deinit(gpa);2401 wasm.string_table.deinit(gpa);
src/link/Wasm/Flush.zig+29-34
...@@ -33,8 +33,6 @@ missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,...@@ -33,8 +33,6 @@ missing_exports: std.AutoArrayHashMapUnmanaged(String, void) = .empty,
33function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,33function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = .empty,
34global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,34global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty,
3535
36indirect_function_table: std.AutoArrayHashMapUnmanaged(Wasm.OutputFunctionIndex, u32) = .empty,
37
38/// For debug purposes only.36/// For debug purposes only.
39memory_layout_finished: bool = false,37memory_layout_finished: bool = false,
4038
...@@ -42,7 +40,6 @@ pub fn clear(f: *Flush) void {...@@ -42,7 +40,6 @@ pub fn clear(f: *Flush) void {
42 f.data_segments.clearRetainingCapacity();40 f.data_segments.clearRetainingCapacity();
43 f.data_segment_groups.clearRetainingCapacity();41 f.data_segment_groups.clearRetainingCapacity();
44 f.binary_bytes.clearRetainingCapacity();42 f.binary_bytes.clearRetainingCapacity();
45 f.indirect_function_table.clearRetainingCapacity();
46 f.memory_layout_finished = false;43 f.memory_layout_finished = false;
47}44}
4845
...@@ -53,7 +50,6 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {...@@ -53,7 +50,6 @@ pub fn deinit(f: *Flush, gpa: Allocator) void {
53 f.missing_exports.deinit(gpa);50 f.missing_exports.deinit(gpa);
54 f.function_imports.deinit(gpa);51 f.function_imports.deinit(gpa);
55 f.global_imports.deinit(gpa);52 f.global_imports.deinit(gpa);
56 f.indirect_function_table.deinit(gpa);
57 f.* = undefined;53 f.* = undefined;
58}54}
5955
...@@ -72,10 +68,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -72,10 +68,6 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
72 };68 };
73 const is_obj = comp.config.output_mode == .Obj;69 const is_obj = comp.config.output_mode == .Obj;
74 const allow_undefined = is_obj or wasm.import_symbols;70 const allow_undefined = is_obj or wasm.import_symbols;
75 //const undef_byte: u8 = switch (comp.root_mod.optimize_mode) {
76 // .Debug, .ReleaseSafe => 0xaa,
77 // .ReleaseFast, .ReleaseSmall => 0x00,
78 //};
7971
80 if (comp.zcu) |zcu| {72 if (comp.zcu) |zcu| {
81 const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed!73 const ip: *const InternPool = &zcu.intern_pool; // No mutations allowed!
...@@ -215,6 +207,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -215,6 +207,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
215 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});207 wasm.functions.putAssumeCapacity(.__wasm_init_tls, {});
216 }208 }
217209
210 try wasm.tables.ensureUnusedCapacity(gpa, 1);
211
212 if (wasm.indirect_function_table.entries.len > 0) {
213 wasm.tables.putAssumeCapacity(.__indirect_function_table, {});
214 }
215
218 // Sort order:216 // Sort order:
219 // 0. Segment category (tls, data, zero)217 // 0. Segment category (tls, data, zero)
220 // 1. Segment name prefix218 // 1. Segment name prefix
...@@ -642,34 +640,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {...@@ -642,34 +640,31 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void {
642 replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(func_index));640 replaceVecSectionHeader(binary_bytes, header_offset, .start, @intFromEnum(func_index));
643 }641 }
644642
645 // element section (function table)643 // element section
646 if (f.indirect_function_table.count() > 0) {644 if (wasm.indirect_function_table.entries.len > 0) {
647 @panic("TODO");645 const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
648 //const header_offset = try reserveVecSectionHeader(gpa, binary_bytes);
649
650 //const table_loc = wasm.globals.get(wasm.preloaded_strings.__indirect_function_table).?;
651 //const table_sym = wasm.finalSymbolByLoc(table_loc);
652646
653 //const flags: u32 = if (table_sym.index == 0) 0x0 else 0x02; // passive with implicit 0-index table or set table index manually647 // indirect function table elements
654 //try leb.writeUleb128(binary_writer, flags);648 const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?);
655 //if (flags == 0x02) {649 // passive with implicit 0-index table or set table index manually
656 // try leb.writeUleb128(binary_writer, table_sym.index);650 const flags: u32 = if (table_index == 0) 0x0 else 0x02;
657 //}651 try leb.writeUleb128(binary_writer, flags);
658 //try emitInit(binary_writer, .{ .i32_const = 1 }); // We start at index 1, so unresolved function pointers are invalid652 if (flags == 0x02) {
659 //if (flags == 0x02) {653 try leb.writeUleb128(binary_writer, table_index);
660 // try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref654 }
661 //}655 // We start at index 1, so unresolved function pointers are invalid
662 //try leb.writeUleb128(binary_writer, @as(u32, @intCast(f.indirect_function_table.count())));656 try emitInit(binary_writer, .{ .i32_const = 1 });
663 //var symbol_it = f.indirect_function_table.keyIterator();657 if (flags == 0x02) {
664 //while (symbol_it.next()) |symbol_loc_ptr| {658 try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref
665 // const sym = wasm.finalSymbolByLoc(symbol_loc_ptr.*);659 }
666 // assert(sym.flags.alive);660 try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.indirect_function_table.entries.len)));
667 // assert(sym.index < wasm.functions.count() + wasm.imported_functions_count);661 for (wasm.indirect_function_table.keys()) |ip_index| {
668 // try leb.writeUleb128(binary_writer, sym.index);662 const func_index: Wasm.OutputFunctionIndex = .fromIpIndex(wasm, ip_index);
669 //}663 try leb.writeUleb128(binary_writer, @intFromEnum(func_index));
664 }
670665
671 //replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);666 replaceVecSectionHeader(binary_bytes, header_offset, .element, 1);
672 //section_index += 1;667 section_index += 1;
673 }668 }
674669
675 // When the shared-memory option is enabled, we *must* emit the 'data count' section.670 // When the shared-memory option is enabled, we *must* emit the 'data count' section.