| ... | ... | @@ -34,9 +34,28 @@ function_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.FunctionImportId) = |
| 34 | 34 | global_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.GlobalImportId) = .empty, |
| 35 | 35 | data_imports: std.AutoArrayHashMapUnmanaged(String, Wasm.DataImportId) = .empty, |
| 36 | 36 | |
| 37 | indirect_function_table: std.AutoArrayHashMapUnmanaged(Wasm.OutputFunctionIndex, void) = .empty, |
| 38 | |
| 37 | 39 | /// For debug purposes only. |
| 38 | 40 | memory_layout_finished: bool = false, |
| 39 | 41 | |
| 42 | /// Index into `indirect_function_table`. |
| 43 | const IndirectFunctionTableIndex = enum(u32) { |
| 44 | _, |
| 45 | |
| 46 | fn fromObjectFunctionHandlingWeak(wasm: *const Wasm, index: Wasm.ObjectFunctionIndex) IndirectFunctionTableIndex { |
| 47 | return fromOutputFunctionIndex(&wasm.flush_buffer, .fromObjectFunctionHandlingWeak(wasm, index)); |
| 48 | } |
| 49 | |
| 50 | fn fromSymbolName(wasm: *const Wasm, name: String) IndirectFunctionTableIndex { |
| 51 | return fromOutputFunctionIndex(&wasm.flush_buffer, .fromSymbolName(wasm, name)); |
| 52 | } |
| 53 | |
| 54 | fn fromOutputFunctionIndex(f: *const Flush, i: Wasm.OutputFunctionIndex) IndirectFunctionTableIndex { |
| 55 | return @enumFromInt(f.indirect_function_table.getIndex(i).?); |
| 56 | } |
| 57 | }; |
| 58 | |
| 40 | 59 | const DataSegmentGroup = struct { |
| 41 | 60 | first_segment: Wasm.DataSegmentId, |
| 42 | 61 | end_addr: u32, |
| ... | ... | @@ -46,6 +65,7 @@ pub fn clear(f: *Flush) void { |
| 46 | 65 | f.data_segments.clearRetainingCapacity(); |
| 47 | 66 | f.data_segment_groups.clearRetainingCapacity(); |
| 48 | 67 | f.binary_bytes.clearRetainingCapacity(); |
| 68 | f.indirect_function_table.clearRetainingCapacity(); |
| 49 | 69 | f.memory_layout_finished = false; |
| 50 | 70 | } |
| 51 | 71 | |
| ... | ... | @@ -57,6 +77,7 @@ pub fn deinit(f: *Flush, gpa: Allocator) void { |
| 57 | 77 | f.function_imports.deinit(gpa); |
| 58 | 78 | f.global_imports.deinit(gpa); |
| 59 | 79 | f.data_imports.deinit(gpa); |
| 80 | f.indirect_function_table.deinit(gpa); |
| 60 | 81 | f.* = undefined; |
| 61 | 82 | } |
| 62 | 83 | |
| ... | ... | @@ -156,6 +177,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 156 | 177 | |
| 157 | 178 | if (diags.hasErrors()) return error.LinkFailure; |
| 158 | 179 | |
| 180 | // Merge indirect function tables. |
| 181 | try f.indirect_function_table.ensureUnusedCapacity(gpa, wasm.zcu_indirect_function_set.entries.len + |
| 182 | wasm.object_indirect_function_import_set.entries.len + wasm.object_indirect_function_set.entries.len); |
| 183 | // This one goes first so the indexes can be stable for MIR lowering. |
| 184 | for (wasm.zcu_indirect_function_set.keys()) |nav_index| |
| 185 | f.indirect_function_table.putAssumeCapacity(.fromIpNav(wasm, nav_index), {}); |
| 186 | for (wasm.object_indirect_function_import_set.keys()) |symbol_name| |
| 187 | f.indirect_function_table.putAssumeCapacity(.fromSymbolName(wasm, symbol_name), {}); |
| 188 | for (wasm.object_indirect_function_set.keys()) |object_function_index| |
| 189 | f.indirect_function_table.putAssumeCapacity(.fromObjectFunction(wasm, object_function_index), {}); |
| 190 | |
| 159 | 191 | // TODO only include init functions for objects with must_link=true or |
| 160 | 192 | // which have any alive functions inside them. |
| 161 | 193 | if (wasm.object_init_funcs.items.len > 0) { |
| ... | ... | @@ -213,7 +245,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 213 | 245 | |
| 214 | 246 | try wasm.tables.ensureUnusedCapacity(gpa, 1); |
| 215 | 247 | |
| 216 | | if (wasm.indirect_function_table.entries.len > 0) { |
| 248 | if (f.indirect_function_table.entries.len > 0) { |
| 217 | 249 | wasm.tables.putAssumeCapacity(.__indirect_function_table, {}); |
| 218 | 250 | } |
| 219 | 251 | |
| ... | ... | @@ -634,7 +666,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 634 | 666 | } |
| 635 | 667 | |
| 636 | 668 | // element section |
| 637 | | if (wasm.indirect_function_table.entries.len > 0) { |
| 669 | if (f.indirect_function_table.entries.len > 0) { |
| 638 | 670 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); |
| 639 | 671 | |
| 640 | 672 | // indirect function table elements |
| ... | ... | @@ -650,9 +682,8 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 650 | 682 | if (flags == 0x02) { |
| 651 | 683 | try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref |
| 652 | 684 | } |
| 653 | | try leb.writeUleb128(binary_writer, @as(u32, @intCast(wasm.indirect_function_table.entries.len))); |
| 654 | | for (wasm.indirect_function_table.keys()) |nav_index| { |
| 655 | | const func_index: Wasm.OutputFunctionIndex = .fromIpNav(wasm, nav_index); |
| 685 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(f.indirect_function_table.entries.len))); |
| 686 | for (f.indirect_function_table.keys()) |func_index| { |
| 656 | 687 | try leb.writeUleb128(binary_writer, @intFromEnum(func_index)); |
| 657 | 688 | } |
| 658 | 689 | |
| ... | ... | @@ -1459,23 +1490,23 @@ fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.Itera |
| 1459 | 1490 | .function_index_leb => reloc_leb_function(sliced_code, .fromObjectFunctionHandlingWeak(wasm, pointee.function)), |
| 1460 | 1491 | .function_offset_i32 => @panic("TODO this value is not known yet"), |
| 1461 | 1492 | .function_offset_i64 => @panic("TODO this value is not known yet"), |
| 1462 | | .table_index_i32 => @panic("TODO indirect function table needs to support object functions too"), |
| 1463 | | .table_index_i64 => @panic("TODO indirect function table needs to support object functions too"), |
| 1464 | | .table_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"), |
| 1465 | | .table_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"), |
| 1466 | | .table_index_sleb => @panic("TODO indirect function table needs to support object functions too"), |
| 1467 | | .table_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"), |
| 1493 | .table_index_i32 => reloc_u32_table_index(sliced_code, .fromObjectFunctionHandlingWeak(wasm, pointee.function)), |
| 1494 | .table_index_i64 => reloc_u64_table_index(sliced_code, .fromObjectFunctionHandlingWeak(wasm, pointee.function)), |
| 1495 | .table_index_rel_sleb => @panic("TODO what does this reloc tag mean?"), |
| 1496 | .table_index_rel_sleb64 => @panic("TODO what does this reloc tag mean?"), |
| 1497 | .table_index_sleb => reloc_sleb_table_index(sliced_code, .fromObjectFunctionHandlingWeak(wasm, pointee.function)), |
| 1498 | .table_index_sleb64 => reloc_sleb64_table_index(sliced_code, .fromObjectFunctionHandlingWeak(wasm, pointee.function)), |
| 1468 | 1499 | |
| 1469 | 1500 | .function_import_index_i32 => reloc_u32_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), |
| 1470 | 1501 | .function_import_index_leb => reloc_leb_function(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), |
| 1471 | 1502 | .function_import_offset_i32 => @panic("TODO this value is not known yet"), |
| 1472 | 1503 | .function_import_offset_i64 => @panic("TODO this value is not known yet"), |
| 1473 | | .table_import_index_i32 => @panic("TODO indirect function table needs to support object functions too"), |
| 1474 | | .table_import_index_i64 => @panic("TODO indirect function table needs to support object functions too"), |
| 1475 | | .table_import_index_rel_sleb => @panic("TODO indirect function table needs to support object functions too"), |
| 1476 | | .table_import_index_rel_sleb64 => @panic("TODO indirect function table needs to support object functions too"), |
| 1477 | | .table_import_index_sleb => @panic("TODO indirect function table needs to support object functions too"), |
| 1478 | | .table_import_index_sleb64 => @panic("TODO indirect function table needs to support object functions too"), |
| 1504 | .table_import_index_i32 => reloc_u32_table_index(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), |
| 1505 | .table_import_index_i64 => reloc_u64_table_index(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), |
| 1506 | .table_import_index_rel_sleb => @panic("TODO what does this reloc tag mean?"), |
| 1507 | .table_import_index_rel_sleb64 => @panic("TODO what does this reloc tag mean?"), |
| 1508 | .table_import_index_sleb => reloc_sleb_table_index(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), |
| 1509 | .table_import_index_sleb64 => reloc_sleb64_table_index(sliced_code, .fromSymbolName(wasm, pointee.symbol_name)), |
| 1479 | 1510 | |
| 1480 | 1511 | .global_index_i32 => reloc_u32_global(sliced_code, .fromObjectGlobalHandlingWeak(wasm, pointee.global)), |
| 1481 | 1512 | .global_index_leb => reloc_leb_global(sliced_code, .fromObjectGlobalHandlingWeak(wasm, pointee.global)), |
| ... | ... | @@ -1517,6 +1548,22 @@ fn applyRelocs(code: []u8, code_offset: u32, relocs: Wasm.ObjectRelocation.Itera |
| 1517 | 1548 | } |
| 1518 | 1549 | } |
| 1519 | 1550 | |
| 1551 | fn reloc_u32_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1552 | mem.writeInt(u32, code[0..4], @intFromEnum(i), .little); |
| 1553 | } |
| 1554 | |
| 1555 | fn reloc_u64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1556 | mem.writeInt(u64, code[0..8], @intFromEnum(i), .little); |
| 1557 | } |
| 1558 | |
| 1559 | fn reloc_sleb_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1560 | leb.writeSignedFixed(5, code[0..5], @intFromEnum(i)); |
| 1561 | } |
| 1562 | |
| 1563 | fn reloc_sleb64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1564 | leb.writeSignedFixed(11, code[0..11], @intFromEnum(i)); |
| 1565 | } |
| 1566 | |
| 1520 | 1567 | fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { |
| 1521 | 1568 | mem.writeInt(u32, code[0..4], @intFromEnum(function), .little); |
| 1522 | 1569 | } |