| ... | @@ -82,6 +82,16 @@ pub const GlobalImport = struct { | ... | @@ -82,6 +82,16 @@ pub const GlobalImport = struct { |
| 82 | mutable: bool, | 82 | mutable: bool, |
| 83 | }; | 83 | }; |
| 84 | | 84 | |
| | 85 | pub const TableImport = struct { |
| | 86 | module_name: Wasm.String, |
| | 87 | name: Wasm.String, |
| | 88 | limits_min: u32, |
| | 89 | limits_max: u32, |
| | 90 | limits_has_max: bool, |
| | 91 | limits_is_shared: bool, |
| | 92 | ref_type: std.wasm.RefType, |
| | 93 | }; |
| | 94 | |
| 85 | pub const DataSegmentFlags = enum(u32) { active, passive, active_memidx }; | 95 | pub const DataSegmentFlags = enum(u32) { active, passive, active_memidx }; |
| 86 | | 96 | |
| 87 | pub const SubsectionType = enum(u8) { | 97 | pub const SubsectionType = enum(u8) { |
| ... | @@ -115,7 +125,7 @@ pub const Symbol = struct { | ... | @@ -115,7 +125,7 @@ pub const Symbol = struct { |
| 115 | global_import: ScratchSpace.GlobalImportIndex, | 125 | global_import: ScratchSpace.GlobalImportIndex, |
| 116 | section: Wasm.ObjectSectionIndex, | 126 | section: Wasm.ObjectSectionIndex, |
| 117 | table: Wasm.ObjectTableIndex, | 127 | table: Wasm.ObjectTableIndex, |
| 118 | table_import: Wasm.TableImport.Index, | 128 | table_import: ScratchSpace.TableImportIndex, |
| 119 | }; | 129 | }; |
| 120 | }; | 130 | }; |
| 121 | | 131 | |
| ... | @@ -124,6 +134,7 @@ pub const ScratchSpace = struct { | ... | @@ -124,6 +134,7 @@ pub const ScratchSpace = struct { |
| 124 | func_type_indexes: std.ArrayListUnmanaged(FuncTypeIndex) = .empty, | 134 | func_type_indexes: std.ArrayListUnmanaged(FuncTypeIndex) = .empty, |
| 125 | func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty, | 135 | func_imports: std.ArrayListUnmanaged(FunctionImport) = .empty, |
| 126 | global_imports: std.ArrayListUnmanaged(GlobalImport) = .empty, | 136 | global_imports: std.ArrayListUnmanaged(GlobalImport) = .empty, |
| | 137 | table_imports: std.ArrayListUnmanaged(TableImport) = .empty, |
| 127 | symbol_table: std.ArrayListUnmanaged(Symbol) = .empty, | 138 | symbol_table: std.ArrayListUnmanaged(Symbol) = .empty, |
| 128 | segment_info: std.ArrayListUnmanaged(SegmentInfo) = .empty, | 139 | segment_info: std.ArrayListUnmanaged(SegmentInfo) = .empty, |
| 129 | exports: std.ArrayListUnmanaged(Export) = .empty, | 140 | exports: std.ArrayListUnmanaged(Export) = .empty, |
| ... | @@ -158,6 +169,15 @@ pub const ScratchSpace = struct { | ... | @@ -158,6 +169,15 @@ pub const ScratchSpace = struct { |
| 158 | } | 169 | } |
| 159 | }; | 170 | }; |
| 160 | | 171 | |
| | 172 | /// Index into `table_imports`. |
| | 173 | const TableImportIndex = enum(u32) { |
| | 174 | _, |
| | 175 | |
| | 176 | fn ptr(index: TableImportIndex, ss: *const ScratchSpace) *TableImport { |
| | 177 | return &ss.table_imports.items[@intFromEnum(index)]; |
| | 178 | } |
| | 179 | }; |
| | 180 | |
| 161 | /// Index into `func_types`. | 181 | /// Index into `func_types`. |
| 162 | const FuncTypeIndex = enum(u32) { | 182 | const FuncTypeIndex = enum(u32) { |
| 163 | _, | 183 | _, |
| ... | @@ -173,6 +193,7 @@ pub const ScratchSpace = struct { | ... | @@ -173,6 +193,7 @@ pub const ScratchSpace = struct { |
| 173 | ss.func_type_indexes.deinit(gpa); | 193 | ss.func_type_indexes.deinit(gpa); |
| 174 | ss.func_imports.deinit(gpa); | 194 | ss.func_imports.deinit(gpa); |
| 175 | ss.global_imports.deinit(gpa); | 195 | ss.global_imports.deinit(gpa); |
| | 196 | ss.table_imports.deinit(gpa); |
| 176 | ss.symbol_table.deinit(gpa); | 197 | ss.symbol_table.deinit(gpa); |
| 177 | ss.segment_info.deinit(gpa); | 198 | ss.segment_info.deinit(gpa); |
| 178 | ss.* = undefined; | 199 | ss.* = undefined; |
| ... | @@ -184,6 +205,7 @@ pub const ScratchSpace = struct { | ... | @@ -184,6 +205,7 @@ pub const ScratchSpace = struct { |
| 184 | ss.func_type_indexes.clearRetainingCapacity(); | 205 | ss.func_type_indexes.clearRetainingCapacity(); |
| 185 | ss.func_imports.clearRetainingCapacity(); | 206 | ss.func_imports.clearRetainingCapacity(); |
| 186 | ss.global_imports.clearRetainingCapacity(); | 207 | ss.global_imports.clearRetainingCapacity(); |
| | 208 | ss.table_imports.clearRetainingCapacity(); |
| 187 | ss.symbol_table.clearRetainingCapacity(); | 209 | ss.symbol_table.clearRetainingCapacity(); |
| 188 | ss.segment_info.clearRetainingCapacity(); | 210 | ss.segment_info.clearRetainingCapacity(); |
| 189 | } | 211 | } |
| ... | @@ -231,7 +253,7 @@ pub fn parse( | ... | @@ -231,7 +253,7 @@ pub fn parse( |
| 231 | var opt_features: ?Wasm.Feature.Set = null; | 253 | var opt_features: ?Wasm.Feature.Set = null; |
| 232 | var saw_linking_section = false; | 254 | var saw_linking_section = false; |
| 233 | var has_tls = false; | 255 | var has_tls = false; |
| 234 | var table_count: usize = 0; | 256 | var table_import_symbol_count: usize = 0; |
| 235 | while (pos < bytes.len) : (wasm.object_total_sections += 1) { | 257 | while (pos < bytes.len) : (wasm.object_total_sections += 1) { |
| 236 | const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections); | 258 | const section_index: Wasm.ObjectSectionIndex = @enumFromInt(wasm.object_total_sections); |
| 237 | | 259 | |
| ... | @@ -403,19 +425,19 @@ pub fn parse( | ... | @@ -403,19 +425,19 @@ pub fn parse( |
| 403 | } | 425 | } |
| 404 | }, | 426 | }, |
| 405 | .table => { | 427 | .table => { |
| 406 | table_count += 1; | | |
| 407 | const local_index, pos = readLeb(u32, bytes, pos); | 428 | const local_index, pos = readLeb(u32, bytes, pos); |
| 408 | if (symbol.flags.undefined) { | 429 | if (symbol.flags.undefined) { |
| 409 | const table_import: Wasm.TableImport.Index = @enumFromInt(table_imports_start + local_index); | 430 | table_import_symbol_count += 1; |
| | 431 | const table_import: ScratchSpace.TableImportIndex = @enumFromInt(local_index); |
| 410 | symbol.pointee = .{ .table_import = table_import }; | 432 | symbol.pointee = .{ .table_import = table_import }; |
| 411 | if (symbol.flags.explicit_name) { | 433 | if (symbol.flags.explicit_name) { |
| 412 | const name, pos = readBytes(bytes, pos); | 434 | const name, pos = readBytes(bytes, pos); |
| 413 | symbol.name = (try wasm.internString(name)).toOptional(); | 435 | symbol.name = (try wasm.internString(name)).toOptional(); |
| 414 | } else { | 436 | } else { |
| 415 | symbol.name = table_import.key(wasm).toOptional(); | 437 | symbol.name = table_import.ptr(ss).name.toOptional(); |
| 416 | } | 438 | } |
| 417 | } else { | 439 | } else { |
| 418 | symbol.pointee = .{ .table = @enumFromInt(tables_start + local_index) }; | 440 | symbol.pointee = .{ .table = @enumFromInt(tables_start + (local_index - ss.table_imports.items.len)) }; |
| 419 | const name, pos = readBytes(bytes, pos); | 441 | const name, pos = readBytes(bytes, pos); |
| 420 | symbol.name = (try wasm.internString(name)).toOptional(); | 442 | symbol.name = (try wasm.internString(name)).toOptional(); |
| 421 | } | 443 | } |
| ... | @@ -608,17 +630,14 @@ pub fn parse( | ... | @@ -608,17 +630,14 @@ pub fn parse( |
| 608 | .table => { | 630 | .table => { |
| 609 | const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos); | 631 | const ref_type, pos = readEnum(std.wasm.RefType, bytes, pos); |
| 610 | const limits, pos = readLimits(bytes, pos); | 632 | const limits, pos = readLimits(bytes, pos); |
| 611 | try wasm.object_table_imports.put(gpa, interned_name, .{ | 633 | try ss.table_imports.append(gpa, .{ |
| 612 | .flags = .{ | 634 | .name = interned_name, |
| 613 | .limits_has_max = limits.flags.has_max, | | |
| 614 | .limits_is_shared = limits.flags.is_shared, | | |
| 615 | .ref_type = .from(ref_type), | | |
| 616 | }, | | |
| 617 | .module_name = interned_module_name, | 635 | .module_name = interned_module_name, |
| 618 | .source_location = source_location, | | |
| 619 | .resolution = .unresolved, | | |
| 620 | .limits_min = limits.min, | 636 | .limits_min = limits.min, |
| 621 | .limits_max = limits.max, | 637 | .limits_max = limits.max, |
| | 638 | .limits_has_max = limits.flags.has_max, |
| | 639 | .limits_is_shared = limits.flags.is_shared, |
| | 640 | .ref_type = ref_type, |
| 622 | }); | 641 | }); |
| 623 | }, | 642 | }, |
| 624 | } | 643 | } |
| ... | @@ -697,7 +716,7 @@ pub fn parse( | ... | @@ -697,7 +716,7 @@ pub fn parse( |
| 697 | .name = try wasm.internString(name), | 716 | .name = try wasm.internString(name), |
| 698 | .pointee = switch (kind) { | 717 | .pointee = switch (kind) { |
| 699 | .function => .{ .function = @enumFromInt(functions_start + (index - ss.func_imports.items.len)) }, | 718 | .function => .{ .function = @enumFromInt(functions_start + (index - ss.func_imports.items.len)) }, |
| 700 | .table => .{ .table = @enumFromInt(tables_start + index) }, | 719 | .table => .{ .table = @enumFromInt(tables_start + (index - ss.table_imports.items.len)) }, |
| 701 | .memory => .{ .memory = @enumFromInt(memories_start + index) }, | 720 | .memory => .{ .memory = @enumFromInt(memories_start + index) }, |
| 702 | .global => .{ .global = @enumFromInt(globals_start + (index - ss.global_imports.items.len)) }, | 721 | .global => .{ .global = @enumFromInt(globals_start + (index - ss.global_imports.items.len)) }, |
| 703 | }, | 722 | }, |
| ... | @@ -884,7 +903,7 @@ pub fn parse( | ... | @@ -884,7 +903,7 @@ pub fn parse( |
| 884 | } | 903 | } |
| 885 | if (gop.value_ptr.module_name != ptr.module_name.toOptional()) { | 904 | if (gop.value_ptr.module_name != ptr.module_name.toOptional()) { |
| 886 | var err = try diags.addErrorWithNotes(2); | 905 | var err = try diags.addErrorWithNotes(2); |
| 887 | try err.addMsg("function symbol '{s}' mismatching module names", .{name.slice(wasm)}); | 906 | try err.addMsg("symbol '{s}' mismatching module names", .{name.slice(wasm)}); |
| 888 | if (gop.value_ptr.module_name.slice(wasm)) |module_name| { | 907 | if (gop.value_ptr.module_name.slice(wasm)) |module_name| { |
| 889 | gop.value_ptr.source_location.addNote(wasm, &err, "module '{s}' here", .{module_name}); | 908 | gop.value_ptr.source_location.addNote(wasm, &err, "module '{s}' here", .{module_name}); |
| 890 | } else { | 909 | } else { |
| ... | @@ -909,6 +928,49 @@ pub fn parse( | ... | @@ -909,6 +928,49 @@ pub fn parse( |
| 909 | }; | 928 | }; |
| 910 | } | 929 | } |
| 911 | }, | 930 | }, |
| | 931 | .table_import => |index| { |
| | 932 | const ptr = index.ptr(ss); |
| | 933 | const name = symbol.name.unwrap().?; |
| | 934 | if (symbol.flags.binding == .local) { |
| | 935 | diags.addParseError(path, "local symbol '{s}' references import", .{name.slice(wasm)}); |
| | 936 | continue; |
| | 937 | } |
| | 938 | const gop = try wasm.object_table_imports.getOrPut(gpa, name); |
| | 939 | if (gop.found_existing) { |
| | 940 | const existing_reftype = gop.value_ptr.flags.ref_type.to(); |
| | 941 | if (ptr.ref_type != existing_reftype) { |
| | 942 | var err = try diags.addErrorWithNotes(2); |
| | 943 | try err.addMsg("symbol '{s}' mismatching table reftypes", .{name.slice(wasm)}); |
| | 944 | gop.value_ptr.source_location.addNote(wasm, &err, "{s} here", .{@tagName(existing_reftype)}); |
| | 945 | err.addNote("{}: {s} here", .{ path, @tagName(ptr.ref_type) }); |
| | 946 | continue; |
| | 947 | } |
| | 948 | if (gop.value_ptr.module_name != ptr.module_name) { |
| | 949 | var err = try diags.addErrorWithNotes(2); |
| | 950 | try err.addMsg("symbol '{s}' mismatching module names", .{name.slice(wasm)}); |
| | 951 | gop.value_ptr.source_location.addNote(wasm, &err, "module '{s}' here", .{ |
| | 952 | gop.value_ptr.module_name.slice(wasm), |
| | 953 | }); |
| | 954 | err.addNote("{}: module '{s}' here", .{ path, ptr.module_name.slice(wasm) }); |
| | 955 | continue; |
| | 956 | } |
| | 957 | if (symbol.flags.binding == .strong) gop.value_ptr.flags.binding = .strong; |
| | 958 | if (!symbol.flags.visibility_hidden) gop.value_ptr.flags.visibility_hidden = false; |
| | 959 | if (symbol.flags.no_strip) gop.value_ptr.flags.no_strip = true; |
| | 960 | } else { |
| | 961 | gop.value_ptr.* = .{ |
| | 962 | .flags = symbol.flags, |
| | 963 | .module_name = ptr.module_name, |
| | 964 | .source_location = source_location, |
| | 965 | .resolution = .unresolved, |
| | 966 | .limits_min = ptr.limits_min, |
| | 967 | .limits_max = ptr.limits_max, |
| | 968 | }; |
| | 969 | gop.value_ptr.flags.limits_has_max = ptr.limits_has_max; |
| | 970 | gop.value_ptr.flags.limits_is_shared = ptr.limits_is_shared; |
| | 971 | gop.value_ptr.flags.ref_type = .from(ptr.ref_type); |
| | 972 | } |
| | 973 | }, |
| 912 | .function => |index| { | 974 | .function => |index| { |
| 913 | assert(!symbol.flags.undefined); | 975 | assert(!symbol.flags.undefined); |
| 914 | const ptr = index.ptr(wasm); | 976 | const ptr = index.ptr(wasm); |
| ... | @@ -951,15 +1013,6 @@ pub fn parse( | ... | @@ -951,15 +1013,6 @@ pub fn parse( |
| 951 | } | 1013 | } |
| 952 | }, | 1014 | }, |
| 953 | | 1015 | |
| 954 | .table_import => |i| { | | |
| 955 | const ptr = i.value(wasm); | | |
| 956 | assert(i.key(wasm).toOptional() == symbol.name); // TODO | | |
| 957 | ptr.flags = symbol.flags; | | |
| 958 | if (symbol.flags.undefined and symbol.flags.binding == .local) { | | |
| 959 | const name = i.key(wasm).slice(wasm); | | |
| 960 | diags.addParseError(path, "local symbol '{s}' references import", .{name}); | | |
| 961 | } | | |
| 962 | }, | | |
| 963 | inline .global, .table => |i| { | 1016 | inline .global, .table => |i| { |
| 964 | const ptr = i.ptr(wasm); | 1017 | const ptr = i.ptr(wasm); |
| 965 | ptr.name = symbol.name; | 1018 | ptr.name = symbol.name; |
| ... | @@ -1016,31 +1069,30 @@ pub fn parse( | ... | @@ -1016,31 +1069,30 @@ pub fn parse( |
| 1016 | | 1069 | |
| 1017 | // Check for indirect function table in case of an MVP object file. | 1070 | // Check for indirect function table in case of an MVP object file. |
| 1018 | legacy_indirect_function_table: { | 1071 | legacy_indirect_function_table: { |
| 1019 | const table_import_names = wasm.object_table_imports.keys()[table_imports_start..]; | | |
| 1020 | const table_import_values = wasm.object_table_imports.values()[table_imports_start..]; | | |
| 1021 | // If there is a symbol for each import table, this is not a legacy object file. | 1072 | // If there is a symbol for each import table, this is not a legacy object file. |
| 1022 | if (table_import_names.len == table_count) break :legacy_indirect_function_table; | 1073 | if (ss.table_imports.items.len == table_import_symbol_count) break :legacy_indirect_function_table; |
| 1023 | if (table_count != 0) { | 1074 | if (table_import_symbol_count != 0) { |
| 1024 | return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{ | 1075 | return diags.failParse(path, "expected a table entry symbol for each of the {d} table(s), but instead got {d} symbols.", .{ |
| 1025 | table_import_names.len, table_count, | 1076 | ss.table_imports.items.len, table_import_symbol_count, |
| 1026 | }); | 1077 | }); |
| 1027 | } | 1078 | } |
| 1028 | // MVP object files cannot have any table definitions, only | 1079 | // MVP object files cannot have any table definitions, only imports |
| 1029 | // imports (for the indirect function table). | 1080 | // (for the indirect function table). |
| 1030 | const tables = wasm.object_tables.items[tables_start..]; | 1081 | const tables = wasm.object_tables.items[tables_start..]; |
| 1031 | if (tables.len > 0) { | 1082 | if (tables.len > 0) { |
| 1032 | return diags.failParse(path, "table definition without representing table symbols", .{}); | 1083 | return diags.failParse(path, "table definition without representing table symbols", .{}); |
| 1033 | } | 1084 | } |
| 1034 | if (table_import_names.len != 1) { | 1085 | if (ss.table_imports.items.len != 1) { |
| 1035 | return diags.failParse(path, "found more than one table import, but no representing table symbols", .{}); | 1086 | return diags.failParse(path, "found more than one table import, but no representing table symbols", .{}); |
| 1036 | } | 1087 | } |
| 1037 | const table_import_name = table_import_names[0]; | 1088 | const table_import_name = ss.table_imports.items[0].name; |
| 1038 | if (table_import_name != wasm.preloaded_strings.__indirect_function_table) { | 1089 | if (table_import_name != wasm.preloaded_strings.__indirect_function_table) { |
| 1039 | return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{ | 1090 | return diags.failParse(path, "non-indirect function table import '{s}' is missing a corresponding symbol", .{ |
| 1040 | table_import_name.slice(wasm), | 1091 | table_import_name.slice(wasm), |
| 1041 | }); | 1092 | }); |
| 1042 | } | 1093 | } |
| 1043 | table_import_values[0].flags = .{ | 1094 | const ptr = wasm.object_table_imports.getPtr(table_import_name).?; |
| | 1095 | ptr.flags = .{ |
| 1044 | .undefined = true, | 1096 | .undefined = true, |
| 1045 | .no_strip = true, | 1097 | .no_strip = true, |
| 1046 | }; | 1098 | }; |