Skip to content

Commit 9a5b054

Browse files
committed
Rework #8542 wrt. deterministic IDs via generateIdWithLoc()
1 parent 4b2c885 commit 9a5b054

5 files changed

Lines changed: 54 additions & 162 deletions

File tree

src/dmd/globals.d

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
module dmd.globals;
1414

1515
import core.stdc.stdint;
16+
import core.stdc.string;
1617
import dmd.root.array;
1718
import dmd.root.filename;
1819
import dmd.root.outbuffer;
@@ -469,6 +470,24 @@ nothrow:
469470
FileName.equals(filename, loc.filename);
470471
}
471472

473+
extern (D) bool opEquals(Loc loc) const pure
474+
{
475+
return charnum == loc.charnum &&
476+
linnum == loc.linnum &&
477+
FileName.equals(filename, loc.filename);
478+
}
479+
480+
extern (D) hash_t toHash() const pure
481+
{
482+
import dmd.root.hash : mixHash;
483+
484+
auto hash = hashOf(linnum);
485+
hash = mixHash(hash, hashOf(charnum));
486+
if (filename !is null)
487+
hash = mixHash(hash, hashOf(filename[0 .. strlen(filename)]));
488+
return hash;
489+
}
490+
472491
/******************
473492
* Returns:
474493
* true if Loc has been set to other than the default initialization

src/dmd/identifier.d

Lines changed: 29 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -125,18 +125,6 @@ nothrow:
125125

126126
extern (C++) __gshared StringTable stringtable;
127127

128-
/**
129-
A secondary string table is used to guarantee that we generate unique
130-
identifiers per module. See generateIdWithLoc and issues
131-
https://issues.dlang.org/show_bug.cgi?id=16995
132-
https://issues.dlang.org/show_bug.cgi?id=18097
133-
https://issues.dlang.org/show_bug.cgi?id=18111
134-
https://issues.dlang.org/show_bug.cgi?id=18880
135-
https://issues.dlang.org/show_bug.cgi?id=18868
136-
https://issues.dlang.org/show_bug.cgi?id=19058.
137-
*/
138-
private extern (C++) __gshared StringTable fullPathStringTable;
139-
140128
static Identifier generateId(const(char)* prefix)
141129
{
142130
__gshared size_t i;
@@ -166,75 +154,36 @@ nothrow:
166154
*/
167155
extern (D) static Identifier generateIdWithLoc(string prefix, const ref Loc loc)
168156
{
169-
import dmd.root.filename: absPathThen;
170-
171-
// see below for why we use absPathThen
172-
return loc.filename.absPathThen!((absPath)
157+
// generate `<prefix>_L<line>_C<col>`
158+
OutBuffer idBuf;
159+
idBuf.writestring(prefix);
160+
idBuf.writestring("_L");
161+
idBuf.print(loc.linnum);
162+
idBuf.writestring("_C");
163+
idBuf.print(loc.charnum);
164+
165+
/**
166+
* Make sure the identifiers are unique per module. See issues
167+
* https://issues.dlang.org/show_bug.cgi?id=16995
168+
* https://issues.dlang.org/show_bug.cgi?id=18097
169+
* https://issues.dlang.org/show_bug.cgi?id=18111
170+
* https://issues.dlang.org/show_bug.cgi?id=18880
171+
* https://issues.dlang.org/show_bug.cgi?id=18868
172+
* https://issues.dlang.org/show_bug.cgi?id=19058.
173+
*/
174+
static struct Key { Loc loc; string prefix; }
175+
__gshared uint[Key] counters;
176+
177+
const key = Key(loc, prefix);
178+
if (auto pCounter = key in counters)
173179
{
180+
idBuf.writestring("_");
181+
idBuf.print((*pCounter)++);
182+
}
183+
else
184+
counters[key] = 1;
174185

175-
// this block generates the "regular" identifier, i.e. if there are no collisions
176-
OutBuffer idBuf;
177-
idBuf.writestring(prefix);
178-
idBuf.writestring("_L");
179-
idBuf.print(loc.linnum);
180-
idBuf.writestring("_C");
181-
idBuf.print(loc.charnum);
182-
183-
// This block generates an identifier that is prefixed by the absolute path of the file
184-
// being compiled. The reason this is necessary is that we want unique identifiers per
185-
// module, but the identifiers are generated before the module information is available.
186-
// To guarantee that each generated identifier is unique without modules, we make them
187-
// unique to each absolute file path. This also makes it consistent even if the files
188-
// are compiled separately. See issues:
189-
// https://issues.dlang.org/show_bug.cgi?id=16995
190-
// https://issues.dlang.org/show_bug.cgi?id=18097
191-
// https://issues.dlang.org/show_bug.cgi?id=18111
192-
// https://issues.dlang.org/show_bug.cgi?id=18880
193-
// https://issues.dlang.org/show_bug.cgi?id=18868
194-
// https://issues.dlang.org/show_bug.cgi?id=19058.
195-
OutBuffer fullPathIdBuf;
196-
197-
if (absPath)
198-
{
199-
// replace characters that demangle can't handle
200-
for (auto ptr = absPath; *ptr != '\0'; ++ptr)
201-
{
202-
// see dmd.dmangle.isValidMangling
203-
// Unfortunately importing it leads to either build failures or cyclic dependencies
204-
// between modules.
205-
if (*ptr == '/' || *ptr == '\\' || *ptr == '.' || *ptr == '?' || *ptr == ':')
206-
*ptr = '_';
207-
}
208-
209-
fullPathIdBuf.writestring(absPath);
210-
fullPathIdBuf.writestring("_");
211-
}
212-
213-
fullPathIdBuf.writestring(idBuf.peekSlice());
214-
const fullPathIdLength = fullPathIdBuf.peekSlice().length;
215-
uint counter = 1;
216-
217-
// loop until we can't find the absolute path ~ identifier, adding a counter suffix each time
218-
while (fullPathStringTable.lookup(fullPathIdBuf.peekSlice()) !is null)
219-
{
220-
// Strip the counter suffix if any
221-
fullPathIdBuf.setsize(fullPathIdLength);
222-
// Add new counter suffix
223-
fullPathIdBuf.writestring("_");
224-
fullPathIdBuf.print(counter++);
225-
}
226-
227-
// `idStartIndex` is the start of the "true" identifier. We don't actually use the absolute
228-
// file path in the generated identifier since the module system makes sure that the fully
229-
// qualified name is unique.
230-
const idStartIndex = fullPathIdLength - idBuf.peekSlice().length;
231-
232-
// Remember the full path identifier to avoid possible future collisions
233-
fullPathStringTable.insert(fullPathIdBuf.peekSlice(),
234-
null);
235-
236-
return idPool(fullPathIdBuf.peekSlice()[idStartIndex .. $]);
237-
});
186+
return idPool(idBuf.peekSlice());
238187
}
239188

240189
/********************************************
@@ -305,8 +254,6 @@ nothrow:
305254

306255
static void initTable()
307256
{
308-
enum size = 28_000;
309-
stringtable._init(size);
310-
fullPathStringTable._init(size);
257+
stringtable._init(28_000);
311258
}
312259
}

src/dmd/identifier.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,6 @@ class Identifier : public RootObject
3737
int dyncast() const;
3838

3939
static StringTable stringtable;
40-
static StringTable fullPathStringTable;
4140
static Identifier *generateId(const char *prefix);
4241
static Identifier *generateId(const char *prefix, size_t i);
4342
static Identifier *idPool(const char *s, unsigned len);

src/dmd/root/filename.d

Lines changed: 0 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -926,80 +926,3 @@ version(Windows)
926926
}
927927

928928
}
929-
930-
version(Posix)
931-
{
932-
933-
/**
934-
Takes a callable F and applies it to the result of converting
935-
`fileName` to an absolute file path (char*)
936-
937-
Params:
938-
fileName = The file name to be converted to an absolute path
939-
Returns: Whatever `F` returns.
940-
*/
941-
auto absPathThen(alias F)(const(char)* fileName)
942-
{
943-
import core.sys.posix.stdlib: realpath, free;
944-
auto absPath = realpath(fileName, null /* realpath allocates */);
945-
scope(exit) free(absPath);
946-
return F(absPath);
947-
}
948-
}
949-
else
950-
{
951-
/**
952-
Takes a callable F and applies it to the result of converting
953-
`fileName` to an absolute file path (char*)
954-
955-
Params:
956-
fileName = The file name to be converted to an absolute path
957-
Returns: Whatever `F` returns.
958-
*/
959-
auto absPathThen(alias F)(const(char)* fileName)
960-
{
961-
import core.sys.windows.winnls: WideCharToMultiByte;
962-
import core.stdc.stdlib: malloc, free;
963-
964-
return fileName.extendedPathThen!((wpath) {
965-
// first find out how long the buffer must be to store the result
966-
const length = WideCharToMultiByte(0, // code page
967-
0, // flags
968-
wpath,
969-
-1, // wpath len, -1 is null terminated
970-
null, // multibyte output ptr
971-
0, // multibyte output length
972-
null, // default char
973-
null, // if used default char
974-
);
975-
976-
if(!length) return F((char*).init);
977-
978-
char[1024] buf = void;
979-
980-
scope multibyteBuf = length > buf.length
981-
? (cast(char*)malloc(length * char.sizeof))
982-
: &buf[0];
983-
scope (exit)
984-
{
985-
if (multibyteBuf != &buf[0])
986-
free(multibyteBuf);
987-
}
988-
989-
// now store the result
990-
const length2 = WideCharToMultiByte(0, // code page
991-
0, // flags
992-
wpath,
993-
-1, // wpath len, -1 is null terminated
994-
multibyteBuf,
995-
length,
996-
null, // default char
997-
null, // if used default char
998-
);
999-
1000-
assert(length == length2);
1001-
1002-
return F(multibyteBuf);
1003-
});
1004-
}
1005-
}

src/dmd/root/hash.d

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,15 +12,19 @@
1212

1313
module dmd.root.hash;
1414

15+
pure:
16+
nothrow:
17+
@nogc:
18+
1519
// MurmurHash2 was written by Austin Appleby, and is placed in the public
1620
// domain. The author hereby disclaims copyright to this source code.
1721
// https://sites.google.com/site/murmurhash/
18-
uint calcHash(const(char)* data, size_t len) pure nothrow @nogc
22+
uint calcHash(const(char)* data, size_t len)
1923
{
2024
return calcHash(cast(const(ubyte)*)data, len);
2125
}
2226

23-
uint calcHash(const(ubyte)* data, size_t len) pure nothrow @nogc
27+
uint calcHash(const(ubyte)* data, size_t len)
2428
{
2529
// 'm' and 'r' are mixing constants generated offline.
2630
// They're not really 'magic', they just happen to work well.

0 commit comments

Comments
 (0)