| ... | ... | @@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 463 | 463 | continue; |
| 464 | 464 | } |
| 465 | 465 | |
| 466 | | // TODO: Store undefined symbols so we can verify at the end if they've all been found |
| 467 | | // if not, emit an error (unless --allow-undefined is enabled). |
| 468 | 466 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index); |
| 469 | 467 | if (!maybe_existing.found_existing) { |
| 470 | 468 | maybe_existing.value_ptr.* = location; |
| ... | ... | @@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 483 | 481 | break :blk self.objects.items[file].name; |
| 484 | 482 | } else self.name; |
| 485 | 483 | |
| 486 | | if (!existing_sym.isUndefined()) { |
| 487 | | if (!symbol.isUndefined()) { |
| 484 | if (!existing_sym.isUndefined()) outer: { |
| 485 | if (!symbol.isUndefined()) inner: { |
| 486 | if (symbol.isWeak()) { |
| 487 | break :inner; // ignore the new symbol (discard it) |
| 488 | } |
| 489 | if (existing_sym.isWeak()) { |
| 490 | break :outer; // existing is weak, while new one isn't. Replace it. |
| 491 | } |
| 492 | // both are defined and weak, we have a symbol collision. |
| 488 | 493 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 489 | 494 | log.err(" first definition in '{s}'", .{existing_file_path}); |
| 490 | 495 | log.err(" next definition in '{s}'", .{object.name}); |
| ... | ... | @@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 502 | 507 | return error.SymbolMismatchingType; |
| 503 | 508 | } |
| 504 | 509 | |
| 510 | if (existing_sym.isUndefined() and symbol.isUndefined()) { |
| 511 | const existing_name = if (existing_loc.file) |file_index| blk: { |
| 512 | const obj = self.objects.items[file_index]; |
| 513 | const name_index = obj.findImport(symbol.tag.externalType(), existing_sym.index).module_name; |
| 514 | break :blk obj.string_table.get(name_index); |
| 515 | } else blk: { |
| 516 | const name_index = self.imports.get(existing_loc).?.module_name; |
| 517 | break :blk self.string_table.get(name_index); |
| 518 | }; |
| 519 | |
| 520 | const module_index = object.findImport(symbol.tag.externalType(), symbol.index).module_name; |
| 521 | const module_name = object.string_table.get(module_index); |
| 522 | if (!mem.eql(u8, existing_name, module_name)) { |
| 523 | log.err("symbol '{s}' module name mismatch. Expected '{s}', but found '{s}'", .{ |
| 524 | sym_name, |
| 525 | existing_name, |
| 526 | module_name, |
| 527 | }); |
| 528 | log.err(" first definition in '{s}'", .{existing_file_path}); |
| 529 | log.err(" next definition in '{s}'", .{object.name}); |
| 530 | return error.ModuleNameMismatch; |
| 531 | } |
| 532 | } |
| 533 | |
| 534 | if (existing_sym.tag == .global) { |
| 535 | const existing_ty = self.getGlobalType(existing_loc); |
| 536 | const new_ty = self.getGlobalType(location); |
| 537 | if (existing_ty.mutable != new_ty.mutable or existing_ty.valtype != new_ty.valtype) { |
| 538 | log.err("symbol '{s}' mismatching global types", .{sym_name}); |
| 539 | log.err(" first definition in '{s}'", .{existing_file_path}); |
| 540 | log.err(" next definition in '{s}'", .{object.name}); |
| 541 | return error.GlobalTypeMismatch; |
| 542 | } |
| 543 | } |
| 544 | |
| 545 | if (existing_sym.tag == .function) { |
| 546 | const existing_ty = self.getFunctionSignature(existing_loc); |
| 547 | const new_ty = self.getFunctionSignature(location); |
| 548 | if (!existing_ty.eql(new_ty)) { |
| 549 | log.err("symbol '{s}' mismatching function signatures.", .{sym_name}); |
| 550 | log.err(" expected signature {}, but found signature {}", .{ existing_ty, new_ty }); |
| 551 | log.err(" first definition in '{s}'", .{existing_file_path}); |
| 552 | log.err(" next definition in '{s}'", .{object.name}); |
| 553 | return error.FunctionSignatureMismatch; |
| 554 | } |
| 555 | } |
| 556 | |
| 505 | 557 | // when both symbols are weak, we skip overwriting |
| 506 | 558 | if (existing_sym.isWeak() and symbol.isWeak()) { |
| 507 | 559 | try self.discarded.put(self.base.allocator, location, existing_loc); |
| ... | ... | @@ -797,6 +849,46 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 797 | 849 | try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {}); |
| 798 | 850 | } |
| 799 | 851 | |
| 852 | /// From a given symbol location, returns its `wasm.GlobalType`. |
| 853 | /// Asserts the Symbol represents a global. |
| 854 | fn getGlobalType(self: *const Wasm, loc: SymbolLoc) wasm.GlobalType { |
| 855 | const symbol = loc.getSymbol(self); |
| 856 | assert(symbol.tag == .global); |
| 857 | const is_undefined = symbol.isUndefined(); |
| 858 | if (loc.file) |file_index| { |
| 859 | const obj: Object = self.objects.items[file_index]; |
| 860 | if (is_undefined) { |
| 861 | return obj.findImport(.global, symbol.index).kind.global; |
| 862 | } |
| 863 | return obj.globals[symbol.index].global_type; |
| 864 | } |
| 865 | if (is_undefined) { |
| 866 | return self.imports.get(loc).?.kind.global; |
| 867 | } |
| 868 | return self.wasm_globals.items[symbol.index].global_type; |
| 869 | } |
| 870 | |
| 871 | /// From a given symbol location, returns its `wasm.Type`. |
| 872 | /// Asserts the Symbol represents a function. |
| 873 | fn getFunctionSignature(self: *const Wasm, loc: SymbolLoc) wasm.Type { |
| 874 | const symbol = loc.getSymbol(self); |
| 875 | assert(symbol.tag == .function); |
| 876 | const is_undefined = symbol.isUndefined(); |
| 877 | if (loc.file) |file_index| { |
| 878 | const obj: Object = self.objects.items[file_index]; |
| 879 | if (is_undefined) { |
| 880 | const ty_index = obj.findImport(.function, symbol.index).kind.function; |
| 881 | return obj.func_types[ty_index]; |
| 882 | } |
| 883 | return obj.func_types[obj.functions[symbol.index].type_index]; |
| 884 | } |
| 885 | if (is_undefined) { |
| 886 | const ty_index = self.imports.get(loc).?.kind.function; |
| 887 | return self.func_types.items[ty_index]; |
| 888 | } |
| 889 | return self.func_types.items[self.functions.get(.{ .file = loc.file, .index = loc.index }).?.type_index]; |
| 890 | } |
| 891 | |
| 800 | 892 | /// Lowers a constant typed value to a local symbol and atom. |
| 801 | 893 | /// Returns the symbol index of the local |
| 802 | 894 | /// The given `decl` is the parent decl whom owns the constant. |