| ... | @@ -16,9 +16,9 @@ const build_options = @import("build_options"); | ... | @@ -16,9 +16,9 @@ const build_options = @import("build_options"); |
| 16 | const std = @import("std"); | 16 | const std = @import("std"); |
| 17 | const Allocator = std.mem.Allocator; | 17 | const Allocator = std.mem.Allocator; |
| 18 | const mem = std.mem; | 18 | const mem = std.mem; |
| 19 | const leb = std.leb; | | |
| 20 | const log = std.log.scoped(.link); | 19 | const log = std.log.scoped(.link); |
| 21 | const assert = std.debug.assert; | 20 | const assert = std.debug.assert; |
| | 21 | const Writer = std.Io.Writer; |
| 22 | | 22 | |
| 23 | /// Ordered list of data segments that will appear in the final binary. | 23 | /// Ordered list of data segments that will appear in the final binary. |
| 24 | /// When sorted, to-be-merged segments will be made adjacent. | 24 | /// When sorted, to-be-merged segments will be made adjacent. |
| ... | @@ -557,13 +557,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -557,13 +557,12 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 557 | // Index of the data section. Used to tell relocation table where the section lives. | 557 | // Index of the data section. Used to tell relocation table where the section lives. |
| 558 | var data_section_index: ?u32 = null; | 558 | var data_section_index: ?u32 = null; |
| 559 | | 559 | |
| 560 | const binary_bytes = &f.binary_bytes; | 560 | assert(f.binary_bytes.items.len == 0); |
| 561 | assert(binary_bytes.items.len == 0); | 561 | var aw: Writer.Allocating = .fromArrayList(gpa, &f.binary_bytes); |
| | 562 | defer f.binary_bytes = aw.toArrayList(); |
| | 563 | const w = &aw.writer; |
| 562 | | 564 | |
| 563 | try binary_bytes.appendSlice(gpa, &std.wasm.magic ++ &std.wasm.version); | 565 | try w.writeAll(&std.wasm.magic ++ &std.wasm.version); |
| 564 | assert(binary_bytes.items.len == 8); | | |
| 565 | | | |
| 566 | const binary_writer = binary_bytes.writer(gpa); | | |
| 567 | | 566 | |
| 568 | // Type section. | 567 | // Type section. |
| 569 | for (f.function_imports.values()) |id| { | 568 | for (f.function_imports.values()) |id| { |
| ... | @@ -573,22 +572,18 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -573,22 +572,18 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 573 | try f.func_types.put(gpa, function.typeIndex(wasm), {}); | 572 | try f.func_types.put(gpa, function.typeIndex(wasm), {}); |
| 574 | } | 573 | } |
| 575 | if (f.func_types.entries.len != 0) { | 574 | if (f.func_types.entries.len != 0) { |
| 576 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 575 | const header_offset = try reserveVecSectionHeader(w); |
| 577 | for (f.func_types.keys()) |func_type_index| { | 576 | for (f.func_types.keys()) |func_type_index| { |
| 578 | const func_type = func_type_index.ptr(wasm); | 577 | const func_type = func_type_index.ptr(wasm); |
| 579 | try leb.writeUleb128(binary_writer, std.wasm.function_type); | 578 | try w.writeLeb128(std.wasm.function_type); |
| 580 | const params = func_type.params.slice(wasm); | 579 | const params = func_type.params.slice(wasm); |
| 581 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(params.len))); | 580 | try w.writeLeb128(params.len); |
| 582 | for (params) |param_ty| { | 581 | for (params) |param_ty| try w.writeLeb128(@intFromEnum(param_ty)); |
| 583 | try leb.writeUleb128(binary_writer, @intFromEnum(param_ty)); | | |
| 584 | } | | |
| 585 | const returns = func_type.returns.slice(wasm); | 582 | const returns = func_type.returns.slice(wasm); |
| 586 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(returns.len))); | 583 | try w.writeLeb128(returns.len); |
| 587 | for (returns) |ret_ty| { | 584 | for (returns) |ret_ty| try w.writeLeb128(@intFromEnum(ret_ty)); |
| 588 | try leb.writeUleb128(binary_writer, @intFromEnum(ret_ty)); | | |
| 589 | } | | |
| 590 | } | 585 | } |
| 591 | replaceVecSectionHeader(binary_bytes, header_offset, .type, @intCast(f.func_types.entries.len)); | 586 | replaceVecSectionHeader(&aw, header_offset, .type, @intCast(f.func_types.entries.len)); |
| 592 | section_index += 1; | 587 | section_index += 1; |
| 593 | } | 588 | } |
| 594 | | 589 | |
| ... | @@ -601,42 +596,42 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -601,42 +596,42 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 601 | // Import section | 596 | // Import section |
| 602 | { | 597 | { |
| 603 | var total_imports: usize = 0; | 598 | var total_imports: usize = 0; |
| 604 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 599 | const header_offset = try reserveVecSectionHeader(w); |
| 605 | | 600 | |
| 606 | for (f.function_imports.values()) |id| { | 601 | for (f.function_imports.values()) |id| { |
| 607 | const module_name = id.moduleName(wasm).slice(wasm).?; | 602 | const module_name = id.moduleName(wasm).slice(wasm).?; |
| 608 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); | 603 | try w.writeLeb128(module_name.len); |
| 609 | try binary_writer.writeAll(module_name); | 604 | try w.writeAll(module_name); |
| 610 | | 605 | |
| 611 | const name = id.importName(wasm).slice(wasm); | 606 | const name = id.importName(wasm).slice(wasm); |
| 612 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 607 | try w.writeLeb128(name.len); |
| 613 | try binary_writer.writeAll(name); | 608 | try w.writeAll(name); |
| 614 | | 609 | |
| 615 | try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); | 610 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); |
| 616 | const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f); | 611 | const type_index: FuncTypeIndex = .fromTypeIndex(id.functionType(wasm), f); |
| 617 | try leb.writeUleb128(binary_writer, @intFromEnum(type_index)); | 612 | try w.writeLeb128(@intFromEnum(type_index)); |
| 618 | } | 613 | } |
| 619 | total_imports += f.function_imports.entries.len; | 614 | total_imports += f.function_imports.entries.len; |
| 620 | | 615 | |
| 621 | for (wasm.table_imports.values()) |id| { | 616 | for (wasm.table_imports.values()) |id| { |
| 622 | const table_import = id.value(wasm); | 617 | const table_import = id.value(wasm); |
| 623 | const module_name = table_import.module_name.slice(wasm); | 618 | const module_name = table_import.module_name.slice(wasm); |
| 624 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); | 619 | try w.writeLeb128(module_name.len); |
| 625 | try binary_writer.writeAll(module_name); | 620 | try w.writeAll(module_name); |
| 626 | | 621 | |
| 627 | const name = table_import.name.slice(wasm); | 622 | const name = table_import.name.slice(wasm); |
| 628 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 623 | try w.writeLeb128(name.len); |
| 629 | try binary_writer.writeAll(name); | 624 | try w.writeAll(name); |
| 630 | | 625 | |
| 631 | try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); | 626 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); |
| 632 | try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); | 627 | try w.writeLeb128(@intFromEnum(@as(std.wasm.RefType, table_import.flags.ref_type.to()))); |
| 633 | try emitLimits(gpa, binary_bytes, table_import.limits()); | 628 | try emitLimits(w, table_import.limits()); |
| 634 | } | 629 | } |
| 635 | total_imports += wasm.table_imports.entries.len; | 630 | total_imports += wasm.table_imports.entries.len; |
| 636 | | 631 | |
| 637 | if (import_memory) { | 632 | if (import_memory) { |
| 638 | const name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory; | 633 | const name = if (is_obj) wasm.preloaded_strings.__linear_memory else wasm.preloaded_strings.memory; |
| 639 | try emitMemoryImport(wasm, binary_bytes, name, &.{ | 634 | try emitMemoryImport(wasm, w, name, &.{ |
| 640 | // TODO the import_memory option needs to specify from which module | 635 | // TODO the import_memory option needs to specify from which module |
| 641 | .module_name = wasm.object_host_name.unwrap().?, | 636 | .module_name = wasm.object_host_name.unwrap().?, |
| 642 | .limits_min = wasm.memories.limits.min, | 637 | .limits_min = wasm.memories.limits.min, |
| ... | @@ -650,215 +645,209 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -650,215 +645,209 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 650 | | 645 | |
| 651 | for (f.global_imports.values()) |id| { | 646 | for (f.global_imports.values()) |id| { |
| 652 | const module_name = id.moduleName(wasm).slice(wasm).?; | 647 | const module_name = id.moduleName(wasm).slice(wasm).?; |
| 653 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(module_name.len))); | 648 | try w.writeLeb128(module_name.len); |
| 654 | try binary_writer.writeAll(module_name); | 649 | try w.writeAll(module_name); |
| 655 | | 650 | |
| 656 | const name = id.importName(wasm).slice(wasm); | 651 | const name = id.importName(wasm).slice(wasm); |
| 657 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 652 | try w.writeLeb128(name.len); |
| 658 | try binary_writer.writeAll(name); | 653 | try w.writeAll(name); |
| 659 | | 654 | |
| 660 | try binary_writer.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); | 655 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); |
| 661 | const global_type = id.globalType(wasm); | 656 | const global_type = id.globalType(wasm); |
| 662 | try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.Valtype, global_type.valtype))); | 657 | try w.writeLeb128(@intFromEnum(global_type.valtype)); |
| 663 | try binary_writer.writeByte(@intFromBool(global_type.mutable)); | 658 | try w.writeByte(@intFromBool(global_type.mutable)); |
| 664 | } | 659 | } |
| 665 | total_imports += f.global_imports.entries.len; | 660 | total_imports += f.global_imports.entries.len; |
| 666 | | 661 | |
| 667 | if (total_imports > 0) { | 662 | if (total_imports > 0) { |
| 668 | replaceVecSectionHeader(binary_bytes, header_offset, .import, @intCast(total_imports)); | 663 | replaceVecSectionHeader(&aw, header_offset, .import, @intCast(total_imports)); |
| 669 | section_index += 1; | 664 | section_index += 1; |
| 670 | } else { | 665 | } else { |
| 671 | binary_bytes.shrinkRetainingCapacity(header_offset); | 666 | aw.shrinkRetainingCapacity(header_offset); |
| 672 | } | 667 | } |
| 673 | } | 668 | } |
| 674 | | 669 | |
| 675 | // Function section | 670 | // Function section |
| 676 | if (wasm.functions.count() != 0) { | 671 | if (wasm.functions.count() != 0) { |
| 677 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 672 | const header_offset = try reserveVecSectionHeader(w); |
| 678 | for (wasm.functions.keys()) |function| { | 673 | for (wasm.functions.keys()) |function| { |
| 679 | const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f); | 674 | const index: FuncTypeIndex = .fromTypeIndex(function.typeIndex(wasm), f); |
| 680 | try leb.writeUleb128(binary_writer, @intFromEnum(index)); | 675 | try w.writeLeb128(@intFromEnum(index)); |
| 681 | } | 676 | } |
| 682 | | 677 | |
| 683 | replaceVecSectionHeader(binary_bytes, header_offset, .function, @intCast(wasm.functions.count())); | 678 | replaceVecSectionHeader(&aw, header_offset, .function, @intCast(wasm.functions.count())); |
| 684 | section_index += 1; | 679 | section_index += 1; |
| 685 | } | 680 | } |
| 686 | | 681 | |
| 687 | // Table section | 682 | // Table section |
| 688 | if (wasm.tables.entries.len > 0) { | 683 | if (wasm.tables.entries.len > 0) { |
| 689 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 684 | const header_offset = try reserveVecSectionHeader(w); |
| 690 | | 685 | |
| 691 | for (wasm.tables.keys()) |table| { | 686 | for (wasm.tables.keys()) |table| { |
| 692 | try leb.writeUleb128(binary_writer, @intFromEnum(@as(std.wasm.RefType, table.refType(wasm)))); | 687 | try w.writeLeb128(@intFromEnum(table.refType(wasm))); |
| 693 | try emitLimits(gpa, binary_bytes, table.limits(wasm)); | 688 | try emitLimits(w, table.limits(wasm)); |
| 694 | } | 689 | } |
| 695 | | 690 | |
| 696 | replaceVecSectionHeader(binary_bytes, header_offset, .table, @intCast(wasm.tables.entries.len)); | 691 | replaceVecSectionHeader(&aw, header_offset, .table, @intCast(wasm.tables.entries.len)); |
| 697 | section_index += 1; | 692 | section_index += 1; |
| 698 | } | 693 | } |
| 699 | | 694 | |
| 700 | // Memory section. wasm currently only supports 1 linear memory segment. | 695 | // Memory section. wasm currently only supports 1 linear memory segment. |
| 701 | if (!import_memory) { | 696 | if (!import_memory) { |
| 702 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 697 | const header_offset = try reserveVecSectionHeader(w); |
| 703 | try emitLimits(gpa, binary_bytes, wasm.memories.limits); | 698 | try emitLimits(w, wasm.memories.limits); |
| 704 | replaceVecSectionHeader(binary_bytes, header_offset, .memory, 1); | 699 | replaceVecSectionHeader(&aw, header_offset, .memory, 1); |
| 705 | section_index += 1; | 700 | section_index += 1; |
| 706 | } | 701 | } |
| 707 | | 702 | |
| 708 | // Global section. | 703 | // Global section. |
| 709 | const globals_len: u32 = @intCast(wasm.globals.entries.len); | 704 | const globals_len: u32 = @intCast(wasm.globals.entries.len); |
| 710 | if (globals_len > 0) { | 705 | if (globals_len > 0) { |
| 711 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 706 | const header_offset = try reserveVecSectionHeader(w); |
| 712 | | 707 | |
| 713 | for (wasm.globals.keys()) |global_resolution| { | 708 | for (wasm.globals.keys()) |global_resolution| { |
| 714 | switch (global_resolution.unpack(wasm)) { | 709 | switch (global_resolution.unpack(wasm)) { |
| 715 | .unresolved => unreachable, | 710 | .unresolved => unreachable, |
| 716 | .__heap_base => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_base), | 711 | .__heap_base => try appendGlobal(w, false, virtual_addrs.heap_base), |
| 717 | .__heap_end => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.heap_end), | 712 | .__heap_end => try appendGlobal(w, false, virtual_addrs.heap_end), |
| 718 | .__stack_pointer => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.stack_pointer), | 713 | .__stack_pointer => try appendGlobal(w, true, virtual_addrs.stack_pointer), |
| 719 | .__tls_align => try appendGlobal(gpa, binary_bytes, 0, @intCast(virtual_addrs.tls_align.toByteUnits().?)), | 714 | .__tls_align => try appendGlobal(w, false, @intCast(virtual_addrs.tls_align.toByteUnits().?)), |
| 720 | .__tls_base => try appendGlobal(gpa, binary_bytes, 1, virtual_addrs.tls_base.?), | 715 | .__tls_base => try appendGlobal(w, true, virtual_addrs.tls_base.?), |
| 721 | .__tls_size => try appendGlobal(gpa, binary_bytes, 0, virtual_addrs.tls_size.?), | 716 | .__tls_size => try appendGlobal(w, false, virtual_addrs.tls_size.?), |
| 722 | .object_global => |i| { | 717 | .object_global => |i| { |
| 723 | const global = i.ptr(wasm); | 718 | const global = i.ptr(wasm); |
| 724 | try binary_bytes.appendSlice(gpa, &.{ | 719 | try w.writeAll(&.{ |
| 725 | @intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())), | 720 | @intFromEnum(@as(std.wasm.Valtype, global.flags.global_type.valtype.to())), |
| 726 | @intFromBool(global.flags.global_type.mutable), | 721 | @intFromBool(global.flags.global_type.mutable), |
| 727 | }); | 722 | }); |
| 728 | try emitExpr(wasm, binary_bytes, global.expr); | 723 | try emitExpr(wasm, w, global.expr); |
| 729 | }, | 724 | }, |
| 730 | .nav_exe => unreachable, // Zig source code currently cannot represent this. | 725 | .nav_exe => unreachable, // Zig source code currently cannot represent this. |
| 731 | .nav_obj => unreachable, // Zig source code currently cannot represent this. | 726 | .nav_obj => unreachable, // Zig source code currently cannot represent this. |
| 732 | } | 727 | } |
| 733 | } | 728 | } |
| 734 | | 729 | |
| 735 | replaceVecSectionHeader(binary_bytes, header_offset, .global, globals_len); | 730 | replaceVecSectionHeader(&aw, header_offset, .global, globals_len); |
| 736 | section_index += 1; | 731 | section_index += 1; |
| 737 | } | 732 | } |
| 738 | | 733 | |
| 739 | // Export section | 734 | // Export section |
| 740 | { | 735 | { |
| 741 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 736 | const header_offset = try reserveVecSectionHeader(w); |
| 742 | var exports_len: usize = 0; | 737 | var exports_len: usize = 0; |
| 743 | | 738 | |
| 744 | for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| { | 739 | for (wasm.function_exports.keys(), wasm.function_exports.values()) |exp_name, function_index| { |
| 745 | const name = exp_name.slice(wasm); | 740 | const name = exp_name.slice(wasm); |
| 746 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 741 | try w.writeLeb128(name.len); |
| 747 | try binary_bytes.appendSlice(gpa, name); | 742 | try w.writeAll(name); |
| 748 | try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.function)); | 743 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.function)); |
| 749 | const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index); | 744 | const func_index = Wasm.OutputFunctionIndex.fromFunctionIndex(wasm, function_index); |
| 750 | try leb.writeUleb128(binary_writer, @intFromEnum(func_index)); | 745 | try w.writeLeb128(@intFromEnum(func_index)); |
| 751 | } | 746 | } |
| 752 | exports_len += wasm.function_exports.entries.len; | 747 | exports_len += wasm.function_exports.entries.len; |
| 753 | | 748 | |
| 754 | if (wasm.export_table and f.indirect_function_table.entries.len > 0) { | 749 | if (wasm.export_table and f.indirect_function_table.entries.len > 0) { |
| 755 | const name = "__indirect_function_table"; | 750 | const name = "__indirect_function_table"; |
| 756 | const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); | 751 | const index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); |
| 757 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 752 | try w.writeLeb128(name.len); |
| 758 | try binary_bytes.appendSlice(gpa, name); | 753 | try w.writeAll(name); |
| 759 | try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.table)); | 754 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.table)); |
| 760 | try leb.writeUleb128(binary_writer, index); | 755 | try w.writeLeb128(index); |
| 761 | exports_len += 1; | 756 | exports_len += 1; |
| 762 | } | 757 | } |
| 763 | | 758 | |
| 764 | if (export_memory) { | 759 | if (export_memory) { |
| 765 | const name = "memory"; | 760 | const name = "memory"; |
| 766 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 761 | try w.writeLeb128(name.len); |
| 767 | try binary_bytes.appendSlice(gpa, name); | 762 | try w.writeAll(name); |
| 768 | try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory)); | 763 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); |
| 769 | try leb.writeUleb128(binary_writer, @as(u32, 0)); | 764 | try w.writeUleb128(0); |
| 770 | exports_len += 1; | 765 | exports_len += 1; |
| 771 | } | 766 | } |
| 772 | | 767 | |
| 773 | for (wasm.global_exports.items) |exp| { | 768 | for (wasm.global_exports.items) |exp| { |
| 774 | const name = exp.name.slice(wasm); | 769 | const name = exp.name.slice(wasm); |
| 775 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(name.len))); | 770 | try w.writeLeb128(name.len); |
| 776 | try binary_bytes.appendSlice(gpa, name); | 771 | try w.writeAll(name); |
| 777 | try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.global)); | 772 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.global)); |
| 778 | try leb.writeUleb128(binary_writer, @intFromEnum(exp.global_index)); | 773 | try w.writeLeb128(@intFromEnum(exp.global_index)); |
| 779 | } | 774 | } |
| 780 | exports_len += wasm.global_exports.items.len; | 775 | exports_len += wasm.global_exports.items.len; |
| 781 | | 776 | |
| 782 | if (exports_len > 0) { | 777 | if (exports_len > 0) { |
| 783 | replaceVecSectionHeader(binary_bytes, header_offset, .@"export", @intCast(exports_len)); | 778 | replaceVecSectionHeader(&aw, header_offset, .@"export", @intCast(exports_len)); |
| 784 | section_index += 1; | 779 | section_index += 1; |
| 785 | } else { | 780 | } else { |
| 786 | binary_bytes.shrinkRetainingCapacity(header_offset); | 781 | aw.shrinkRetainingCapacity(header_offset); |
| 787 | } | 782 | } |
| 788 | } | 783 | } |
| 789 | | 784 | |
| 790 | // start section | 785 | // start section |
| 791 | if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| { | 786 | if (wasm.functions.getIndex(.__wasm_init_memory)) |func_index| { |
| 792 | try emitStartSection(gpa, binary_bytes, .fromFunctionIndex(wasm, @enumFromInt(func_index))); | 787 | try emitStartSection(&aw, .fromFunctionIndex(wasm, @enumFromInt(func_index))); |
| 793 | } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| { | 788 | } else if (Wasm.OutputFunctionIndex.fromResolution(wasm, wasm.entry_resolution)) |func_index| { |
| 794 | try emitStartSection(gpa, binary_bytes, func_index); | 789 | try emitStartSection(&aw, func_index); |
| 795 | } | 790 | } |
| 796 | | 791 | |
| 797 | // element section | 792 | // element section |
| 798 | if (f.indirect_function_table.entries.len > 0) { | 793 | if (f.indirect_function_table.entries.len > 0) { |
| 799 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 794 | const header_offset = try reserveVecSectionHeader(w); |
| 800 | | 795 | |
| 801 | // indirect function table elements | 796 | // indirect function table elements |
| 802 | const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); | 797 | const table_index: u32 = @intCast(wasm.tables.getIndex(.__indirect_function_table).?); |
| 803 | // passive with implicit 0-index table or set table index manually | 798 | // passive with implicit 0-index table or set table index manually |
| 804 | const flags: u32 = if (table_index == 0) 0x0 else 0x02; | 799 | const flags: u32 = if (table_index == 0) 0x0 else 0x02; |
| 805 | try leb.writeUleb128(binary_writer, flags); | 800 | try w.writeLeb128(flags); |
| 806 | if (flags == 0x02) { | 801 | if (flags == 0x02) try w.writeLeb128(table_index); |
| 807 | try leb.writeUleb128(binary_writer, table_index); | | |
| 808 | } | | |
| 809 | // We start at index 1, so unresolved function pointers are invalid | 802 | // We start at index 1, so unresolved function pointers are invalid |
| 810 | try emitInit(binary_writer, .{ .i32_const = 1 }); | 803 | try emitInit(w, .{ .i32_const = 1 }); |
| 811 | if (flags == 0x02) { | 804 | if (flags == 0x02) try w.writeUleb128(0); // represents funcref |
| 812 | try leb.writeUleb128(binary_writer, @as(u8, 0)); // represents funcref | 805 | try w.writeLeb128(f.indirect_function_table.entries.len); |
| 813 | } | 806 | for (f.indirect_function_table.keys()) |func_index| try w.writeLeb128(@intFromEnum(func_index)); |
| 814 | try leb.writeUleb128(binary_writer, @as(u32, @intCast(f.indirect_function_table.entries.len))); | | |
| 815 | for (f.indirect_function_table.keys()) |func_index| { | | |
| 816 | try leb.writeUleb128(binary_writer, @intFromEnum(func_index)); | | |
| 817 | } | | |
| 818 | | 807 | |
| 819 | replaceVecSectionHeader(binary_bytes, header_offset, .element, 1); | 808 | replaceVecSectionHeader(&aw, header_offset, .element, 1); |
| 820 | section_index += 1; | 809 | section_index += 1; |
| 821 | } | 810 | } |
| 822 | | 811 | |
| 823 | // When the shared-memory option is enabled, we *must* emit the 'data count' section. | 812 | // When the shared-memory option is enabled, we *must* emit the 'data count' section. |
| 824 | if (f.data_segment_groups.items.len > 0) { | 813 | if (f.data_segment_groups.items.len > 0) { |
| 825 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 814 | const header_offset = try reserveVecSectionHeader(w); |
| 826 | replaceVecSectionHeader(binary_bytes, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); | 815 | replaceVecSectionHeader(&aw, header_offset, .data_count, @intCast(f.data_segment_groups.items.len)); |
| 827 | } | 816 | } |
| 828 | | 817 | |
| 829 | // Code section. | 818 | // Code section. |
| 830 | if (wasm.functions.count() != 0) { | 819 | if (wasm.functions.count() != 0) { |
| 831 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 820 | const header_offset = try reserveVecSectionHeader(w); |
| 832 | | 821 | |
| 833 | for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) { | 822 | for (wasm.functions.keys()) |resolution| switch (resolution.unpack(wasm)) { |
| 834 | .unresolved => unreachable, | 823 | .unresolved => unreachable, |
| 835 | .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"), | 824 | .__wasm_apply_global_tls_relocs => @panic("TODO lower __wasm_apply_global_tls_relocs"), |
| 836 | .__wasm_call_ctors => { | 825 | .__wasm_call_ctors => { |
| 837 | const code_start = try reserveSize(gpa, binary_bytes); | 826 | const code_start = try reserveSizeHeader(w); |
| 838 | defer replaceSize(binary_bytes, code_start); | 827 | defer replaceSizeHeader(&aw, code_start); |
| 839 | try emitCallCtorsFunction(wasm, binary_bytes); | 828 | try emitCallCtorsFunction(wasm, w); |
| 840 | }, | 829 | }, |
| 841 | .__wasm_init_memory => { | 830 | .__wasm_init_memory => { |
| 842 | const code_start = try reserveSize(gpa, binary_bytes); | 831 | const code_start = try reserveSizeHeader(w); |
| 843 | defer replaceSize(binary_bytes, code_start); | 832 | defer replaceSizeHeader(&aw, code_start); |
| 844 | try emitInitMemoryFunction(wasm, binary_bytes, &virtual_addrs); | 833 | try emitInitMemoryFunction(wasm, w, &virtual_addrs); |
| 845 | }, | 834 | }, |
| 846 | .__wasm_init_tls => { | 835 | .__wasm_init_tls => { |
| 847 | const code_start = try reserveSize(gpa, binary_bytes); | 836 | const code_start = try reserveSizeHeader(w); |
| 848 | defer replaceSize(binary_bytes, code_start); | 837 | defer replaceSizeHeader(&aw, code_start); |
| 849 | try emitInitTlsFunction(wasm, binary_bytes); | 838 | try emitInitTlsFunction(wasm, w); |
| 850 | }, | 839 | }, |
| 851 | .object_function => |i| { | 840 | .object_function => |i| { |
| 852 | const ptr = i.ptr(wasm); | 841 | const ptr = i.ptr(wasm); |
| 853 | const code = ptr.code.slice(wasm); | 842 | const code = ptr.code.slice(wasm); |
| 854 | try leb.writeUleb128(binary_writer, code.len); | 843 | try w.writeLeb128(code.len); |
| 855 | const code_start = binary_bytes.items.len; | 844 | const code_start = w.end; |
| 856 | try binary_bytes.appendSlice(gpa, code); | 845 | try w.writeAll(code); |
| 857 | if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); | 846 | if (!is_obj) applyRelocs(aw.getWritten()[code_start..], ptr.offset, ptr.relocations(wasm), wasm); |
| 858 | }, | 847 | }, |
| 859 | .zcu_func => |i| { | 848 | .zcu_func => |i| { |
| 860 | const code_start = try reserveSize(gpa, binary_bytes); | 849 | const code_start = try reserveSizeHeader(w); |
| 861 | defer replaceSize(binary_bytes, code_start); | 850 | defer replaceSizeHeader(&aw, code_start); |
| 862 | | 851 | |
| 863 | log.debug("lowering function code for '{s}'", .{resolution.name(wasm).?}); | 852 | log.debug("lowering function code for '{s}'", .{resolution.name(wasm).?}); |
| 864 | | 853 | |
| ... | @@ -867,7 +856,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -867,7 +856,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 867 | const ip_index = i.key(wasm).*; | 856 | const ip_index = i.key(wasm).*; |
| 868 | switch (ip.indexToKey(ip_index)) { | 857 | switch (ip.indexToKey(ip_index)) { |
| 869 | .enum_type => { | 858 | .enum_type => { |
| 870 | try emitTagNameFunction(wasm, binary_bytes, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); | 859 | try emitTagNameFunction(wasm, w, f.data_segments.get(.__zig_tag_name_table).?, i.value(wasm).tag_name.table_index, ip_index); |
| 871 | }, | 860 | }, |
| 872 | else => { | 861 | else => { |
| 873 | const func = i.value(wasm).function; | 862 | const func = i.value(wasm).function; |
| ... | @@ -882,13 +871,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -882,13 +871,13 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 882 | .func_tys = undefined, | 871 | .func_tys = undefined, |
| 883 | .error_name_table_ref_count = undefined, | 872 | .error_name_table_ref_count = undefined, |
| 884 | }; | 873 | }; |
| 885 | try mir.lower(wasm, binary_bytes); | 874 | try mir.lower(wasm, w); |
| 886 | }, | 875 | }, |
| 887 | } | 876 | } |
| 888 | }, | 877 | }, |
| 889 | }; | 878 | }; |
| 890 | | 879 | |
| 891 | replaceVecSectionHeader(binary_bytes, header_offset, .code, @intCast(wasm.functions.entries.len)); | 880 | replaceVecSectionHeader(&aw, header_offset, .code, @intCast(wasm.functions.entries.len)); |
| 892 | code_section_index = section_index; | 881 | code_section_index = section_index; |
| 893 | section_index += 1; | 882 | section_index += 1; |
| 894 | } | 883 | } |
| ... | @@ -924,7 +913,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -924,7 +913,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 924 | | 913 | |
| 925 | // Data section. | 914 | // Data section. |
| 926 | if (f.data_segment_groups.items.len != 0) { | 915 | if (f.data_segment_groups.items.len != 0) { |
| 927 | const header_offset = try reserveVecSectionHeader(gpa, binary_bytes); | 916 | const header_offset = try reserveVecSectionHeader(w); |
| 928 | | 917 | |
| 929 | var group_index: u32 = 0; | 918 | var group_index: u32 = 0; |
| 930 | var segment_offset: u32 = 0; | 919 | var segment_offset: u32 = 0; |
| ... | @@ -932,7 +921,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -932,7 +921,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 932 | var group_end_addr = f.data_segment_groups.items[group_index].end_addr; | 921 | var group_end_addr = f.data_segment_groups.items[group_index].end_addr; |
| 933 | for (segment_ids, segment_vaddrs) |segment_id, segment_vaddr| { | 922 | for (segment_ids, segment_vaddrs) |segment_id, segment_vaddr| { |
| 934 | if (segment_vaddr >= group_end_addr) { | 923 | if (segment_vaddr >= group_end_addr) { |
| 935 | try binary_bytes.appendNTimes(gpa, 0, group_end_addr - group_start_addr - segment_offset); | 924 | try w.splatByteAll(0, group_end_addr - group_start_addr - segment_offset); |
| 936 | group_index += 1; | 925 | group_index += 1; |
| 937 | if (group_index >= f.data_segment_groups.items.len) { | 926 | if (group_index >= f.data_segment_groups.items.len) { |
| 938 | // All remaining segments are zero. | 927 | // All remaining segments are zero. |
| ... | @@ -946,12 +935,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -946,12 +935,10 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 946 | const group_size = group_end_addr - group_start_addr; | 935 | const group_size = group_end_addr - group_start_addr; |
| 947 | log.debug("emit data section group, {d} bytes", .{group_size}); | 936 | log.debug("emit data section group, {d} bytes", .{group_size}); |
| 948 | const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active; | 937 | const flags: Object.DataSegmentFlags = if (segment_id.isPassive(wasm)) .passive else .active; |
| 949 | try leb.writeUleb128(binary_writer, @intFromEnum(flags)); | 938 | try w.writeLeb128(@intFromEnum(flags)); |
| 950 | // Passive segments are initialized at runtime. | 939 | // Passive segments are initialized at runtime. |
| 951 | if (flags != .passive) { | 940 | if (flags != .passive) try emitInit(w, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) }); |
| 952 | try emitInit(binary_writer, .{ .i32_const = @as(i32, @bitCast(group_start_addr)) }); | 941 | try w.writeLeb128(group_size); |
| 953 | } | | |
| 954 | try leb.writeUleb128(binary_writer, group_size); | | |
| 955 | } | 942 | } |
| 956 | if (segment_id.isEmpty(wasm)) { | 943 | if (segment_id.isEmpty(wasm)) { |
| 957 | // It counted for virtual memory but it does not go into the binary. | 944 | // It counted for virtual memory but it does not go into the binary. |
| ... | @@ -960,62 +947,62 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -960,62 +947,62 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 960 | | 947 | |
| 961 | // Padding for alignment. | 948 | // Padding for alignment. |
| 962 | const needed_offset = segment_vaddr - group_start_addr; | 949 | const needed_offset = segment_vaddr - group_start_addr; |
| 963 | try binary_bytes.appendNTimes(gpa, 0, needed_offset - segment_offset); | 950 | try w.splatByteAll(0, needed_offset - segment_offset); |
| 964 | segment_offset = needed_offset; | 951 | segment_offset = needed_offset; |
| 965 | | 952 | |
| 966 | const code_start = binary_bytes.items.len; | 953 | const code_start = w.end; |
| 967 | append: { | 954 | append: { |
| 968 | const code = switch (segment_id.unpack(wasm)) { | 955 | const code = switch (segment_id.unpack(wasm)) { |
| 969 | .__heap_base => { | 956 | .__heap_base => { |
| 970 | mem.writeInt(u32, try binary_bytes.addManyAsArray(gpa, 4), virtual_addrs.heap_base, .little); | 957 | try w.writeInt(u32, virtual_addrs.heap_base, .little); |
| 971 | break :append; | 958 | break :append; |
| 972 | }, | 959 | }, |
| 973 | .__heap_end => { | 960 | .__heap_end => { |
| 974 | mem.writeInt(u32, try binary_bytes.addManyAsArray(gpa, 4), virtual_addrs.heap_end, .little); | 961 | try w.writeInt(u32, virtual_addrs.heap_end, .little); |
| 975 | break :append; | 962 | break :append; |
| 976 | }, | 963 | }, |
| 977 | .__zig_error_names => { | 964 | .__zig_error_names => { |
| 978 | try binary_bytes.appendSlice(gpa, wasm.error_name_bytes.items); | 965 | try w.writeAll(wasm.error_name_bytes.items); |
| 979 | break :append; | 966 | break :append; |
| 980 | }, | 967 | }, |
| 981 | .__zig_error_name_table => { | 968 | .__zig_error_name_table => { |
| 982 | if (is_obj) @panic("TODO error name table reloc"); | 969 | if (is_obj) @panic("TODO error name table reloc"); |
| 983 | const base = f.data_segments.get(.__zig_error_names).?; | 970 | const base = f.data_segments.get(.__zig_error_names).?; |
| 984 | if (!is64) { | 971 | if (!is64) { |
| 985 | try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); | 972 | try emitTagNameTable(w, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u32); |
| 986 | } else { | 973 | } else { |
| 987 | try emitTagNameTable(gpa, binary_bytes, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); | 974 | try emitTagNameTable(w, wasm.error_name_offs.items, wasm.error_name_bytes.items, base, u64); |
| 988 | } | 975 | } |
| 989 | break :append; | 976 | break :append; |
| 990 | }, | 977 | }, |
| 991 | .__zig_tag_names => { | 978 | .__zig_tag_names => { |
| 992 | try binary_bytes.appendSlice(gpa, wasm.tag_name_bytes.items); | 979 | try w.writeAll(wasm.tag_name_bytes.items); |
| 993 | break :append; | 980 | break :append; |
| 994 | }, | 981 | }, |
| 995 | .__zig_tag_name_table => { | 982 | .__zig_tag_name_table => { |
| 996 | if (is_obj) @panic("TODO tag name table reloc"); | 983 | if (is_obj) @panic("TODO tag name table reloc"); |
| 997 | const base = f.data_segments.get(.__zig_tag_names).?; | 984 | const base = f.data_segments.get(.__zig_tag_names).?; |
| 998 | if (!is64) { | 985 | if (!is64) { |
| 999 | try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); | 986 | try emitTagNameTable(w, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u32); |
| 1000 | } else { | 987 | } else { |
| 1001 | try emitTagNameTable(gpa, binary_bytes, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); | 988 | try emitTagNameTable(w, wasm.tag_name_offs.items, wasm.tag_name_bytes.items, base, u64); |
| 1002 | } | 989 | } |
| 1003 | break :append; | 990 | break :append; |
| 1004 | }, | 991 | }, |
| 1005 | .object => |i| { | 992 | .object => |i| { |
| 1006 | const ptr = i.ptr(wasm); | 993 | const ptr = i.ptr(wasm); |
| 1007 | try binary_bytes.appendSlice(gpa, ptr.payload.slice(wasm)); | 994 | try w.writeAll(ptr.payload.slice(wasm)); |
| 1008 | if (!is_obj) applyRelocs(binary_bytes.items[code_start..], ptr.offset, ptr.relocations(wasm), wasm); | 995 | if (!is_obj) applyRelocs(aw.getWritten()[code_start..], ptr.offset, ptr.relocations(wasm), wasm); |
| 1009 | break :append; | 996 | break :append; |
| 1010 | }, | 997 | }, |
| 1011 | inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code, | 998 | inline .uav_exe, .uav_obj, .nav_exe, .nav_obj => |i| i.value(wasm).code, |
| 1012 | }; | 999 | }; |
| 1013 | try binary_bytes.appendSlice(gpa, code.slice(wasm)); | 1000 | try w.writeAll(code.slice(wasm)); |
| 1014 | } | 1001 | } |
| 1015 | segment_offset += @intCast(binary_bytes.items.len - code_start); | 1002 | segment_offset += @intCast(w.end - code_start); |
| 1016 | } | 1003 | } |
| 1017 | | 1004 | |
| 1018 | replaceVecSectionHeader(binary_bytes, header_offset, .data, @intCast(f.data_segment_groups.items.len)); | 1005 | replaceVecSectionHeader(&aw, header_offset, .data, @intCast(f.data_segment_groups.items.len)); |
| 1019 | data_section_index = section_index; | 1006 | data_section_index = section_index; |
| 1020 | section_index += 1; | 1007 | section_index += 1; |
| 1021 | } | 1008 | } |
| ... | @@ -1023,7 +1010,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -1023,7 +1010,7 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 1023 | if (is_obj) { | 1010 | if (is_obj) { |
| 1024 | @panic("TODO emit link section for object file and emit modified relocations"); | 1011 | @panic("TODO emit link section for object file and emit modified relocations"); |
| 1025 | } else if (comp.config.debug_format != .strip) { | 1012 | } else if (comp.config.debug_format != .strip) { |
| 1026 | try emitNameSection(wasm, f.data_segment_groups.items, binary_bytes); | 1013 | try emitNameSection(wasm, &aw, f.data_segment_groups.items); |
| 1027 | } | 1014 | } |
| 1028 | | 1015 | |
| 1029 | if (comp.config.debug_format != .strip) { | 1016 | if (comp.config.debug_format != .strip) { |
| ... | @@ -1033,17 +1020,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -1033,17 +1020,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 1033 | .none => {}, | 1020 | .none => {}, |
| 1034 | .fast => { | 1021 | .fast => { |
| 1035 | var id: [16]u8 = undefined; | 1022 | var id: [16]u8 = undefined; |
| 1036 | std.crypto.hash.sha3.TurboShake128(null).hash(binary_bytes.items, &id, .{}); | 1023 | std.crypto.hash.sha3.TurboShake128(null).hash(w.buffered(), &id, .{}); |
| 1037 | var uuid: [36]u8 = undefined; | 1024 | var uuid: [36]u8 = undefined; |
| 1038 | _ = try std.fmt.bufPrint(&uuid, "{x}-{x}-{x}-{x}-{x}", .{ | 1025 | _ = try std.fmt.bufPrint(&uuid, "{x}-{x}-{x}-{x}-{x}", .{ |
| 1039 | id[0..4], id[4..6], id[6..8], id[8..10], id[10..], | 1026 | id[0..4], id[4..6], id[6..8], id[8..10], id[10..], |
| 1040 | }); | 1027 | }); |
| 1041 | try emitBuildIdSection(gpa, binary_bytes, &uuid); | 1028 | try emitBuildIdSection(&aw, &uuid); |
| 1042 | }, | 1029 | }, |
| 1043 | .hexstring => |hs| { | 1030 | .hexstring => |hs| { |
| 1044 | var buffer: [32 * 2]u8 = undefined; | 1031 | var buffer: [32 * 2]u8 = undefined; |
| 1045 | const str = std.fmt.bufPrint(&buffer, "{x}", .{hs.toSlice()}) catch unreachable; | 1032 | const str = std.fmt.bufPrint(&buffer, "{x}", .{hs.toSlice()}) catch unreachable; |
| 1046 | try emitBuildIdSection(gpa, binary_bytes, str); | 1033 | try emitBuildIdSection(&aw, str); |
| 1047 | }, | 1034 | }, |
| 1048 | else => |mode| { | 1035 | else => |mode| { |
| 1049 | var err = try diags.addErrorWithNotes(0); | 1036 | var err = try diags.addErrorWithNotes(0); |
| ... | @@ -1054,14 +1041,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { | ... | @@ -1054,14 +1041,17 @@ pub fn finish(f: *Flush, wasm: *Wasm) !void { |
| 1054 | var debug_bytes = std.ArrayList(u8).init(gpa); | 1041 | var debug_bytes = std.ArrayList(u8).init(gpa); |
| 1055 | defer debug_bytes.deinit(); | 1042 | defer debug_bytes.deinit(); |
| 1056 | | 1043 | |
| 1057 | try emitProducerSection(gpa, binary_bytes); | 1044 | try emitProducerSection(&aw); |
| 1058 | try emitFeaturesSection(gpa, binary_bytes, target); | 1045 | emitFeaturesSection(&aw, target) catch |err| switch (err) { |
| | 1046 | error.WriteFailed => return error.OutOfMemory, |
| | 1047 | }; |
| 1059 | } | 1048 | } |
| 1060 | | 1049 | |
| 1061 | // Finally, write the entire binary into the file. | 1050 | // Finally, write the entire binary into the file. |
| 1062 | const file = wasm.base.file.?; | 1051 | const file = wasm.base.file.?; |
| 1063 | try file.pwriteAll(binary_bytes.items, 0); | 1052 | const contents = aw.getWritten(); |
| 1064 | try file.setEndPos(binary_bytes.items.len); | 1053 | try file.setEndPos(contents.len); |
| | 1054 | try file.pwriteAll(contents, 0); |
| 1065 | } | 1055 | } |
| 1066 | | 1056 | |
| 1067 | const VirtualAddrs = struct { | 1057 | const VirtualAddrs = struct { |
| ... | @@ -1076,170 +1066,155 @@ const VirtualAddrs = struct { | ... | @@ -1076,170 +1066,155 @@ const VirtualAddrs = struct { |
| 1076 | | 1066 | |
| 1077 | fn emitNameSection( | 1067 | fn emitNameSection( |
| 1078 | wasm: *Wasm, | 1068 | wasm: *Wasm, |
| | 1069 | aw: *Writer.Allocating, |
| 1079 | data_segment_groups: []const DataSegmentGroup, | 1070 | data_segment_groups: []const DataSegmentGroup, |
| 1080 | binary_bytes: *std.ArrayListUnmanaged(u8), | | |
| 1081 | ) !void { | 1071 | ) !void { |
| 1082 | const f = &wasm.flush_buffer; | 1072 | const f = &wasm.flush_buffer; |
| 1083 | const comp = wasm.base.comp; | 1073 | const w = &aw.writer; |
| 1084 | const gpa = comp.gpa; | 1074 | const header_offset = try reserveSectionHeader(w); |
| | 1075 | defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); |
| 1085 | | 1076 | |
| 1086 | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1077 | const section_name = "name"; |
| 1087 | defer writeCustomSectionHeader(binary_bytes, header_offset); | 1078 | try w.writeLeb128(section_name.len); |
| 1088 | | 1079 | try w.writeAll(section_name); |
| 1089 | const name_name = "name"; | | |
| 1090 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, name_name.len)); | | |
| 1091 | try binary_bytes.appendSlice(gpa, name_name); | | |
| 1092 | | 1080 | |
| 1093 | { | 1081 | { |
| 1094 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1082 | const sub_header_offset = try reserveSectionHeader(w); |
| 1095 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.function)); | 1083 | defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.function)); |
| 1096 | | | |
| 1097 | const total_functions: u32 = @intCast(f.function_imports.entries.len + wasm.functions.entries.len); | | |
| 1098 | try leb.writeUleb128(binary_bytes.writer(gpa), total_functions); | | |
| 1099 | | 1084 | |
| | 1085 | try w.writeLeb128(f.function_imports.entries.len + wasm.functions.entries.len); |
| 1100 | for (f.function_imports.keys(), 0..) |name_index, function_index| { | 1086 | for (f.function_imports.keys(), 0..) |name_index, function_index| { |
| 1101 | const name = name_index.slice(wasm); | 1087 | const name = name_index.slice(wasm); |
| 1102 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); | 1088 | try w.writeLeb128(function_index); |
| 1103 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); | 1089 | try w.writeLeb128(name.len); |
| 1104 | try binary_bytes.appendSlice(gpa, name); | 1090 | try w.writeAll(name); |
| 1105 | } | 1091 | } |
| 1106 | for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| { | 1092 | for (wasm.functions.keys(), f.function_imports.entries.len..) |resolution, function_index| { |
| 1107 | const name = resolution.name(wasm).?; | 1093 | const name = resolution.name(wasm).?; |
| 1108 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(function_index))); | 1094 | try w.writeLeb128(function_index); |
| 1109 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); | 1095 | try w.writeLeb128(name.len); |
| 1110 | try binary_bytes.appendSlice(gpa, name); | 1096 | try w.writeAll(name); |
| 1111 | } | 1097 | } |
| 1112 | } | 1098 | } |
| 1113 | | 1099 | |
| 1114 | { | 1100 | { |
| 1115 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1101 | const sub_header_offset = try reserveSectionHeader(w); |
| 1116 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.global)); | 1102 | defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.global)); |
| 1117 | | | |
| 1118 | const total_globals: u32 = @intCast(f.global_imports.entries.len + wasm.globals.entries.len); | | |
| 1119 | try leb.writeUleb128(binary_bytes.writer(gpa), total_globals); | | |
| 1120 | | 1103 | |
| | 1104 | try w.writeLeb128(f.global_imports.entries.len + wasm.globals.entries.len); |
| 1121 | for (f.global_imports.keys(), 0..) |name_index, global_index| { | 1105 | for (f.global_imports.keys(), 0..) |name_index, global_index| { |
| 1122 | const name = name_index.slice(wasm); | 1106 | const name = name_index.slice(wasm); |
| 1123 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); | 1107 | try w.writeLeb128(global_index); |
| 1124 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); | 1108 | try w.writeLeb128(name.len); |
| 1125 | try binary_bytes.appendSlice(gpa, name); | 1109 | try w.writeAll(name); |
| 1126 | } | 1110 | } |
| 1127 | for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| { | 1111 | for (wasm.globals.keys(), f.global_imports.entries.len..) |resolution, global_index| { |
| 1128 | const name = resolution.name(wasm).?; | 1112 | const name = resolution.name(wasm).?; |
| 1129 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(global_index))); | 1113 | try w.writeLeb128(global_index); |
| 1130 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); | 1114 | try w.writeLeb128(name.len); |
| 1131 | try binary_bytes.appendSlice(gpa, name); | 1115 | try w.writeAll(name); |
| 1132 | } | 1116 | } |
| 1133 | } | 1117 | } |
| 1134 | | 1118 | |
| 1135 | { | 1119 | { |
| 1136 | const sub_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1120 | const sub_header_offset = try reserveSectionHeader(w); |
| 1137 | defer replaceHeader(binary_bytes, sub_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); | 1121 | defer replaceSectionHeader(aw, sub_header_offset, @intFromEnum(std.wasm.NameSubsection.data_segment)); |
| 1138 | | 1122 | |
| 1139 | const total_data_segments: u32 = @intCast(data_segment_groups.len); | 1123 | try w.writeLeb128(data_segment_groups.len); |
| 1140 | try leb.writeUleb128(binary_bytes.writer(gpa), total_data_segments); | 1124 | for (data_segment_groups, 0..) |group, group_index| { |
| 1141 | | | |
| 1142 | for (data_segment_groups, 0..) |group, i| { | | |
| 1143 | const name, _ = splitSegmentName(group.first_segment.name(wasm)); | 1125 | const name, _ = splitSegmentName(group.first_segment.name(wasm)); |
| 1144 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(i))); | 1126 | try w.writeLeb128(group_index); |
| 1145 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); | 1127 | try w.writeLeb128(name.len); |
| 1146 | try binary_bytes.appendSlice(gpa, name); | 1128 | try w.writeAll(name); |
| 1147 | } | 1129 | } |
| 1148 | } | 1130 | } |
| 1149 | } | 1131 | } |
| 1150 | | 1132 | |
| 1151 | fn emitFeaturesSection( | 1133 | fn emitFeaturesSection(aw: *Writer.Allocating, target: *const std.Target) !void { |
| 1152 | gpa: Allocator, | | |
| 1153 | binary_bytes: *std.ArrayListUnmanaged(u8), | | |
| 1154 | target: *const std.Target, | | |
| 1155 | ) Allocator.Error!void { | | |
| 1156 | const feature_count = target.cpu.features.count(); | 1134 | const feature_count = target.cpu.features.count(); |
| 1157 | if (feature_count == 0) return; | 1135 | if (feature_count == 0) return; |
| 1158 | | 1136 | |
| 1159 | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1137 | const w = &aw.writer; |
| 1160 | defer writeCustomSectionHeader(binary_bytes, header_offset); | 1138 | const header_offset = try reserveSectionHeader(w); |
| 1161 | | 1139 | defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); |
| 1162 | const writer = binary_bytes.writer(gpa); | | |
| 1163 | const target_features = "target_features"; | | |
| 1164 | try leb.writeUleb128(writer, @as(u32, @intCast(target_features.len))); | | |
| 1165 | try writer.writeAll(target_features); | | |
| 1166 | | 1140 | |
| 1167 | try leb.writeUleb128(writer, @as(u32, @intCast(feature_count))); | 1141 | const section_name = "target_features"; |
| | 1142 | try w.writeLeb128(section_name.len); |
| | 1143 | try w.writeAll(section_name); |
| 1168 | | 1144 | |
| | 1145 | try w.writeLeb128(feature_count); |
| 1169 | var safety_count = feature_count; | 1146 | var safety_count = feature_count; |
| 1170 | for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| { | 1147 | for (target.cpu.arch.allFeaturesList(), 0..) |*feature, i| { |
| 1171 | if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue; | 1148 | if (!target.cpu.has(.wasm, @as(std.Target.wasm.Feature, @enumFromInt(i)))) continue; |
| 1172 | safety_count -= 1; | 1149 | safety_count -= 1; |
| 1173 | | 1150 | |
| 1174 | try leb.writeUleb128(writer, @as(u32, '+')); | 1151 | try w.writeUleb128('+'); |
| 1175 | // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions. | 1152 | // Depends on llvm_name for the hyphenated version that matches wasm tooling conventions. |
| 1176 | const name = feature.llvm_name.?; | 1153 | const name = feature.llvm_name.?; |
| 1177 | try leb.writeUleb128(writer, @as(u32, @intCast(name.len))); | 1154 | try w.writeLeb128(name.len); |
| 1178 | try writer.writeAll(name); | 1155 | try w.writeAll(name); |
| 1179 | } | 1156 | } |
| 1180 | assert(safety_count == 0); | 1157 | assert(safety_count == 0); |
| 1181 | } | 1158 | } |
| 1182 | | 1159 | |
| 1183 | fn emitBuildIdSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8), build_id: []const u8) !void { | 1160 | fn emitBuildIdSection(aw: *Writer.Allocating, build_id: []const u8) !void { |
| 1184 | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1161 | const w = &aw.writer; |
| 1185 | defer writeCustomSectionHeader(binary_bytes, header_offset); | 1162 | const header_offset = try reserveSectionHeader(w); |
| | 1163 | defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); |
| 1186 | | 1164 | |
| 1187 | const writer = binary_bytes.writer(gpa); | 1165 | const section_name = "build_id"; |
| 1188 | const hdr_build_id = "build_id"; | 1166 | try w.writeLeb128(section_name.len); |
| 1189 | try leb.writeUleb128(writer, @as(u32, @intCast(hdr_build_id.len))); | 1167 | try w.writeAll(section_name); |
| 1190 | try writer.writeAll(hdr_build_id); | | |
| 1191 | | 1168 | |
| 1192 | try leb.writeUleb128(writer, @as(u32, 1)); | 1169 | try w.writeUleb128(1); |
| 1193 | try leb.writeUleb128(writer, @as(u32, @intCast(build_id.len))); | 1170 | try w.writeLeb128(build_id.len); |
| 1194 | try writer.writeAll(build_id); | 1171 | try w.writeAll(build_id); |
| 1195 | } | 1172 | } |
| 1196 | | 1173 | |
| 1197 | fn emitProducerSection(gpa: Allocator, binary_bytes: *std.ArrayListUnmanaged(u8)) !void { | 1174 | fn emitProducerSection(aw: *Writer.Allocating) !void { |
| 1198 | const header_offset = try reserveCustomSectionHeader(gpa, binary_bytes); | 1175 | const w = &aw.writer; |
| 1199 | defer writeCustomSectionHeader(binary_bytes, header_offset); | 1176 | const header_offset = try reserveSectionHeader(w); |
| 1200 | | 1177 | defer replaceSectionHeader(aw, header_offset, @intFromEnum(std.wasm.Section.custom)); |
| 1201 | const writer = binary_bytes.writer(gpa); | | |
| 1202 | const producers = "producers"; | | |
| 1203 | try leb.writeUleb128(writer, @as(u32, @intCast(producers.len))); | | |
| 1204 | try writer.writeAll(producers); | | |
| 1205 | | 1178 | |
| 1206 | try leb.writeUleb128(writer, @as(u32, 2)); // 2 fields: Language + processed-by | 1179 | const section_name = "producers"; |
| | 1180 | try w.writeLeb128(section_name.len); |
| | 1181 | try w.writeAll(section_name); |
| 1207 | | 1182 | |
| 1208 | // language field | 1183 | try w.writeUleb128(2); // 2 fields: language + processed-by |
| 1209 | { | 1184 | { |
| 1210 | const language = "language"; | 1185 | const field_name = "language"; |
| 1211 | try leb.writeUleb128(writer, @as(u32, @intCast(language.len))); | 1186 | try w.writeLeb128(field_name.len); |
| 1212 | try writer.writeAll(language); | 1187 | try w.writeAll(field_name); |
| 1213 | | 1188 | |
| 1214 | // field_value_count (TODO: Parse object files for producer sections to detect their language) | 1189 | // field_value_count (TODO: Parse object files for producer sections to detect their language) |
| 1215 | try leb.writeUleb128(writer, @as(u32, 1)); | 1190 | try w.writeUleb128(1); |
| 1216 | | 1191 | |
| 1217 | // versioned name | 1192 | // versioned name |
| 1218 | { | 1193 | { |
| 1219 | try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig" | 1194 | const field_value = "Zig"; |
| 1220 | try writer.writeAll("Zig"); | 1195 | try w.writeLeb128(field_value.len); |
| | 1196 | try w.writeAll(field_value); |
| 1221 | | 1197 | |
| 1222 | try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len))); | 1198 | try w.writeLeb128(build_options.version.len); |
| 1223 | try writer.writeAll(build_options.version); | 1199 | try w.writeAll(build_options.version); |
| 1224 | } | 1200 | } |
| 1225 | } | 1201 | } |
| 1226 | | | |
| 1227 | // processed-by field | | |
| 1228 | { | 1202 | { |
| 1229 | const processed_by = "processed-by"; | 1203 | const field_name = "processed-by"; |
| 1230 | try leb.writeUleb128(writer, @as(u32, @intCast(processed_by.len))); | 1204 | try w.writeLeb128(field_name.len); |
| 1231 | try writer.writeAll(processed_by); | 1205 | try w.writeAll(field_name); |
| 1232 | | 1206 | |
| 1233 | // field_value_count (TODO: Parse object files for producer sections to detect other used tools) | 1207 | // field_value_count (TODO: Parse object files for producer sections to detect other used tools) |
| 1234 | try leb.writeUleb128(writer, @as(u32, 1)); | 1208 | try w.writeUleb128(1); |
| 1235 | | 1209 | |
| 1236 | // versioned name | 1210 | // versioned name |
| 1237 | { | 1211 | { |
| 1238 | try leb.writeUleb128(writer, @as(u32, 3)); // len of "Zig" | 1212 | const field_value = "Zig"; |
| 1239 | try writer.writeAll("Zig"); | 1213 | try w.writeLeb128(field_value.len); |
| | 1214 | try w.writeAll(field_value); |
| 1240 | | 1215 | |
| 1241 | try leb.writeUleb128(writer, @as(u32, @intCast(build_options.version.len))); | 1216 | try w.writeLeb128(build_options.version.len); |
| 1242 | try writer.writeAll(build_options.version); | 1217 | try w.writeAll(build_options.version); |
| 1243 | } | 1218 | } |
| 1244 | } | 1219 | } |
| 1245 | } | 1220 | } |
| ... | @@ -1277,170 +1252,130 @@ fn wantSegmentMerge( | ... | @@ -1277,170 +1252,130 @@ fn wantSegmentMerge( |
| 1277 | } | 1252 | } |
| 1278 | | 1253 | |
| 1279 | /// section id + fixed leb contents size + fixed leb vector length | 1254 | /// section id + fixed leb contents size + fixed leb vector length |
| 1280 | const section_header_reserve_size = 1 + 5 + 5; | 1255 | const vec_section_header_size = section_header_size + size_header_size; |
| 1281 | const section_header_size = 5 + 1; | | |
| 1282 | | 1256 | |
| 1283 | fn reserveVecSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { | 1257 | fn reserveVecSectionHeader(w: *Writer) Writer.Error!u32 { |
| 1284 | try bytes.appendNTimes(gpa, 0, section_header_reserve_size); | 1258 | const offset = w.end; |
| 1285 | return @intCast(bytes.items.len - section_header_reserve_size); | 1259 | _ = try w.writableSlice(vec_section_header_size); |
| | 1260 | return @intCast(offset); |
| 1286 | } | 1261 | } |
| 1287 | | 1262 | |
| 1288 | fn replaceVecSectionHeader( | 1263 | fn replaceVecSectionHeader( |
| 1289 | bytes: *std.ArrayListUnmanaged(u8), | 1264 | aw: *Writer.Allocating, |
| 1290 | offset: u32, | 1265 | offset: u32, |
| 1291 | section: std.wasm.Section, | 1266 | section: std.wasm.Section, |
| 1292 | n_items: u32, | 1267 | n_items: u32, |
| 1293 | ) void { | 1268 | ) void { |
| 1294 | const size: u32 = @intCast(bytes.items.len - offset - section_header_reserve_size + uleb128size(n_items)); | 1269 | const header = aw.getWritten()[offset..][0..vec_section_header_size]; |
| 1295 | var buf: [section_header_reserve_size]u8 = undefined; | 1270 | header[0] = @intFromEnum(section); |
| 1296 | var fbw = std.io.fixedBufferStream(&buf); | 1271 | std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.writer.end - offset - section_header_size)); |
| 1297 | const w = fbw.writer(); | 1272 | std.leb.writeUnsignedFixed(5, header[6..], n_items); |
| 1298 | w.writeByte(@intFromEnum(section)) catch unreachable; | | |
| 1299 | leb.writeUleb128(w, size) catch unreachable; | | |
| 1300 | leb.writeUleb128(w, n_items) catch unreachable; | | |
| 1301 | bytes.replaceRangeAssumeCapacity(offset, section_header_reserve_size, fbw.getWritten()); | | |
| 1302 | } | 1273 | } |
| 1303 | | 1274 | |
| 1304 | fn reserveCustomSectionHeader(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { | 1275 | const section_header_size = 1 + size_header_size; |
| 1305 | try bytes.appendNTimes(gpa, 0, section_header_size); | | |
| 1306 | return @intCast(bytes.items.len - section_header_size); | | |
| 1307 | } | | |
| 1308 | | 1276 | |
| 1309 | fn writeCustomSectionHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { | 1277 | fn reserveSectionHeader(w: *Writer) Writer.Error!u32 { |
| 1310 | return replaceHeader(bytes, offset, 0); // 0 = 'custom' section | 1278 | const offset = w.end; |
| | 1279 | _ = try w.writableSlice(section_header_size); |
| | 1280 | return @intCast(offset); |
| 1311 | } | 1281 | } |
| 1312 | | 1282 | |
| 1313 | fn replaceHeader(bytes: *std.ArrayListUnmanaged(u8), offset: u32, tag: u8) void { | 1283 | fn replaceSectionHeader(aw: *Writer.Allocating, offset: u32, section: u8) void { |
| 1314 | const size: u32 = @intCast(bytes.items.len - offset - section_header_size); | 1284 | const header = aw.getWritten()[offset..][0..section_header_size]; |
| 1315 | var buf: [section_header_size]u8 = undefined; | 1285 | header[0] = section; |
| 1316 | var fbw = std.io.fixedBufferStream(&buf); | 1286 | std.leb.writeUnsignedFixed(5, header[1..6], @intCast(aw.writer.end - offset - section_header_size)); |
| 1317 | const w = fbw.writer(); | | |
| 1318 | w.writeByte(tag) catch unreachable; | | |
| 1319 | leb.writeUleb128(w, size) catch unreachable; | | |
| 1320 | bytes.replaceRangeAssumeCapacity(offset, section_header_size, fbw.getWritten()); | | |
| 1321 | } | 1287 | } |
| 1322 | | 1288 | |
| 1323 | const max_size_encoding = 5; | 1289 | const size_header_size = 5; |
| 1324 | | 1290 | |
| 1325 | fn reserveSize(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!u32 { | 1291 | fn reserveSizeHeader(w: *Writer) Writer.Error!u32 { |
| 1326 | try bytes.appendNTimes(gpa, 0, max_size_encoding); | 1292 | const offset = w.end; |
| 1327 | return @intCast(bytes.items.len - max_size_encoding); | 1293 | _ = try w.writableSlice(size_header_size); |
| | 1294 | return @intCast(offset); |
| 1328 | } | 1295 | } |
| 1329 | | 1296 | |
| 1330 | fn replaceSize(bytes: *std.ArrayListUnmanaged(u8), offset: u32) void { | 1297 | fn replaceSizeHeader(aw: *Writer.Allocating, offset: u32) void { |
| 1331 | const size: u32 = @intCast(bytes.items.len - offset - max_size_encoding); | 1298 | const header = aw.getWritten()[offset..][0..size_header_size]; |
| 1332 | var buf: [max_size_encoding]u8 = undefined; | 1299 | std.leb.writeUnsignedFixed(5, header[0..5], @intCast(aw.writer.end - offset - size_header_size)); |
| 1333 | var fbw = std.io.fixedBufferStream(&buf); | | |
| 1334 | leb.writeUleb128(fbw.writer(), size) catch unreachable; | | |
| 1335 | bytes.replaceRangeAssumeCapacity(offset, max_size_encoding, fbw.getWritten()); | | |
| 1336 | } | 1300 | } |
| 1337 | | 1301 | |
| 1338 | fn emitLimits( | 1302 | fn emitLimits(w: *Writer, limits: std.wasm.Limits) Writer.Error!void { |
| 1339 | gpa: Allocator, | 1303 | try w.writeByte(@bitCast(limits.flags)); |
| 1340 | binary_bytes: *std.ArrayListUnmanaged(u8), | 1304 | try w.writeLeb128(limits.min); |
| 1341 | limits: std.wasm.Limits, | 1305 | if (limits.flags.has_max) try w.writeLeb128(limits.max); |
| 1342 | ) Allocator.Error!void { | | |
| 1343 | try binary_bytes.append(gpa, @bitCast(limits.flags)); | | |
| 1344 | try leb.writeUleb128(binary_bytes.writer(gpa), limits.min); | | |
| 1345 | if (limits.flags.has_max) try leb.writeUleb128(binary_bytes.writer(gpa), limits.max); | | |
| 1346 | } | 1306 | } |
| 1347 | | 1307 | |
| 1348 | fn emitMemoryImport( | 1308 | fn emitMemoryImport( |
| 1349 | wasm: *Wasm, | 1309 | wasm: *Wasm, |
| 1350 | binary_bytes: *std.ArrayListUnmanaged(u8), | 1310 | w: *Writer, |
| 1351 | name_index: String, | 1311 | name_index: String, |
| 1352 | memory_import: *const Wasm.MemoryImport, | 1312 | memory_import: *const Wasm.MemoryImport, |
| 1353 | ) Allocator.Error!void { | 1313 | ) Writer.Error!void { |
| 1354 | const gpa = wasm.base.comp.gpa; | | |
| 1355 | const module_name = memory_import.module_name.slice(wasm); | 1314 | const module_name = memory_import.module_name.slice(wasm); |
| 1356 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(module_name.len))); | 1315 | try w.writeLeb128(module_name.len); |
| 1357 | try binary_bytes.appendSlice(gpa, module_name); | 1316 | try w.writeAll(module_name); |
| 1358 | | 1317 | |
| 1359 | const name = name_index.slice(wasm); | 1318 | const name = name_index.slice(wasm); |
| 1360 | try leb.writeUleb128(binary_bytes.writer(gpa), @as(u32, @intCast(name.len))); | 1319 | try w.writeLeb128(name.len); |
| 1361 | try binary_bytes.appendSlice(gpa, name); | 1320 | try w.writeAll(name); |
| 1362 | | 1321 | |
| 1363 | try binary_bytes.append(gpa, @intFromEnum(std.wasm.ExternalKind.memory)); | 1322 | try w.writeByte(@intFromEnum(std.wasm.ExternalKind.memory)); |
| 1364 | try emitLimits(gpa, binary_bytes, memory_import.limits()); | 1323 | try emitLimits(w, memory_import.limits()); |
| 1365 | } | 1324 | } |
| 1366 | | 1325 | |
| 1367 | pub fn emitInit(writer: anytype, init_expr: std.wasm.InitExpression) !void { | 1326 | pub fn emitInit(w: *Writer, init_expr: std.wasm.InitExpression) Writer.Error!void { |
| 1368 | switch (init_expr) { | 1327 | switch (init_expr) { |
| 1369 | .i32_const => |val| { | 1328 | inline else => |val, tag| { |
| 1370 | try writer.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); | 1329 | try w.writeByte(@intFromEnum(@field(std.wasm.Opcode, @tagName(tag)))); |
| 1371 | try leb.writeIleb128(writer, val); | 1330 | switch (@typeInfo(@TypeOf(val))) { |
| 1372 | }, | 1331 | .int => try w.writeLeb128(val), |
| 1373 | .i64_const => |val| { | 1332 | .float => |float| try w.writeInt( |
| 1374 | try writer.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); | 1333 | @Type(.{ .int = .{ .signedness = .unsigned, .bits = float.bits } }), |
| 1375 | try leb.writeIleb128(writer, val); | 1334 | @bitCast(val), |
| 1376 | }, | 1335 | .little, |
| 1377 | .f32_const => |val| { | 1336 | ), |
| 1378 | try writer.writeByte(@intFromEnum(std.wasm.Opcode.f32_const)); | 1337 | else => comptime unreachable, |
| 1379 | try writer.writeInt(u32, @bitCast(val), .little); | 1338 | } |
| 1380 | }, | | |
| 1381 | .f64_const => |val| { | | |
| 1382 | try writer.writeByte(@intFromEnum(std.wasm.Opcode.f64_const)); | | |
| 1383 | try writer.writeInt(u64, @bitCast(val), .little); | | |
| 1384 | }, | | |
| 1385 | .global_get => |val| { | | |
| 1386 | try writer.writeByte(@intFromEnum(std.wasm.Opcode.global_get)); | | |
| 1387 | try leb.writeUleb128(writer, val); | | |
| 1388 | }, | 1339 | }, |
| 1389 | } | 1340 | } |
| 1390 | try writer.writeByte(@intFromEnum(std.wasm.Opcode.end)); | 1341 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1391 | } | 1342 | } |
| 1392 | | 1343 | |
| 1393 | pub fn emitExpr(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8), expr: Wasm.Expr) Allocator.Error!void { | 1344 | pub fn emitExpr(wasm: *const Wasm, w: *Writer, expr: Wasm.Expr) Writer.Error!void { |
| 1394 | const gpa = wasm.base.comp.gpa; | | |
| 1395 | const slice = expr.slice(wasm); | 1345 | const slice = expr.slice(wasm); |
| 1396 | try binary_bytes.appendSlice(gpa, slice[0 .. slice.len + 1]); // +1 to include end opcode | 1346 | try w.writeAll(slice[0 .. slice.len + 1]); // +1 to include end opcode |
| 1397 | } | 1347 | } |
| 1398 | | 1348 | |
| 1399 | fn emitSegmentInfo(wasm: *Wasm, binary_bytes: *std.ArrayList(u8)) !void { | 1349 | fn emitSegmentInfo(wasm: *Wasm, aw: *Writer) Writer.Error!void { |
| 1400 | const gpa = wasm.base.comp.gpa; | 1350 | const w = &aw.writer; |
| 1401 | const writer = binary_bytes.writer(gpa); | 1351 | const header_offset = try reserveSectionHeader(w); |
| 1402 | try leb.writeUleb128(writer, @intFromEnum(Wasm.SubsectionType.segment_info)); | 1352 | defer replaceSectionHeader(aw, header_offset, @intFromEnum(Wasm.SubsectionType.segment_info)); |
| 1403 | const segment_offset = binary_bytes.items.len; | | |
| 1404 | | 1353 | |
| 1405 | try leb.writeUleb128(writer, @as(u32, @intCast(wasm.segment_info.count()))); | 1354 | try w.writeLeb128(wasm.segment_info.count()); |
| 1406 | for (wasm.segment_info.values()) |segment_info| { | 1355 | for (wasm.segment_info.values()) |segment_info| { |
| 1407 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ | 1356 | log.debug("Emit segment: {s} align({d}) flags({b})", .{ |
| 1408 | segment_info.name, | 1357 | segment_info.name, |
| 1409 | segment_info.alignment, | 1358 | segment_info.alignment, |
| 1410 | segment_info.flags, | 1359 | segment_info.flags, |
| 1411 | }); | 1360 | }); |
| 1412 | try leb.writeUleb128(writer, @as(u32, @intCast(segment_info.name.len))); | 1361 | try w.writeLeb128(segment_info.name.len); |
| 1413 | try writer.writeAll(segment_info.name); | 1362 | try w.writeAll(segment_info.name); |
| 1414 | try leb.writeUleb128(writer, segment_info.alignment.toLog2Units()); | 1363 | try w.writeLeb128(segment_info.alignment.toLog2Units()); |
| 1415 | try leb.writeUleb128(writer, segment_info.flags); | 1364 | try w.writeLeb128(segment_info.flags); |
| 1416 | } | 1365 | } |
| 1417 | | | |
| 1418 | var buf: [5]u8 = undefined; | | |
| 1419 | leb.writeUnsignedFixed(5, &buf, @as(u32, @intCast(binary_bytes.items.len - segment_offset))); | | |
| 1420 | try binary_bytes.insertSlice(segment_offset, &buf); | | |
| 1421 | } | | |
| 1422 | | | |
| 1423 | fn uleb128size(x: u32) u32 { | | |
| 1424 | var value = x; | | |
| 1425 | var size: u32 = 0; | | |
| 1426 | while (value != 0) : (size += 1) value >>= 7; | | |
| 1427 | return size; | | |
| 1428 | } | 1366 | } |
| 1429 | | 1367 | |
| 1430 | fn emitTagNameTable( | 1368 | fn emitTagNameTable( |
| 1431 | gpa: Allocator, | 1369 | w: *Writer, |
| 1432 | code: *std.ArrayListUnmanaged(u8), | | |
| 1433 | tag_name_offs: []const u32, | 1370 | tag_name_offs: []const u32, |
| 1434 | tag_name_bytes: []const u8, | 1371 | tag_name_bytes: []const u8, |
| 1435 | base: u32, | 1372 | base: u32, |
| 1436 | comptime Int: type, | 1373 | comptime Int: type, |
| 1437 | ) error{OutOfMemory}!void { | 1374 | ) Writer.Error!void { |
| 1438 | const ptr_size_bytes = @divExact(@bitSizeOf(Int), 8); | | |
| 1439 | try code.ensureUnusedCapacity(gpa, ptr_size_bytes * 2 * tag_name_offs.len); | | |
| 1440 | for (tag_name_offs) |off| { | 1375 | for (tag_name_offs) |off| { |
| 1441 | const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?); | 1376 | const name_len: u32 = @intCast(mem.indexOfScalar(u8, tag_name_bytes[off..], 0).?); |
| 1442 | mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), base + off, .little); | 1377 | try w.writeInt(Int, base + off, .little); |
| 1443 | mem.writeInt(Int, code.addManyAsArrayAssumeCapacity(ptr_size_bytes), name_len, .little); | 1378 | try w.writeInt(Int, name_len, .little); |
| 1444 | } | 1379 | } |
| 1445 | } | 1380 | } |
| 1446 | | 1381 | |
| ... | @@ -1525,11 +1460,11 @@ fn reloc_u64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { | ... | @@ -1525,11 +1460,11 @@ fn reloc_u64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1525 | } | 1460 | } |
| 1526 | | 1461 | |
| 1527 | fn reloc_sleb_table_index(code: []u8, i: IndirectFunctionTableIndex) void { | 1462 | fn reloc_sleb_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1528 | leb.writeSignedFixed(5, code[0..5], i.toAbi()); | 1463 | std.leb.writeSignedFixed(5, code[0..5], i.toAbi()); |
| 1529 | } | 1464 | } |
| 1530 | | 1465 | |
| 1531 | fn reloc_sleb64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { | 1466 | fn reloc_sleb64_table_index(code: []u8, i: IndirectFunctionTableIndex) void { |
| 1532 | leb.writeSignedFixed(11, code[0..11], i.toAbi()); | 1467 | std.leb.writeSignedFixed(11, code[0..11], i.toAbi()); |
| 1533 | } | 1468 | } |
| 1534 | | 1469 | |
| 1535 | fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { | 1470 | fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { |
| ... | @@ -1537,7 +1472,7 @@ fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { | ... | @@ -1537,7 +1472,7 @@ fn reloc_u32_function(code: []u8, function: Wasm.OutputFunctionIndex) void { |
| 1537 | } | 1472 | } |
| 1538 | | 1473 | |
| 1539 | fn reloc_leb_function(code: []u8, function: Wasm.OutputFunctionIndex) void { | 1474 | fn reloc_leb_function(code: []u8, function: Wasm.OutputFunctionIndex) void { |
| 1540 | leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function)); | 1475 | std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(function)); |
| 1541 | } | 1476 | } |
| 1542 | | 1477 | |
| 1543 | fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { | 1478 | fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { |
| ... | @@ -1545,7 +1480,7 @@ fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { | ... | @@ -1545,7 +1480,7 @@ fn reloc_u32_global(code: []u8, global: Wasm.GlobalIndex) void { |
| 1545 | } | 1480 | } |
| 1546 | | 1481 | |
| 1547 | fn reloc_leb_global(code: []u8, global: Wasm.GlobalIndex) void { | 1482 | fn reloc_leb_global(code: []u8, global: Wasm.GlobalIndex) void { |
| 1548 | leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global)); | 1483 | std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(global)); |
| 1549 | } | 1484 | } |
| 1550 | | 1485 | |
| 1551 | const RelocAddr = struct { | 1486 | const RelocAddr = struct { |
| ... | @@ -1581,35 +1516,31 @@ fn reloc_u64_addr(code: []u8, ra: RelocAddr) void { | ... | @@ -1581,35 +1516,31 @@ fn reloc_u64_addr(code: []u8, ra: RelocAddr) void { |
| 1581 | } | 1516 | } |
| 1582 | | 1517 | |
| 1583 | fn reloc_leb_addr(code: []u8, ra: RelocAddr) void { | 1518 | fn reloc_leb_addr(code: []u8, ra: RelocAddr) void { |
| 1584 | leb.writeUnsignedFixed(5, code[0..5], ra.addr); | 1519 | std.leb.writeUnsignedFixed(5, code[0..5], ra.addr); |
| 1585 | } | 1520 | } |
| 1586 | | 1521 | |
| 1587 | fn reloc_leb64_addr(code: []u8, ra: RelocAddr) void { | 1522 | fn reloc_leb64_addr(code: []u8, ra: RelocAddr) void { |
| 1588 | leb.writeUnsignedFixed(11, code[0..11], ra.addr); | 1523 | std.leb.writeUnsignedFixed(11, code[0..11], ra.addr); |
| 1589 | } | 1524 | } |
| 1590 | | 1525 | |
| 1591 | fn reloc_sleb_addr(code: []u8, ra: RelocAddr) void { | 1526 | fn reloc_sleb_addr(code: []u8, ra: RelocAddr) void { |
| 1592 | leb.writeSignedFixed(5, code[0..5], ra.addr); | 1527 | std.leb.writeSignedFixed(5, code[0..5], ra.addr); |
| 1593 | } | 1528 | } |
| 1594 | | 1529 | |
| 1595 | fn reloc_sleb64_addr(code: []u8, ra: RelocAddr) void { | 1530 | fn reloc_sleb64_addr(code: []u8, ra: RelocAddr) void { |
| 1596 | leb.writeSignedFixed(11, code[0..11], ra.addr); | 1531 | std.leb.writeSignedFixed(11, code[0..11], ra.addr); |
| 1597 | } | 1532 | } |
| 1598 | | 1533 | |
| 1599 | fn reloc_leb_table(code: []u8, table: Wasm.TableIndex) void { | 1534 | fn reloc_leb_table(code: []u8, table: Wasm.TableIndex) void { |
| 1600 | leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table)); | 1535 | std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(table)); |
| 1601 | } | 1536 | } |
| 1602 | | 1537 | |
| 1603 | fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void { | 1538 | fn reloc_leb_type(code: []u8, index: FuncTypeIndex) void { |
| 1604 | leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index)); | 1539 | std.leb.writeUnsignedFixed(5, code[0..5], @intFromEnum(index)); |
| 1605 | } | 1540 | } |
| 1606 | | 1541 | |
| 1607 | fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void { | 1542 | fn emitCallCtorsFunction(wasm: *const Wasm, w: *Writer) Writer.Error!void { |
| 1608 | const gpa = wasm.base.comp.gpa; | 1543 | try w.writeUleb128(0); // no locals |
| 1609 | | | |
| 1610 | try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1); | | |
| 1611 | appendReservedUleb32(binary_bytes, 0); // no locals | | |
| 1612 | | | |
| 1613 | for (wasm.object_init_funcs.items) |init_func| { | 1544 | for (wasm.object_init_funcs.items) |init_func| { |
| 1614 | const func = init_func.function_index.ptr(wasm); | 1545 | const func = init_func.function_index.ptr(wasm); |
| 1615 | if (!func.object_index.ptr(wasm).is_included) continue; | 1546 | if (!func.object_index.ptr(wasm).is_included) continue; |
| ... | @@ -1617,25 +1548,18 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage | ... | @@ -1617,25 +1548,18 @@ fn emitCallCtorsFunction(wasm: *const Wasm, binary_bytes: *std.ArrayListUnmanage |
| 1617 | const n_returns = ty.returns.slice(wasm).len; | 1548 | const n_returns = ty.returns.slice(wasm).len; |
| 1618 | | 1549 | |
| 1619 | // Call function by its function index | 1550 | // Call function by its function index |
| 1620 | try binary_bytes.ensureUnusedCapacity(gpa, 1 + 5 + n_returns + 1); | | |
| 1621 | const call_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index); | 1551 | const call_index: Wasm.OutputFunctionIndex = .fromObjectFunction(wasm, init_func.function_index); |
| 1622 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); | 1552 | try w.writeByte(@intFromEnum(std.wasm.Opcode.call)); |
| 1623 | appendReservedUleb32(binary_bytes, @intFromEnum(call_index)); | 1553 | try w.writeLeb128(@intFromEnum(call_index)); |
| 1624 | | 1554 | |
| 1625 | // drop all returned values from the stack as __wasm_call_ctors has no return value | 1555 | // drop all returned values from the stack as __wasm_call_ctors has no return value |
| 1626 | binary_bytes.appendNTimesAssumeCapacity(@intFromEnum(std.wasm.Opcode.drop), n_returns); | 1556 | try w.splatByteAll(@intFromEnum(std.wasm.Opcode.drop), n_returns); |
| 1627 | } | 1557 | } |
| 1628 | | 1558 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end function body |
| 1629 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); // end function body | | |
| 1630 | } | 1559 | } |
| 1631 | | 1560 | |
| 1632 | fn emitInitMemoryFunction( | 1561 | fn emitInitMemoryFunction(wasm: *const Wasm, w: *Writer, virtual_addrs: *const VirtualAddrs) Writer.Error!void { |
| 1633 | wasm: *const Wasm, | | |
| 1634 | binary_bytes: *std.ArrayListUnmanaged(u8), | | |
| 1635 | virtual_addrs: *const VirtualAddrs, | | |
| 1636 | ) Allocator.Error!void { | | |
| 1637 | const comp = wasm.base.comp; | 1562 | const comp = wasm.base.comp; |
| 1638 | const gpa = comp.gpa; | | |
| 1639 | const shared_memory = comp.config.shared_memory; | 1563 | const shared_memory = comp.config.shared_memory; |
| 1640 | | 1564 | |
| 1641 | // Passive segments are used to avoid memory being reinitialized on each | 1565 | // Passive segments are used to avoid memory being reinitialized on each |
| ... | @@ -1645,39 +1569,40 @@ fn emitInitMemoryFunction( | ... | @@ -1645,39 +1569,40 @@ fn emitInitMemoryFunction( |
| 1645 | // function. | 1569 | // function. |
| 1646 | assert(wasm.any_passive_inits); | 1570 | assert(wasm.any_passive_inits); |
| 1647 | | 1571 | |
| 1648 | try binary_bytes.ensureUnusedCapacity(gpa, 5 + 1); | 1572 | try w.writeUleb128(0); // no locals |
| 1649 | appendReservedUleb32(binary_bytes, 0); // no locals | | |
| 1650 | | 1573 | |
| 1651 | if (virtual_addrs.init_memory_flag) |flag_address| { | 1574 | if (virtual_addrs.init_memory_flag) |flag_address| { |
| 1652 | assert(shared_memory); | 1575 | assert(shared_memory); |
| 1653 | try binary_bytes.ensureUnusedCapacity(gpa, 2 * 3 + 6 * 3 + 1 + 6 * 3 + 1 + 5 * 4 + 1 + 1); | | |
| 1654 | // destination blocks | 1576 | // destination blocks |
| 1655 | // based on values we jump to corresponding label | 1577 | // based on values we jump to corresponding label |
| 1656 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); // $drop | 1578 | try w.writeAll(&.{ |
| 1657 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); | 1579 | @intFromEnum(std.wasm.Opcode.block), // $drop |
| 1658 | | 1580 | @intFromEnum(std.wasm.BlockType.empty), |
| 1659 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); // $wait | 1581 | @intFromEnum(std.wasm.Opcode.block), // $wait |
| 1660 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); | 1582 | @intFromEnum(std.wasm.BlockType.empty), |
| 1661 | | 1583 | @intFromEnum(std.wasm.Opcode.block), // $init |
| 1662 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); // $init | 1584 | @intFromEnum(std.wasm.BlockType.empty), |
| 1663 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); | 1585 | }); |
| 1664 | | 1586 | |
| 1665 | // atomically check | 1587 | // atomically check |
| 1666 | appendReservedI32Const(binary_bytes, flag_address); | 1588 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1667 | appendReservedI32Const(binary_bytes, 0); | 1589 | try w.writeLeb128(@as(i32, @bitCast(flag_address))); |
| 1668 | appendReservedI32Const(binary_bytes, 1); | 1590 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1669 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); | 1591 | try w.writeSleb128(0); |
| 1670 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_rmw_cmpxchg)); | 1592 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1671 | appendReservedUleb32(binary_bytes, 2); // alignment | 1593 | try w.writeSleb128(1); |
| 1672 | appendReservedUleb32(binary_bytes, 0); // offset | 1594 | try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); |
| | 1595 | try w.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_rmw_cmpxchg)); |
| | 1596 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| | 1597 | try w.writeUleb128(0); // offset |
| 1673 | | 1598 | |
| 1674 | // based on the value from the atomic check, jump to the label. | 1599 | // based on the value from the atomic check, jump to the label. |
| 1675 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_table)); | 1600 | try w.writeByte(@intFromEnum(std.wasm.Opcode.br_table)); |
| 1676 | appendReservedUleb32(binary_bytes, 2); // length of the table (we have 3 blocks but because of the mandatory default the length is 2). | 1601 | try w.writeUleb128(3 - 1); // length of the table (we have 3 blocks but because of the mandatory default the length is 2). |
| 1677 | appendReservedUleb32(binary_bytes, 0); // $init | 1602 | try w.writeUleb128(0); // $init |
| 1678 | appendReservedUleb32(binary_bytes, 1); // $wait | 1603 | try w.writeUleb128(1); // $wait |
| 1679 | appendReservedUleb32(binary_bytes, 2); // $drop | 1604 | try w.writeUleb128(2); // $drop |
| 1680 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1605 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1681 | } | 1606 | } |
| 1682 | | 1607 | |
| 1683 | const segment_groups = wasm.flush_buffer.data_segment_groups.items; | 1608 | const segment_groups = wasm.flush_buffer.data_segment_groups.items; |
| ... | @@ -1690,74 +1615,82 @@ fn emitInitMemoryFunction( | ... | @@ -1690,74 +1615,82 @@ fn emitInitMemoryFunction( |
| 1690 | const start_addr: u32 = @intCast(segment.alignment(wasm).forward(prev_end)); | 1615 | const start_addr: u32 = @intCast(segment.alignment(wasm).forward(prev_end)); |
| 1691 | const segment_size: u32 = group.end_addr - start_addr; | 1616 | const segment_size: u32 = group.end_addr - start_addr; |
| 1692 | | 1617 | |
| 1693 | try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 5 + 6 + 6 + 1 + 6 * 2 + 1 + 1); | | |
| 1694 | | | |
| 1695 | // For passive BSS segments we can simply issue a memory.fill(0). For | 1618 | // For passive BSS segments we can simply issue a memory.fill(0). For |
| 1696 | // non-BSS segments we do a memory.init. Both instructions take as | 1619 | // non-BSS segments we do a memory.init. Both instructions take as |
| 1697 | // their first argument the destination address. | 1620 | // their first argument the destination address. |
| 1698 | appendReservedI32Const(binary_bytes, start_addr); | 1621 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| | 1622 | try w.writeLeb128(@as(i32, @bitCast(start_addr))); |
| 1699 | | 1623 | |
| 1700 | if (shared_memory and segment.isTls(wasm)) { | 1624 | if (shared_memory and segment.isTls(wasm)) { |
| 1701 | // When we initialize the TLS segment we also set the `__tls_base` | 1625 | // When we initialize the TLS segment we also set the `__tls_base` |
| 1702 | // global. This allows the runtime to use this static copy of the | 1626 | // global. This allows the runtime to use this static copy of the |
| 1703 | // TLS data for the first/main thread. | 1627 | // TLS data for the first/main thread. |
| 1704 | appendReservedI32Const(binary_bytes, start_addr); | 1628 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1705 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); | 1629 | try w.writeLeb128(@as(i32, @bitCast(start_addr))); |
| 1706 | appendReservedUleb32(binary_bytes, virtual_addrs.tls_base.?); | 1630 | try w.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); |
| | 1631 | try w.writeLeb128(virtual_addrs.tls_base.?); |
| 1707 | } | 1632 | } |
| 1708 | | 1633 | |
| 1709 | appendReservedI32Const(binary_bytes, 0); | 1634 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1710 | appendReservedI32Const(binary_bytes, segment_size); | 1635 | try w.writeSleb128(0); |
| 1711 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); | 1636 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| | 1637 | try w.writeLeb128(@as(i32, @bitCast(segment_size))); |
| | 1638 | try w.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); |
| 1712 | if (segment.isBss(wasm)) { | 1639 | if (segment.isBss(wasm)) { |
| 1713 | // fill bss segment with zeroes | 1640 | // fill bss segment with zeroes |
| 1714 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.MiscOpcode.memory_fill)); | 1641 | try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_fill)); |
| 1715 | } else { | 1642 | } else { |
| 1716 | // initialize the segment | 1643 | // initialize the segment |
| 1717 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.MiscOpcode.memory_init)); | 1644 | try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); |
| 1718 | appendReservedUleb32(binary_bytes, @intCast(segment_index)); | 1645 | try w.writeLeb128(segment_index); |
| 1719 | } | 1646 | } |
| 1720 | binary_bytes.appendAssumeCapacity(0); // memory index immediate | 1647 | try w.writeByte(0); // memory index immediate |
| 1721 | } | 1648 | } |
| 1722 | | 1649 | |
| 1723 | if (virtual_addrs.init_memory_flag) |flag_address| { | 1650 | if (virtual_addrs.init_memory_flag) |flag_address| { |
| 1724 | assert(shared_memory); | 1651 | assert(shared_memory); |
| 1725 | try binary_bytes.ensureUnusedCapacity(gpa, 6 + 6 + 1 + 3 * 5 + 6 + 1 + 5 + 1 + 3 * 5 + 1 + 1 + 5 + 1 + 6 * 2 + 1 + 5 + 1 + 3 * 5 + 1 + 1 + 1); | 1652 | |
| 1726 | // we set the init memory flag to value '2' | 1653 | // we set the init memory flag to value '2' |
| 1727 | appendReservedI32Const(binary_bytes, flag_address); | 1654 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1728 | appendReservedI32Const(binary_bytes, 2); | 1655 | try w.writeLeb128(@as(i32, @bitCast(flag_address))); |
| 1729 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); | 1656 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1730 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_store)); | 1657 | try w.writeSleb128(2); |
| 1731 | appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment | 1658 | try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); |
| 1732 | appendReservedUleb32(binary_bytes, @as(u32, 0)); // offset | 1659 | try w.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.i32_atomic_store)); |
| | 1660 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| | 1661 | try w.writeUleb128(0); // offset |
| 1733 | | 1662 | |
| 1734 | // notify any waiters for segment initialization completion | 1663 | // notify any waiters for segment initialization completion |
| 1735 | appendReservedI32Const(binary_bytes, flag_address); | 1664 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1736 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); | 1665 | try w.writeLeb128(@as(i32, @bitCast(flag_address))); |
| 1737 | leb.writeIleb128(binary_bytes.fixedWriter(), @as(i32, -1)) catch unreachable; // number of waiters | 1666 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1738 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); | 1667 | try w.writeSleb128(-1); // number of waiters |
| 1739 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify)); | 1668 | |
| 1740 | appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment | 1669 | try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); |
| 1741 | appendReservedUleb32(binary_bytes, @as(u32, 0)); // offset | 1670 | try w.writeLeb128(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_notify)); |
| 1742 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.drop)); | 1671 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| | 1672 | try w.writeUleb128(0); // offset |
| | 1673 | try w.writeByte(@intFromEnum(std.wasm.Opcode.drop)); |
| 1743 | | 1674 | |
| 1744 | // branch and drop segments | 1675 | // branch and drop segments |
| 1745 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br)); | 1676 | try w.writeByte(@intFromEnum(std.wasm.Opcode.br)); |
| 1746 | appendReservedUleb32(binary_bytes, @as(u32, 1)); | 1677 | try w.writeUleb128(1); |
| 1747 | | 1678 | |
| 1748 | // wait for thread to initialize memory segments | 1679 | // wait for thread to initialize memory segments |
| 1749 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); // end $wait | 1680 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $wait |
| 1750 | appendReservedI32Const(binary_bytes, flag_address); | 1681 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1751 | appendReservedI32Const(binary_bytes, 1); // expected flag value | 1682 | try w.writeLeb128(@as(i32, @bitCast(flag_address))); |
| 1752 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const)); | 1683 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1753 | leb.writeIleb128(binary_bytes.fixedWriter(), @as(i64, -1)) catch unreachable; // timeout | 1684 | try w.writeSleb128(1); // expected flag value |
| 1754 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.atomics_prefix)); | 1685 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); |
| 1755 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32)); | 1686 | try w.writeSleb128(-1); // timeout |
| 1756 | appendReservedUleb32(binary_bytes, @as(u32, 2)); // alignment | 1687 | try w.writeByte(@intFromEnum(std.wasm.Opcode.atomics_prefix)); |
| 1757 | appendReservedUleb32(binary_bytes, @as(u32, 0)); // offset | 1688 | try w.writeByte(@intFromEnum(std.wasm.AtomicsOpcode.memory_atomic_wait32)); |
| 1758 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.drop)); | 1689 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| 1759 | | 1690 | try w.writeUleb128(0); // offset |
| 1760 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); // end $drop | 1691 | try w.writeByte(@intFromEnum(std.wasm.Opcode.drop)); |
| | 1692 | |
| | 1693 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); // end $drop |
| 1761 | } | 1694 | } |
| 1762 | | 1695 | |
| 1763 | for (segment_groups, 0..) |group, segment_index| { | 1696 | for (segment_groups, 0..) |group, segment_index| { |
| ... | @@ -1768,26 +1701,20 @@ fn emitInitMemoryFunction( | ... | @@ -1768,26 +1701,20 @@ fn emitInitMemoryFunction( |
| 1768 | // during the initialization of each thread (__wasm_init_tls). | 1701 | // during the initialization of each thread (__wasm_init_tls). |
| 1769 | if (shared_memory and segment.isTls(wasm)) continue; | 1702 | if (shared_memory and segment.isTls(wasm)) continue; |
| 1770 | | 1703 | |
| 1771 | try binary_bytes.ensureUnusedCapacity(gpa, 1 + 5 + 5 + 1); | 1704 | try w.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); |
| 1772 | | 1705 | try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.data_drop)); |
| 1773 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); | 1706 | try w.writeLeb128(segment_index); |
| 1774 | appendReservedUleb32(binary_bytes, @intFromEnum(std.wasm.MiscOpcode.data_drop)); | | |
| 1775 | appendReservedUleb32(binary_bytes, @intCast(segment_index)); | | |
| 1776 | } | 1707 | } |
| 1777 | | 1708 | |
| 1778 | // End of the function body | 1709 | // End of the function body |
| 1779 | binary_bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1710 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1780 | } | 1711 | } |
| 1781 | | 1712 | |
| 1782 | fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Allocator.Error!void { | 1713 | fn emitInitTlsFunction(wasm: *const Wasm, w: *Writer) Writer.Error!void { |
| 1783 | const comp = wasm.base.comp; | 1714 | const comp = wasm.base.comp; |
| 1784 | const gpa = comp.gpa; | | |
| 1785 | | | |
| 1786 | assert(comp.config.shared_memory); | 1715 | assert(comp.config.shared_memory); |
| 1787 | | 1716 | |
| 1788 | try bytes.ensureUnusedCapacity(gpa, 5 * 10 + 8); | 1717 | try w.writeUleb128(0); // no locals |
| 1789 | | | |
| 1790 | appendReservedUleb32(bytes, 0); // no locals | | |
| 1791 | | 1718 | |
| 1792 | // If there's a TLS segment, initialize it during runtime using the bulk-memory feature | 1719 | // If there's a TLS segment, initialize it during runtime using the bulk-memory feature |
| 1793 | // TLS segment is always the first one due to how we sort the data segments. | 1720 | // TLS segment is always the first one due to how we sort the data segments. |
| ... | @@ -1796,36 +1723,35 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al | ... | @@ -1796,36 +1723,35 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al |
| 1796 | const start_addr = wasm.flush_buffer.data_segments.values()[0]; | 1723 | const start_addr = wasm.flush_buffer.data_segments.values()[0]; |
| 1797 | const end_addr = wasm.flush_buffer.data_segment_groups.items[0].end_addr; | 1724 | const end_addr = wasm.flush_buffer.data_segment_groups.items[0].end_addr; |
| 1798 | const group_size = end_addr - start_addr; | 1725 | const group_size = end_addr - start_addr; |
| 1799 | const data_segment_index = 0; | 1726 | const data_segment_index: u32 = 0; |
| 1800 | | 1727 | |
| 1801 | const param_local: u32 = 0; | 1728 | const param_local: u32 = 0; |
| 1802 | | 1729 | |
| 1803 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); | 1730 | try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); |
| 1804 | appendReservedUleb32(bytes, param_local); | 1731 | try w.writeLeb128(param_local); |
| 1805 | | 1732 | |
| 1806 | const tls_base_global_index: Wasm.GlobalIndex = @enumFromInt(wasm.globals.getIndex(.__tls_base).?); | 1733 | const tls_base_global_index: Wasm.GlobalIndex = @enumFromInt(wasm.globals.getIndex(.__tls_base).?); |
| 1807 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.global_set)); | 1734 | try w.writeByte(@intFromEnum(std.wasm.Opcode.global_set)); |
| 1808 | appendReservedUleb32(bytes, @intFromEnum(tls_base_global_index)); | 1735 | try w.writeLeb128(@intFromEnum(tls_base_global_index)); |
| 1809 | | 1736 | |
| 1810 | // load stack values for the bulk-memory operation | 1737 | // load stack values for the bulk-memory operation |
| 1811 | { | 1738 | { |
| 1812 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); | 1739 | try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); |
| 1813 | appendReservedUleb32(bytes, param_local); | 1740 | try w.writeLeb128(param_local); |
| 1814 | | 1741 | |
| 1815 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); | 1742 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1816 | appendReservedUleb32(bytes, 0); //segment offset | 1743 | try w.writeSleb128(0); // segment offset |
| 1817 | | 1744 | |
| 1818 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); | 1745 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1819 | appendReservedUleb32(bytes, group_size); //segment offset | 1746 | try w.writeLeb128(@as(i32, @bitCast(group_size))); // segment offset |
| 1820 | } | 1747 | } |
| 1821 | | 1748 | |
| 1822 | // perform the bulk-memory operation to initialize the data segment | 1749 | // perform the bulk-memory operation to initialize the data segment |
| 1823 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.misc_prefix)); | 1750 | try w.writeByte(@intFromEnum(std.wasm.Opcode.misc_prefix)); |
| 1824 | appendReservedUleb32(bytes, @intFromEnum(std.wasm.MiscOpcode.memory_init)); | 1751 | try w.writeLeb128(@intFromEnum(std.wasm.MiscOpcode.memory_init)); |
| 1825 | // segment immediate | 1752 | // segment immediate |
| 1826 | appendReservedUleb32(bytes, data_segment_index); | 1753 | try w.writeLeb128(data_segment_index); |
| 1827 | // memory index immediate (always 0) | 1754 | try w.writeByte(0); // memory index immediate |
| 1828 | appendReservedUleb32(bytes, 0); | | |
| 1829 | } | 1755 | } |
| 1830 | | 1756 | |
| 1831 | // If we have to perform any TLS relocations, call the corresponding function | 1757 | // If we have to perform any TLS relocations, call the corresponding function |
| ... | @@ -1833,56 +1759,59 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al | ... | @@ -1833,56 +1759,59 @@ fn emitInitTlsFunction(wasm: *const Wasm, bytes: *std.ArrayListUnmanaged(u8)) Al |
| 1833 | // generated by the linker. | 1759 | // generated by the linker. |
| 1834 | if (wasm.functions.getIndex(.__wasm_apply_global_tls_relocs)) |function_index| { | 1760 | if (wasm.functions.getIndex(.__wasm_apply_global_tls_relocs)) |function_index| { |
| 1835 | const output_function_index: Wasm.OutputFunctionIndex = .fromFunctionIndex(wasm, @enumFromInt(function_index)); | 1761 | const output_function_index: Wasm.OutputFunctionIndex = .fromFunctionIndex(wasm, @enumFromInt(function_index)); |
| 1836 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.call)); | 1762 | try w.writeByte(@intFromEnum(std.wasm.Opcode.call)); |
| 1837 | appendReservedUleb32(bytes, @intFromEnum(output_function_index)); | 1763 | try w.writeLeb128(@intFromEnum(output_function_index)); |
| 1838 | } | 1764 | } |
| 1839 | | 1765 | |
| 1840 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1766 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1841 | } | 1767 | } |
| 1842 | | 1768 | |
| 1843 | fn emitStartSection(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), i: Wasm.OutputFunctionIndex) !void { | 1769 | fn emitStartSection(aw: *Writer.Allocating, i: Wasm.OutputFunctionIndex) !void { |
| 1844 | const header_offset = try reserveVecSectionHeader(gpa, bytes); | 1770 | const header_offset = try reserveVecSectionHeader(&aw.writer); |
| 1845 | replaceVecSectionHeader(bytes, header_offset, .start, @intFromEnum(i)); | 1771 | defer replaceVecSectionHeader(aw, header_offset, .start, @intFromEnum(i)); |
| 1846 | } | 1772 | } |
| 1847 | | 1773 | |
| 1848 | fn emitTagNameFunction( | 1774 | fn emitTagNameFunction( |
| 1849 | wasm: *Wasm, | 1775 | wasm: *Wasm, |
| 1850 | code: *std.ArrayListUnmanaged(u8), | 1776 | w: *Writer, |
| 1851 | table_base_addr: u32, | 1777 | table_base_addr: u32, |
| 1852 | table_index: u32, | 1778 | table_index: u32, |
| 1853 | enum_type_ip: InternPool.Index, | 1779 | enum_type_ip: InternPool.Index, |
| 1854 | ) !void { | 1780 | ) !void { |
| 1855 | const comp = wasm.base.comp; | 1781 | const comp = wasm.base.comp; |
| 1856 | const gpa = comp.gpa; | | |
| 1857 | const diags = &comp.link_diags; | 1782 | const diags = &comp.link_diags; |
| 1858 | const zcu = comp.zcu.?; | 1783 | const zcu = comp.zcu.?; |
| 1859 | const ip = &zcu.intern_pool; | 1784 | const ip = &zcu.intern_pool; |
| 1860 | const enum_type = ip.loadEnumType(enum_type_ip); | 1785 | const enum_type = ip.loadEnumType(enum_type_ip); |
| 1861 | const tag_values = enum_type.values.get(ip); | 1786 | const tag_values = enum_type.values.get(ip); |
| 1862 | | 1787 | |
| 1863 | try code.ensureUnusedCapacity(gpa, 7 * 5 + 6 + 1 * 6); | 1788 | try w.writeUleb128(0); // no locals |
| 1864 | appendReservedUleb32(code, 0); // no locals | | |
| 1865 | | 1789 | |
| 1866 | const slice_abi_size = 8; | 1790 | const slice_abi_size: u32 = 8; |
| 1867 | const encoded_alignment = @ctz(@as(u32, 4)); | | |
| 1868 | if (tag_values.len == 0) { | 1791 | if (tag_values.len == 0) { |
| 1869 | // Then it's auto-numbered and therefore a direct table lookup. | 1792 | // Then it's auto-numbered and therefore a direct table lookup. |
| 1870 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); | 1793 | try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); |
| 1871 | appendReservedUleb32(code, 0); | 1794 | try w.writeUleb128(0); |
| 1872 | | 1795 | |
| 1873 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); | 1796 | try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); |
| 1874 | appendReservedUleb32(code, 1); | 1797 | try w.writeUleb128(1); |
| 1875 | | 1798 | |
| 1876 | appendReservedI32Const(code, slice_abi_size); | 1799 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1877 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_mul)); | 1800 | if (std.math.isPowerOfTwo(slice_abi_size)) { |
| | 1801 | try w.writeLeb128(@as(i32, @bitCast(@as(u32, std.math.log2_int(u32, slice_abi_size))))); |
| | 1802 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_shl)); |
| | 1803 | } else { |
| | 1804 | try w.writeLeb128(@as(i32, @bitCast(slice_abi_size))); |
| | 1805 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_mul)); |
| | 1806 | } |
| 1878 | | 1807 | |
| 1879 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load)); | 1808 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); |
| 1880 | appendReservedUleb32(code, encoded_alignment); | 1809 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| 1881 | appendReservedUleb32(code, table_base_addr + table_index * 8); | 1810 | try w.writeLeb128(table_base_addr + slice_abi_size * table_index); |
| 1882 | | 1811 | |
| 1883 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_store)); | 1812 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); |
| 1884 | appendReservedUleb32(code, encoded_alignment); | 1813 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| 1885 | appendReservedUleb32(code, 0); | 1814 | try w.writeUleb128(0); |
| 1886 | } else { | 1815 | } else { |
| 1887 | const int_info = Zcu.Type.intInfo(.fromInterned(enum_type.tag_ty), zcu); | 1816 | const int_info = Zcu.Type.intInfo(.fromInterned(enum_type.tag_ty), zcu); |
| 1888 | const outer_block_type: std.wasm.BlockType = switch (int_info.bits) { | 1817 | const outer_block_type: std.wasm.BlockType = switch (int_info.bits) { |
| ... | @@ -1891,94 +1820,80 @@ fn emitTagNameFunction( | ... | @@ -1891,94 +1820,80 @@ fn emitTagNameFunction( |
| 1891 | else => return diags.fail("wasm linker does not yet implement @tagName for sparse enums with more than 64 bit integer tag types", .{}), | 1820 | else => return diags.fail("wasm linker does not yet implement @tagName for sparse enums with more than 64 bit integer tag types", .{}), |
| 1892 | }; | 1821 | }; |
| 1893 | | 1822 | |
| 1894 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); | 1823 | try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); |
| 1895 | appendReservedUleb32(code, 0); | 1824 | try w.writeUleb128(0); |
| 1896 | | 1825 | |
| 1897 | // Outer block that computes table offset. | 1826 | // Outer block that computes table offset. |
| 1898 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); | 1827 | try w.writeByte(@intFromEnum(std.wasm.Opcode.block)); |
| 1899 | code.appendAssumeCapacity(@intFromEnum(outer_block_type)); | 1828 | try w.writeByte(@intFromEnum(outer_block_type)); |
| 1900 | | 1829 | |
| 1901 | for (tag_values, 0..) |tag_value, tag_index| { | 1830 | for (tag_values, 0..) |tag_value, tag_index| { |
| 1902 | // block for this if case | 1831 | // block for this if case |
| 1903 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.block)); | 1832 | try w.writeByte(@intFromEnum(std.wasm.Opcode.block)); |
| 1904 | code.appendAssumeCapacity(@intFromEnum(std.wasm.BlockType.empty)); | 1833 | try w.writeByte(@intFromEnum(std.wasm.BlockType.empty)); |
| 1905 | | 1834 | |
| 1906 | // Tag value whose name should be returned. | 1835 | // Tag value whose name should be returned. |
| 1907 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.local_get)); | 1836 | try w.writeByte(@intFromEnum(std.wasm.Opcode.local_get)); |
| 1908 | appendReservedUleb32(code, 1); | 1837 | try w.writeUleb128(1); |
| 1909 | | 1838 | |
| 1910 | const val: Zcu.Value = .fromInterned(tag_value); | 1839 | const val: Zcu.Value = .fromInterned(tag_value); |
| 1911 | switch (outer_block_type) { | 1840 | switch (outer_block_type) { |
| 1912 | .i32 => { | 1841 | .i32 => { |
| 1913 | const x: u32 = switch (int_info.signedness) { | 1842 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| 1914 | .signed => @bitCast(@as(i32, @intCast(val.toSignedInt(zcu)))), | 1843 | try w.writeLeb128(@as(i32, switch (int_info.signedness) { |
| 1915 | .unsigned => @intCast(val.toUnsignedInt(zcu)), | 1844 | .signed => @intCast(val.toSignedInt(zcu)), |
| 1916 | }; | 1845 | .unsigned => @bitCast(@as(u32, @intCast(val.toUnsignedInt(zcu)))), |
| 1917 | appendReservedI32Const(code, x); | 1846 | })); |
| 1918 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_ne)); | 1847 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_ne)); |
| 1919 | }, | 1848 | }, |
| 1920 | .i64 => { | 1849 | .i64 => { |
| 1921 | const x: u64 = switch (int_info.signedness) { | 1850 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_const)); |
| 1922 | .signed => @bitCast(val.toSignedInt(zcu)), | 1851 | try w.writeLeb128(@as(i64, switch (int_info.signedness) { |
| 1923 | .unsigned => val.toUnsignedInt(zcu), | 1852 | .signed => val.toSignedInt(zcu), |
| 1924 | }; | 1853 | .unsigned => @bitCast(val.toUnsignedInt(zcu)), |
| 1925 | appendReservedI64Const(code, x); | 1854 | })); |
| 1926 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_ne)); | 1855 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_ne)); |
| 1927 | }, | 1856 | }, |
| 1928 | else => unreachable, | 1857 | else => unreachable, |
| 1929 | } | 1858 | } |
| 1930 | | 1859 | |
| 1931 | // if they're not equal, break out of current branch | 1860 | // if they're not equal, break out of current branch |
| 1932 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br_if)); | 1861 | try w.writeByte(@intFromEnum(std.wasm.Opcode.br_if)); |
| 1933 | appendReservedUleb32(code, 0); | 1862 | try w.writeUleb128(0); |
| 1934 | | 1863 | |
| 1935 | // Put the table offset of the result on the stack. | 1864 | // Put the table offset of the result on the stack. |
| 1936 | appendReservedI32Const(code, @intCast(tag_index * slice_abi_size)); | 1865 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i32_const)); |
| | 1866 | try w.writeLeb128(@as(i32, @bitCast(@as(u32, @intCast(slice_abi_size * tag_index))))); |
| 1937 | | 1867 | |
| 1938 | // break outside blocks | 1868 | // break outside blocks |
| 1939 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.br)); | 1869 | try w.writeByte(@intFromEnum(std.wasm.Opcode.br)); |
| 1940 | appendReservedUleb32(code, 1); | 1870 | try w.writeUleb128(1); |
| 1941 | | 1871 | |
| 1942 | // end the block for this case | 1872 | // end the block for this case |
| 1943 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1873 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1944 | } | 1874 | } |
| 1945 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.@"unreachable")); | 1875 | try w.writeByte(@intFromEnum(std.wasm.Opcode.@"unreachable")); |
| 1946 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1876 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1947 | | 1877 | |
| 1948 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_load)); | 1878 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_load)); |
| 1949 | appendReservedUleb32(code, encoded_alignment); | 1879 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| 1950 | appendReservedUleb32(code, table_base_addr + table_index * 8); | 1880 | try w.writeLeb128(table_base_addr + slice_abi_size * table_index); |
| 1951 | | 1881 | |
| 1952 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_store)); | 1882 | try w.writeByte(@intFromEnum(std.wasm.Opcode.i64_store)); |
| 1953 | appendReservedUleb32(code, encoded_alignment); | 1883 | try w.writeLeb128(comptime Alignment.@"4".toLog2Units()); |
| 1954 | appendReservedUleb32(code, 0); | 1884 | try w.writeUleb128(0); |
| 1955 | } | 1885 | } |
| 1956 | | 1886 | |
| 1957 | // End of the function body | 1887 | // End of the function body |
| 1958 | code.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1888 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1959 | } | | |
| 1960 | | | |
| 1961 | /// Writes an unsigned 32-bit integer as a LEB128-encoded 'i32.const' value. | | |
| 1962 | fn appendReservedI32Const(bytes: *std.ArrayListUnmanaged(u8), val: u32) void { | | |
| 1963 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); | | |
| 1964 | leb.writeIleb128(bytes.fixedWriter(), @as(i32, @bitCast(val))) catch unreachable; | | |
| 1965 | } | | |
| 1966 | | | |
| 1967 | /// Writes an unsigned 64-bit integer as a LEB128-encoded 'i64.const' value. | | |
| 1968 | fn appendReservedI64Const(bytes: *std.ArrayListUnmanaged(u8), val: u64) void { | | |
| 1969 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i64_const)); | | |
| 1970 | leb.writeIleb128(bytes.fixedWriter(), @as(i64, @bitCast(val))) catch unreachable; | | |
| 1971 | } | | |
| 1972 | | | |
| 1973 | fn appendReservedUleb32(bytes: *std.ArrayListUnmanaged(u8), val: u32) void { | | |
| 1974 | leb.writeUleb128(bytes.fixedWriter(), val) catch unreachable; | | |
| 1975 | } | 1889 | } |
| 1976 | | 1890 | |
| 1977 | fn appendGlobal(gpa: Allocator, bytes: *std.ArrayListUnmanaged(u8), mutable: u8, val: u32) Allocator.Error!void { | 1891 | fn appendGlobal(w: *Writer, mutable: bool, val: u32) Writer.Error!void { |
| 1978 | try bytes.ensureUnusedCapacity(gpa, 9); | 1892 | try w.writeAll(&.{ |
| 1979 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Valtype.i32)); | 1893 | @intFromEnum(std.wasm.Valtype.i32), |
| 1980 | bytes.appendAssumeCapacity(mutable); | 1894 | @intFromBool(mutable), |
| 1981 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.i32_const)); | 1895 | @intFromEnum(std.wasm.Opcode.i32_const), |
| 1982 | appendReservedUleb32(bytes, val); | 1896 | }); |
| 1983 | bytes.appendAssumeCapacity(@intFromEnum(std.wasm.Opcode.end)); | 1897 | try w.writeLeb128(val); |
| | 1898 | try w.writeByte(@intFromEnum(std.wasm.Opcode.end)); |
| 1984 | } | 1899 | } |