| ... | ... | @@ -651,7 +651,12 @@ fn resolveSymbolsInArchives(wasm: *Wasm) !void { |
| 651 | 651 | } |
| 652 | 652 | } |
| 653 | 653 | |
| 654 | | fn validateFeatures(wasm: *const Wasm, arena: Allocator) !void { |
| 654 | fn validateFeatures( |
| 655 | wasm: *const Wasm, |
| 656 | arena: Allocator, |
| 657 | to_emit: *[@typeInfo(std.Target.wasm.Feature).Enum.fields.len]bool, |
| 658 | emit_features_count: *u32, |
| 659 | ) !void { |
| 655 | 660 | const cpu_features = wasm.base.options.target.cpu.features; |
| 656 | 661 | const infer = cpu_features.isEmpty(); // when the user did not define any features, we infer them from linked objects. |
| 657 | 662 | var allowed = std.AutoHashMap(std.Target.wasm.Feature, void).init(arena); |
| ... | ... | @@ -755,6 +760,13 @@ fn validateFeatures(wasm: *const Wasm, arena: Allocator) !void { |
| 755 | 760 | if (!valid_feature_set) { |
| 756 | 761 | return error.InvalidFeatureSet; |
| 757 | 762 | } |
| 763 | |
| 764 | if (allowed.count() > 0) { |
| 765 | emit_features_count.* = allowed.count(); |
| 766 | for (to_emit) |*feature_enabled, feature_index| { |
| 767 | feature_enabled.* = allowed.contains(@intToEnum(std.Target.wasm.Feature, feature_index)); |
| 768 | } |
| 769 | } |
| 758 | 770 | } |
| 759 | 771 | |
| 760 | 772 | fn checkUndefinedSymbols(wasm: *const Wasm) !void { |
| ... | ... | @@ -2264,7 +2276,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2264 | 2276 | try wasm.resolveSymbolsInObject(@intCast(u16, object_index)); |
| 2265 | 2277 | } |
| 2266 | 2278 | |
| 2267 | | try wasm.validateFeatures(arena); |
| 2279 | var emit_features_count: u32 = 0; |
| 2280 | var enabled_features: [@typeInfo(std.Target.wasm.Feature).Enum.fields.len]bool = undefined; |
| 2281 | try wasm.validateFeatures(arena, &enabled_features, &emit_features_count); |
| 2268 | 2282 | try wasm.resolveSymbolsInArchives(); |
| 2269 | 2283 | try wasm.checkUndefinedSymbols(); |
| 2270 | 2284 | |
| ... | ... | @@ -2710,6 +2724,9 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod |
| 2710 | 2724 | } |
| 2711 | 2725 | |
| 2712 | 2726 | try emitProducerSection(&binary_bytes); |
| 2727 | if (emit_features_count > 0) { |
| 2728 | try emitFeaturesSection(&binary_bytes, &enabled_features, emit_features_count); |
| 2729 | } |
| 2713 | 2730 | } |
| 2714 | 2731 | |
| 2715 | 2732 | // Only when writing all sections executed properly we write the magic |
| ... | ... | @@ -2802,6 +2819,32 @@ fn emitProducerSection(binary_bytes: *std.ArrayList(u8)) !void { |
| 2802 | 2819 | ); |
| 2803 | 2820 | } |
| 2804 | 2821 | |
| 2822 | fn emitFeaturesSection(binary_bytes: *std.ArrayList(u8), enabled_features: []const bool, features_count: u32) !void { |
| 2823 | const header_offset = try reserveCustomSectionHeader(binary_bytes); |
| 2824 | |
| 2825 | const writer = binary_bytes.writer(); |
| 2826 | const target_features = "target_features"; |
| 2827 | try leb.writeULEB128(writer, @intCast(u32, target_features.len)); |
| 2828 | try writer.writeAll(target_features); |
| 2829 | |
| 2830 | try leb.writeULEB128(writer, features_count); |
| 2831 | for (enabled_features) |enabled, feature_index| { |
| 2832 | if (enabled) { |
| 2833 | const feature: types.Feature = .{ .prefix = .used, .tag = @intToEnum(types.Feature.Tag, feature_index) }; |
| 2834 | try leb.writeULEB128(writer, @enumToInt(feature.prefix)); |
| 2835 | const string = feature.toString(); |
| 2836 | try leb.writeULEB128(writer, @intCast(u32, string.len)); |
| 2837 | try writer.writeAll(string); |
| 2838 | } |
| 2839 | } |
| 2840 | |
| 2841 | try writeCustomSectionHeader( |
| 2842 | binary_bytes.items, |
| 2843 | header_offset, |
| 2844 | @intCast(u32, binary_bytes.items.len - header_offset - 6), |
| 2845 | ); |
| 2846 | } |
| 2847 | |
| 2805 | 2848 | fn emitNameSection(wasm: *Wasm, binary_bytes: *std.ArrayList(u8), arena: std.mem.Allocator) !void { |
| 2806 | 2849 | const Name = struct { |
| 2807 | 2850 | index: u32, |