Commit 80b70470c0

Noam Preil <pleasantatk@gmail.com>
2020-06-28 03:50:59
Stage2/Module: Add symbol -> export lookup table
1 parent ffca156
Changed files (1)
src-self-hosted
src-self-hosted/Module.zig
@@ -32,6 +32,9 @@ bin_file_path: []const u8,
 /// Decl pointers to details about them being exported.
 /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
 decl_exports: std.AutoHashMap(*Decl, []*Export),
+/// We track which export is associated with the given symbol name for quick
+/// detection of symbol collisions.
+symbol_exports: std.StringHashMap(*Export),
 /// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
 /// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
 /// is performing the export of another Decl.
@@ -772,6 +775,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module {
         .optimize_mode = options.optimize_mode,
         .decl_table = DeclTable.init(gpa),
         .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa),
+        .symbol_exports = std.StringHashMap(*Export).init(gpa),
         .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa),
         .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa),
         .failed_files = std.AutoHashMap(*Scope, *ErrorMsg).init(gpa),
@@ -829,6 +833,7 @@ pub fn deinit(self: *Module) void {
         }
         self.export_owners.deinit();
     }
+    self.symbol_exports.deinit();
     self.root_scope.destroy(allocator);
     self.* = undefined;
 }
@@ -1869,6 +1874,7 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
         if (self.failed_exports.remove(exp)) |entry| {
             entry.value.destroy(self.allocator);
         }
+        _ = self.symbol_exports.remove(exp.options.name);
         self.allocator.destroy(exp);
     }
     self.allocator.free(kv.value);
@@ -2104,20 +2110,6 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
         else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
     }
 
-    var already_exported = false;
-    {
-        var it = self.decl_exports.iterator();
-        while (it.next()) |kv| {
-            const export_list = kv.value;
-            for (export_list) |e| {
-                if (std.mem.eql(u8, e.options.name, symbol_name)) {
-                    already_exported = true;
-                    break;
-                }
-            }
-        }
-    }
-
     try self.decl_exports.ensureCapacity(self.decl_exports.size + 1);
     try self.export_owners.ensureCapacity(self.export_owners.size + 1);
 
@@ -2153,7 +2145,7 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
     de_gop.kv.value[de_gop.kv.value.len - 1] = new_export;
     errdefer de_gop.kv.value = self.allocator.shrink(de_gop.kv.value, de_gop.kv.value.len - 1);
 
-    if (already_exported) {
+    if (self.symbol_exports.get(symbol_name)) |_| {
         try self.failed_exports.ensureCapacity(self.failed_exports.size + 1);
         self.failed_exports.putAssumeCapacityNoClobber(new_export, try ErrorMsg.create(
             self.allocator,
@@ -2161,9 +2153,12 @@ fn analyzeExport(self: *Module, scope: *Scope, src: usize, symbol_name: []const
             "exported symbol collision: {}",
             .{symbol_name},
         ));
+        // TODO: add a note
         new_export.status = .failed;
         return;
     }
+
+    try self.symbol_exports.putNoClobber(symbol_name, new_export);
     self.bin_file.updateDeclExports(self, exported_decl, de_gop.kv.value) catch |err| switch (err) {
         error.OutOfMemory => return error.OutOfMemory,
         else => {