| ... | @@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -463,8 +463,6 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 463 | continue; | 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 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index); | 466 | const maybe_existing = try self.globals.getOrPut(self.base.allocator, sym_name_index); |
| 469 | if (!maybe_existing.found_existing) { | 467 | if (!maybe_existing.found_existing) { |
| 470 | maybe_existing.value_ptr.* = location; | 468 | maybe_existing.value_ptr.* = location; |
| ... | @@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -483,8 +481,15 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 483 | break :blk self.objects.items[file].name; | 481 | break :blk self.objects.items[file].name; |
| 484 | } else self.name; | 482 | } else self.name; |
| 485 | | 483 | |
| 486 | if (!existing_sym.isUndefined()) { | 484 | if (!existing_sym.isUndefined()) outer: { |
| 487 | if (!symbol.isUndefined()) { | 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 | log.err("symbol '{s}' defined multiple times", .{sym_name}); | 493 | log.err("symbol '{s}' defined multiple times", .{sym_name}); |
| 489 | log.err(" first definition in '{s}'", .{existing_file_path}); | 494 | log.err(" first definition in '{s}'", .{existing_file_path}); |
| 490 | log.err(" next definition in '{s}'", .{object.name}); | 495 | log.err(" next definition in '{s}'", .{object.name}); |
| ... | @@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { | ... | @@ -502,6 +507,53 @@ fn resolveSymbolsInObject(self: *Wasm, object_index: u16) !void { |
| 502 | return error.SymbolMismatchingType; | 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 | // when both symbols are weak, we skip overwriting | 557 | // when both symbols are weak, we skip overwriting |
| 506 | if (existing_sym.isWeak() and symbol.isWeak()) { | 558 | if (existing_sym.isWeak() and symbol.isWeak()) { |
| 507 | try self.discarded.put(self.base.allocator, location, existing_loc); | 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,6 +849,46 @@ fn finishUpdateDecl(self: *Wasm, decl: *Module.Decl, code: []const u8) !void { |
| 797 | try self.resolved_symbols.put(self.base.allocator, atom.symbolLoc(), {}); | 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 | /// Lowers a constant typed value to a local symbol and atom. | 892 | /// Lowers a constant typed value to a local symbol and atom. |
| 801 | /// Returns the symbol index of the local | 893 | /// Returns the symbol index of the local |
| 802 | /// The given `decl` is the parent decl whom owns the constant. | 894 | /// The given `decl` is the parent decl whom owns the constant. |