Use string interning for a very nice speed boost

This commit is contained in:
Hackerpilot 2014-05-18 01:59:02 -07:00
parent 7eb952e0e5
commit ae91019ab4
13 changed files with 184 additions and 101 deletions

View File

@ -21,16 +21,17 @@ module actypes;
import std.algorithm; import std.algorithm;
import std.array; import std.array;
import std.container; import std.container;
import std.stdio; //import std.stdio;
import std.typecons; import std.typecons;
import std.allocator; import std.allocator;
import containers.karytree; import containers.ttree;
import containers.unrolledlist; import containers.unrolledlist;
import containers.slist; import containers.slist;
import std.d.lexer; import std.d.lexer;
import messages; import messages;
import string_interning;
/** /**
* Any special information about a variable declaration symbol. * Any special information about a variable declaration symbol.
@ -62,7 +63,7 @@ public:
*/ */
this(string name) this(string name)
{ {
this.name = name; this.name = name is null ? name : internString(name);
} }
/** /**
@ -72,7 +73,7 @@ public:
*/ */
this(string name, CompletionKind kind) this(string name, CompletionKind kind)
{ {
this.name = name; this.name = name is null ? name : internString(name);
this.kind = kind; this.kind = kind;
} }
@ -84,16 +85,18 @@ public:
*/ */
this(string name, CompletionKind kind, ACSymbol* type) this(string name, CompletionKind kind, ACSymbol* type)
{ {
this.name = name; this.name = name is null ? name : internString(name);
this.kind = kind; this.kind = kind;
this.type = type; this.type = type;
} }
int opCmp(ref const ACSymbol other) const int opCmp(ref const ACSymbol other) const
{ {
if (name < other.name) // Compare the pointers because the strings have been interned.
// Identical strings MUST have the same address
if (name.ptr < other.name.ptr)
return -1; return -1;
if (name > other.name) if (name.ptr > other.name.ptr)
return 1; return 1;
return 0; return 0;
} }
@ -111,7 +114,7 @@ public:
* Symbols that compose this symbol, such as enum members, class variables, * Symbols that compose this symbol, such as enum members, class variables,
* methods, etc. * methods, etc.
*/ */
KAryTree!(ACSymbol*, true, "a < b", false) parts; TTree!(ACSymbol*, true, "a < b", false) parts;
/** /**
* Symbol's name * Symbol's name
@ -275,7 +278,7 @@ struct Scope
size_t endLocation; size_t endLocation;
/// Symbols contained in this scope /// Symbols contained in this scope
KAryTree!(ACSymbol*, true, "a < b", false) symbols; TTree!(ACSymbol*, true, "a < b", false) symbols;
} }
/** /**
@ -297,33 +300,94 @@ struct ImportInformation
/** /**
* Symbols for the built in types * Symbols for the built in types
*/ */
KAryTree!(ACSymbol*, true) builtinSymbols; TTree!(ACSymbol*, true, "a < b", false) builtinSymbols;
/** /**
* Array properties * Array properties
*/ */
KAryTree!(ACSymbol*, true) arraySymbols; TTree!(ACSymbol*, true, "a < b", false) arraySymbols;
/** /**
* Associative array properties * Associative array properties
*/ */
KAryTree!(ACSymbol*, true) assocArraySymbols; TTree!(ACSymbol*, true, "a < b", false) assocArraySymbols;
/** /**
* Enum, union, class, and interface properties * Enum, union, class, and interface properties
*/ */
KAryTree!(ACSymbol*, true) aggregateSymbols; TTree!(ACSymbol*, true, "a < b", false) aggregateSymbols;
/** /**
* Class properties * Class properties
*/ */
KAryTree!(ACSymbol*, true) classSymbols; TTree!(ACSymbol*, true, "a < b", false) classSymbols;
private immutable(string[24]) builtinTypeNames;
string getBuiltinTypeName(IdType id)
{
switch (id)
{
case tok!"int": return builtinTypeNames[0];
case tok!"uint": return builtinTypeNames[1];
case tok!"double": return builtinTypeNames[2];
case tok!"idouble": return builtinTypeNames[3];
case tok!"float": return builtinTypeNames[4];
case tok!"ifloat": return builtinTypeNames[5];
case tok!"short": return builtinTypeNames[6];
case tok!"ushort": return builtinTypeNames[7];
case tok!"long": return builtinTypeNames[8];
case tok!"ulong": return builtinTypeNames[9];
case tok!"char": return builtinTypeNames[10];
case tok!"wchar": return builtinTypeNames[11];
case tok!"dchar": return builtinTypeNames[12];
case tok!"bool": return builtinTypeNames[13];
case tok!"void": return builtinTypeNames[14];
case tok!"cent": return builtinTypeNames[15];
case tok!"ucent": return builtinTypeNames[16];
case tok!"real": return builtinTypeNames[17];
case tok!"ireal": return builtinTypeNames[18];
case tok!"byte": return builtinTypeNames[19];
case tok!"ubyte": return builtinTypeNames[20];
case tok!"cdouble": return builtinTypeNames[21];
case tok!"cfloat": return builtinTypeNames[22];
case tok!"creal": return builtinTypeNames[23];
default: assert (false);
}
}
/** /**
* Initializes builtin types and the various properties of builtin types * Initializes builtin types and the various properties of builtin types
*/ */
static this() static this()
{ {
builtinTypeNames[0] = internString("int");
builtinTypeNames[1] = internString("uint");
builtinTypeNames[2] = internString("double");
builtinTypeNames[3] = internString("idouble");
builtinTypeNames[4] = internString("float");
builtinTypeNames[5] = internString("ifloat");
builtinTypeNames[6] = internString("short");
builtinTypeNames[7] = internString("ushort");
builtinTypeNames[8] = internString("long");
builtinTypeNames[9] = internString("ulong");
builtinTypeNames[10] = internString("char");
builtinTypeNames[11] = internString("wchar");
builtinTypeNames[12] = internString("dchar");
builtinTypeNames[13] = internString("bool");
builtinTypeNames[14] = internString("void");
builtinTypeNames[15] = internString("cent");
builtinTypeNames[16] = internString("ucent");
builtinTypeNames[17] = internString("real");
builtinTypeNames[18] = internString("ireal");
builtinTypeNames[19] = internString("byte");
builtinTypeNames[20] = internString("ubyte");
builtinTypeNames[21] = internString("cdouble");
builtinTypeNames[22] = internString("cfloat");
builtinTypeNames[23] = internString("creal");
auto bool_ = allocate!ACSymbol(Mallocator.it, "bool", CompletionKind.keyword); auto bool_ = allocate!ACSymbol(Mallocator.it, "bool", CompletionKind.keyword);
auto int_ = allocate!ACSymbol(Mallocator.it, "int", CompletionKind.keyword); auto int_ = allocate!ACSymbol(Mallocator.it, "int", CompletionKind.keyword);
auto long_ = allocate!ACSymbol(Mallocator.it, "long", CompletionKind.keyword); auto long_ = allocate!ACSymbol(Mallocator.it, "long", CompletionKind.keyword);
@ -492,5 +556,10 @@ static this()
builtinSymbols.insert(real_); builtinSymbols.insert(real_);
builtinSymbols.insert(ucent_); builtinSymbols.insert(ucent_);
builtinSymbols.insert(void_); builtinSymbols.insert(void_);
// writeln(">>Builtin symbols");
// foreach (symbol; builtinSymbols[])
// writeln(symbol.name, " ", symbol.name.ptr);
// writeln("<<Builtin symbols");
} }

View File

@ -166,12 +166,10 @@ AutocompleteResponse complete(const AutocompleteRequest request)
case tok!"]": case tok!"]":
case tok!"this": case tok!"this":
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16))); auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
shared(StringCache)* cache = new shared StringCache(StringCache.defaultBucketCount);
Scope* completionScope = generateAutocompleteTrees(tokenArray, Scope* completionScope = generateAutocompleteTrees(tokenArray,
"stdin", allocator, semanticAllocator, cache); "stdin", allocator, semanticAllocator);
scope(exit) typeid(Scope).destroy(completionScope); scope(exit) typeid(Scope).destroy(completionScope);
auto expression = getExpression(beforeTokens); response.setCompletions(completionScope, getExpression(beforeTokens),
response.setCompletions(completionScope, expression,
request.cursorPosition, CompletionType.identifiers, partial); request.cursorPosition, CompletionType.identifiers, partial);
break; break;
case tok!"(": case tok!"(":
@ -199,7 +197,7 @@ auto getTokensBeforeCursor(const(ubyte[]) sourceCode, size_t cursorPosition,
{ {
LexerConfig config; LexerConfig config;
config.fileName = "stdin"; config.fileName = "stdin";
shared(StringCache)* cache = new shared StringCache(StringCache.defaultBucketCount); StringCache* cache = new StringCache(StringCache.defaultBucketCount);
auto tokens = byToken(cast(ubyte[]) sourceCode, config, cache); auto tokens = byToken(cast(ubyte[]) sourceCode, config, cache);
tokenArray = tokens.array(); tokenArray = tokens.array();
auto sortedTokens = assumeSorted(tokenArray); auto sortedTokens = assumeSorted(tokenArray);
@ -221,9 +219,8 @@ ACSymbol*[] getSymbolsForCompletion(const AutocompleteRequest request,
auto beforeTokens = getTokensBeforeCursor(request.sourceCode, auto beforeTokens = getTokensBeforeCursor(request.sourceCode,
request.cursorPosition, tokenArray); request.cursorPosition, tokenArray);
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16))); auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
shared(StringCache)* cache = new shared StringCache(StringCache.defaultBucketCount);
Scope* completionScope = generateAutocompleteTrees(tokenArray, Scope* completionScope = generateAutocompleteTrees(tokenArray,
"stdin", allocator, semanticAllocator, cache); "stdin", allocator, semanticAllocator);
scope(exit) typeid(Scope).destroy(completionScope); scope(exit) typeid(Scope).destroy(completionScope);
auto expression = getExpression(beforeTokens); auto expression = getExpression(beforeTokens);
return getSymbolsByTokenChain(completionScope, expression, return getSymbolsByTokenChain(completionScope, expression,
@ -273,9 +270,8 @@ AutocompleteResponse parenCompletion(T)(T beforeTokens,
case tok!")": case tok!")":
case tok!"]": case tok!"]":
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16))); auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024*16)));
shared(StringCache)* cache = new shared StringCache(StringCache.defaultBucketCount);
Scope* completionScope = generateAutocompleteTrees(tokenArray, Scope* completionScope = generateAutocompleteTrees(tokenArray,
"stdin", allocator, semanticAllocator, cache); "stdin", allocator, semanticAllocator);
scope(exit) typeid(Scope).destroy(completionScope); scope(exit) typeid(Scope).destroy(completionScope);
auto expression = getExpression(beforeTokens[0 .. $ - 1]); auto expression = getExpression(beforeTokens[0 .. $ - 1]);
response.setCompletions(completionScope, expression, response.setCompletions(completionScope, expression,
@ -587,7 +583,7 @@ T getExpression(T)(T beforeTokens)
case tok!"identifier": case tok!"identifier":
if (hasSpecialPrefix) if (hasSpecialPrefix)
i++; i++;
break expressionLoop; break;
case tok!".": case tok!".":
break; break;
case tok!"*": case tok!"*":

View File

@ -1,3 +1,3 @@
dmd -wi client.d messages.d stupidlog.d msgpack-d/src/msgpack.d -Imsgpack-d/src -release -inline -O -ofdcd-client dmd -wi client.d messages.d stupidlog.d msgpack-d/src/msgpack.d -Imsgpack-d/src -release -inline -O -ofdcd-client
dmd actypes.d conversion/astconverter.d conversion/first.d conversion/second.d conversion/third.d autocomplete.d constants.d messages.d modulecache.d semantic.d server.d stupidlog.d dscanner/std/d/ast.d dscanner/std/d/entities.d dscanner/std/d/lexer.d dscanner/std/d/parser.d dscanner/std/lexer.d dscanner/std/allocator.d dscanner/formatter.d containers/src/memory/appender.d containers/src/memory/allocators.d containers/src/containers/dynamicarray.d containers/src/containers/karytree.d containers/src/containers/hashset.d containers/src/containers/unrolledlist.d containers/src/containers/internal/hash.d msgpack-d/src/msgpack.d -Icontainers/src -Imsgpack-d/src -Idscanner -wi -g -O -release -ofdcd-server dmd actypes.d conversion/astconverter.d conversion/first.d conversion/second.d conversion/third.d autocomplete.d constants.d messages.d modulecache.d semantic.d server.d stupidlog.d string_interning.d dscanner/std/d/ast.d dscanner/std/d/entities.d dscanner/std/d/lexer.d dscanner/std/d/parser.d dscanner/std/lexer.d dscanner/std/allocator.d dscanner/formatter.d containers/src/memory/appender.d containers/src/memory/allocators.d containers/src/containers/dynamicarray.d containers/src/containers/karytree.d containers/src/containers/hashset.d containers/src/containers/unrolledlist.d containers/src/containers/internal/hash.d msgpack-d/src/msgpack.d -Icontainers/src -Imsgpack-d/src -Idscanner -wi -g -O -release -ofdcd-server

View File

@ -22,6 +22,7 @@ dmd\
semantic.d\ semantic.d\
server.d\ server.d\
stupidlog.d\ stupidlog.d\
string_interning.d\
dscanner/std/d/ast.d\ dscanner/std/d/ast.d\
dscanner/std/d/entities.d\ dscanner/std/d/entities.d\
dscanner/std/d/lexer.d\ dscanner/std/d/lexer.d\
@ -32,7 +33,7 @@ dmd\
containers/src/memory/allocators.d\ containers/src/memory/allocators.d\
containers/src/memory/appender.d\ containers/src/memory/appender.d\
containers/src/containers/dynamicarray.d\ containers/src/containers/dynamicarray.d\
containers/src/containers/karytree.d\ containers/src/containers/ttree.d\
containers/src/containers/unrolledlist.d\ containers/src/containers/unrolledlist.d\
containers/src/containers/hashset.d\ containers/src/containers/hashset.d\
containers/src/containers/internal/hash.d\ containers/src/containers/internal/hash.d\
@ -41,7 +42,7 @@ dmd\
-Icontainers/src\ -Icontainers/src\
-Imsgpack-d/src\ -Imsgpack-d/src\
-Idscanner\ -Idscanner\
-wi -O -release -inline\ -wi -O -release\
-ofdcd-server -ofdcd-server
#gdc client.d\ #gdc client.d\

@ -1 +1 @@
Subproject commit 819133564a8ebb99672d08774e6731e860e2d103 Subproject commit dfb5bec85daad42752074b5206f5f78c03147c97

View File

@ -30,11 +30,10 @@ import std.d.parser;
import std.typecons; import std.typecons;
Scope* generateAutocompleteTrees(const(Token)[] tokens, string symbolFile, Scope* generateAutocompleteTrees(const(Token)[] tokens, string symbolFile,
CAllocator symbolAllocator, CAllocator semanticAllocator, CAllocator symbolAllocator, CAllocator semanticAllocator)
shared(StringCache)* cache)
{ {
Module m = parseModule(tokens, "editor buffer", semanticAllocator, &doesNothing); Module m = parseModule(tokens, "editor buffer", semanticAllocator, &doesNothing);
auto first = scoped!FirstPass(m, symbolFile, cache, symbolAllocator, auto first = scoped!FirstPass(m, symbolFile, symbolAllocator,
semanticAllocator); semanticAllocator);
first.run(); first.run();

View File

@ -30,6 +30,7 @@ import std.d.lexer;
import std.typecons; import std.typecons;
import stupidlog; import stupidlog;
import containers.unrolledlist; import containers.unrolledlist;
import string_interning;
/** /**
* First Pass handles the following: * First Pass handles the following:
@ -46,8 +47,8 @@ import containers.unrolledlist;
*/ */
final class FirstPass : ASTVisitor final class FirstPass : ASTVisitor
{ {
this(Module mod, string symbolFile, shared(StringCache)* stringCache, this(Module mod, string symbolFile, CAllocator symbolAllocator,
CAllocator symbolAllocator, CAllocator semanticAllocator) CAllocator semanticAllocator)
in in
{ {
assert (symbolAllocator); assert (symbolAllocator);
@ -56,7 +57,6 @@ final class FirstPass : ASTVisitor
{ {
this.mod = mod; this.mod = mod;
this.symbolFile = symbolFile; this.symbolFile = symbolFile;
this.stringCache = stringCache;
this.symbolAllocator = symbolAllocator; this.symbolAllocator = symbolAllocator;
this.semanticAllocator = semanticAllocator; this.semanticAllocator = semanticAllocator;
} }
@ -168,7 +168,7 @@ final class FirstPass : ASTVisitor
{ {
// Log.trace(__FUNCTION__, " ", typeof(bc).stringof); // Log.trace(__FUNCTION__, " ", typeof(bc).stringof);
currentSymbol.baseClasses.insert(iotcToStringArray(symbolAllocator, currentSymbol.baseClasses.insert(iotcToStringArray(symbolAllocator,
bc.identifierOrTemplateChain, stringCache)); bc.identifierOrTemplateChain));
} }
override void visit(const VariableDeclaration dec) override void visit(const VariableDeclaration dec)
@ -237,7 +237,7 @@ final class FirstPass : ASTVisitor
override void visit(const AliasThisDeclaration dec) override void visit(const AliasThisDeclaration dec)
{ {
// Log.trace(__FUNCTION__, " ", typeof(dec).stringof); // Log.trace(__FUNCTION__, " ", typeof(dec).stringof);
currentSymbol.aliasThis.insert(stringCache.intern(dec.identifier.text)); currentSymbol.aliasThis.insert(internString(dec.identifier.text));
} }
override void visit(const Declaration dec) override void visit(const Declaration dec)
@ -306,7 +306,7 @@ final class FirstPass : ASTVisitor
// Log.trace(__FUNCTION__, " ", typeof(dec).stringof); // Log.trace(__FUNCTION__, " ", typeof(dec).stringof);
foreach (identifier; moduleDeclaration.moduleName.identifiers) foreach (identifier; moduleDeclaration.moduleName.identifiers)
{ {
moduleName.insert(stringCache.intern(identifier.text)); moduleName.insert(internString(identifier.text));
} }
} }
@ -340,8 +340,8 @@ final class FirstPass : ASTVisitor
{ {
auto info = allocate!ImportInformation(semanticAllocator); auto info = allocate!ImportInformation(semanticAllocator);
foreach (identifier; single.identifierChain.identifiers) foreach (identifier; single.identifierChain.identifiers)
info.importParts.insert(stringCache.intern(identifier.text)); info.importParts.insert(internString(identifier.text));
info.modulePath = convertChainToImportPath(stringCache, single.identifierChain); info.modulePath = convertChainToImportPath(single.identifierChain);
info.isPublic = protection == tok!"public"; info.isPublic = protection == tok!"public";
currentScope.importInformation.insert(info); currentScope.importInformation.insert(info);
} }
@ -349,18 +349,18 @@ final class FirstPass : ASTVisitor
if (importDeclaration.importBindings.singleImport.identifierChain is null) return; if (importDeclaration.importBindings.singleImport.identifierChain is null) return;
auto info = allocate!ImportInformation(semanticAllocator); auto info = allocate!ImportInformation(semanticAllocator);
info.modulePath = convertChainToImportPath(stringCache, info.modulePath = convertChainToImportPath(
importDeclaration.importBindings.singleImport.identifierChain); importDeclaration.importBindings.singleImport.identifierChain);
foreach (identifier; importDeclaration.importBindings.singleImport foreach (identifier; importDeclaration.importBindings.singleImport
.identifierChain.identifiers) .identifierChain.identifiers)
{ {
info.importParts.insert(stringCache.intern(identifier.text)); info.importParts.insert(internString(identifier.text));
} }
foreach (bind; importDeclaration.importBindings.importBinds) foreach (bind; importDeclaration.importBindings.importBinds)
{ {
Tuple!(string, string) bindTuple; Tuple!(string, string) bindTuple;
bindTuple[0] = stringCache.intern(bind.left.text); bindTuple[0] = internString(bind.left.text);
bindTuple[1] = bind.right == tok!"" ? null : stringCache.intern(bind.right.text); bindTuple[1] = bind.right == tok!"" ? null : internString(bind.right.text);
info.importedSymbols.insert(bindTuple); info.importedSymbols.insert(bindTuple);
} }
info.isPublic = protection == tok!"public"; info.isPublic = protection == tok!"public";
@ -412,8 +412,6 @@ final class FirstPass : ASTVisitor
/// The module /// The module
SemanticSymbol* rootSymbol; SemanticSymbol* rootSymbol;
shared(StringCache)* stringCache;
CAllocator symbolAllocator; CAllocator symbolAllocator;
uint symbolsAllocated; uint symbolsAllocated;
@ -431,7 +429,7 @@ private:
symbol.acSymbol.parts.insert(aggregateSymbols[]); symbol.acSymbol.parts.insert(aggregateSymbols[]);
symbol.parent = currentSymbol; symbol.parent = currentSymbol;
symbol.protection = protection; symbol.protection = protection;
symbol.acSymbol.doc = stringCache.intern(dec.comment); symbol.acSymbol.doc = internString(dec.comment);
currentSymbol = symbol; currentSymbol = symbol;
dec.accept(this); dec.accept(this);
currentSymbol = symbol.parent; currentSymbol = symbol.parent;
@ -446,7 +444,7 @@ private:
processParameters(symbol, null, "this", parameters, doc); processParameters(symbol, null, "this", parameters, doc);
symbol.protection = protection; symbol.protection = protection;
symbol.parent = currentSymbol; symbol.parent = currentSymbol;
symbol.acSymbol.doc = stringCache.intern(doc); symbol.acSymbol.doc = internString(doc);
currentSymbol.addChild(symbol); currentSymbol.addChild(symbol);
if (functionBody !is null) if (functionBody !is null)
{ {
@ -463,7 +461,7 @@ private:
symbol.acSymbol.callTip = "~this()"; symbol.acSymbol.callTip = "~this()";
symbol.protection = protection; symbol.protection = protection;
symbol.parent = currentSymbol; symbol.parent = currentSymbol;
symbol.acSymbol.doc = stringCache.intern(doc); symbol.acSymbol.doc = internString(doc);
currentSymbol.addChild(symbol); currentSymbol.addChild(symbol);
if (functionBody !is null) if (functionBody !is null)
{ {
@ -519,7 +517,7 @@ private:
app.put("()"); app.put("()");
else else
app.formatNode(parameters); app.formatNode(parameters);
return stringCache.intern(cast(ubyte[]) app[]); return internString(cast(string) app[]);
} }
SemanticSymbol* allocateSemanticSymbol(string name, CompletionKind kind, SemanticSymbol* allocateSemanticSymbol(string name, CompletionKind kind,
@ -530,8 +528,7 @@ private:
} }
body body
{ {
ACSymbol* acSymbol = allocate!ACSymbol(symbolAllocator, ACSymbol* acSymbol = allocate!ACSymbol(symbolAllocator, name, kind);
name is null ? name : stringCache.intern(name), kind);
acSymbol.location = location; acSymbol.location = location;
acSymbol.symbolFile = symbolFile; acSymbol.symbolFile = symbolFile;
symbolsAllocated++; symbolsAllocated++;
@ -568,23 +565,21 @@ void formatNode(A, T)(ref A appender, const T node)
private: private:
string[] iotcToStringArray(A)(ref A allocator, const IdentifierOrTemplateChain iotc, string[] iotcToStringArray(A)(ref A allocator, const IdentifierOrTemplateChain iotc)
shared(StringCache)* stringCache)
{ {
string[] retVal = cast(string[]) allocator.allocate((string[]).sizeof string[] retVal = cast(string[]) allocator.allocate((string[]).sizeof
* iotc.identifiersOrTemplateInstances.length); * iotc.identifiersOrTemplateInstances.length);
foreach (i, ioti; iotc.identifiersOrTemplateInstances) foreach (i, ioti; iotc.identifiersOrTemplateInstances)
{ {
if (ioti.identifier != tok!"") if (ioti.identifier != tok!"")
retVal[i] = stringCache.intern(ioti.identifier.text); retVal[i] = internString(ioti.identifier.text);
else else
retVal[i] = stringCache.intern(ioti.templateInstance.identifier.text); retVal[i] = internString(ioti.templateInstance.identifier.text);
} }
return retVal; return retVal;
} }
static string convertChainToImportPath(shared(StringCache)* stringCache, static string convertChainToImportPath(const IdentifierChain ic)
const IdentifierChain ic)
{ {
import std.path; import std.path;
QuickAllocator!1024 q; QuickAllocator!1024 q;
@ -596,5 +591,5 @@ static string convertChainToImportPath(shared(StringCache)* stringCache,
if (i + 1 < ic.identifiers.length) if (i + 1 < ic.identifiers.length)
app.append(dirSeparator); app.append(dirSeparator);
} }
return stringCache.intern(cast(string) app[]); return internString(cast(string) app[]);
} }

View File

@ -22,7 +22,6 @@ import conversion.first;
import actypes; import actypes;
import semantic; import semantic;
import messages; import messages;
import std.lexer : StringCache;
import std.allocator; import std.allocator;
import stupidlog; import stupidlog;
@ -41,7 +40,6 @@ public:
{ {
this.rootSymbol = first.rootSymbol; this.rootSymbol = first.rootSymbol;
this.moduleScope = first.moduleScope; this.moduleScope = first.moduleScope;
this.stringCache = first.stringCache;
this.symbolAllocator = first.symbolAllocator; this.symbolAllocator = first.symbolAllocator;
} }
@ -54,7 +52,6 @@ public:
CAllocator symbolAllocator; CAllocator symbolAllocator;
SemanticSymbol* rootSymbol; SemanticSymbol* rootSymbol;
Scope* moduleScope; Scope* moduleScope;
shared(StringCache)* stringCache;
private: private:
@ -117,18 +114,6 @@ private:
{ {
string location = ModuleCache.resolveImportLoctation(importInfo.modulePath); string location = ModuleCache.resolveImportLoctation(importInfo.modulePath);
ACSymbol*[] symbols = location is null ? [] : ModuleCache.getSymbolsInModule(location); ACSymbol*[] symbols = location is null ? [] : ModuleCache.getSymbolsInModule(location);
//////
foreach (s; symbols)
{
try
std.utf.validate(s.name);
catch (Exception e)
{
writeln("Symbols in ", importInfo.modulePath, " are corrupted");
throw e;
}
}
//////
ACSymbol* moduleSymbol = createImportSymbols(importInfo, currentScope, symbols); ACSymbol* moduleSymbol = createImportSymbols(importInfo, currentScope, symbols);
currentScope.symbols.insert(moduleSymbol); currentScope.symbols.insert(moduleSymbol);
currentScope.symbols.insert(symbols); currentScope.symbols.insert(symbols);

View File

@ -25,6 +25,7 @@ import semantic;
import actypes; import actypes;
import messages; import messages;
import std.allocator; import std.allocator;
import string_interning;
/** /**
* Third pass handles the following: * Third pass handles the following:
@ -43,7 +44,6 @@ public:
{ {
this.rootSymbol = second.rootSymbol; this.rootSymbol = second.rootSymbol;
this.moduleScope = second.moduleScope; this.moduleScope = second.moduleScope;
this.stringCache = second.stringCache;
this.name = name; this.name = name;
this.symbolAllocator = second.symbolAllocator; this.symbolAllocator = second.symbolAllocator;
} }
@ -153,8 +153,7 @@ private:
t.type2.symbol.identifierOrTemplateChain.identifiersOrTemplateInstances.length t.type2.symbol.identifierOrTemplateChain.identifiersOrTemplateInstances.length
* string.sizeof); * string.sizeof);
scope(exit) Mallocator.it.deallocate(symbolParts); scope(exit) Mallocator.it.deallocate(symbolParts);
expandSymbol(symbolParts, expandSymbol(symbolParts, t.type2.symbol.identifierOrTemplateChain);
t.type2.symbol.identifierOrTemplateChain, stringCache);
auto symbols = moduleScope.getSymbolsByNameAndCursor( auto symbols = moduleScope.getSymbolsByNameAndCursor(
symbolParts[0], location); symbolParts[0], location);
if (symbols.length == 0) if (symbols.length == 0)
@ -174,15 +173,14 @@ private:
return s; return s;
} }
static void expandSymbol(string[] strings, const IdentifierOrTemplateChain chain, static void expandSymbol(string[] strings, const IdentifierOrTemplateChain chain)
shared(StringCache)* stringCache)
{ {
for (size_t i = 0; i < chain.identifiersOrTemplateInstances.length; ++i) for (size_t i = 0; i < chain.identifiersOrTemplateInstances.length; ++i)
{ {
auto identOrTemplate = chain.identifiersOrTemplateInstances[i]; auto identOrTemplate = chain.identifiersOrTemplateInstances[i];
if (identOrTemplate is null) if (identOrTemplate is null)
continue; continue;
strings[i] = stringCache.intern(identOrTemplate.templateInstance is null ? strings[i] = internString(identOrTemplate.templateInstance is null ?
identOrTemplate.identifier.text identOrTemplate.identifier.text
: identOrTemplate.templateInstance.identifier.text); : identOrTemplate.templateInstance.identifier.text);
} }
@ -215,20 +213,20 @@ private:
scope(exit) q.deallocate(app.mem); scope(exit) q.deallocate(app.mem);
app.append(suffix.delegateOrFunction.text); app.append(suffix.delegateOrFunction.text);
app.formatNode(suffix.parameters); app.formatNode(suffix.parameters);
s.callTip = stringCache.intern(cast(ubyte[]) app[]); s.callTip = internString(cast(string) app[]);
return s; return s;
} }
return null; return null;
} }
static ACSymbol* convertBuiltinType(const Type2 type2) ACSymbol* convertBuiltinType(const Type2 type2)
{ {
string stringRepresentation = str(type2.builtinType); import std.stdio;
if (stringRepresentation is null) return null; string stringRepresentation = getBuiltinTypeName(type2.builtinType);
// TODO: Make this use binary search instead // writefln(">> %s %016X", stringRepresentation, stringRepresentation.ptr);
ACSymbol s = ACSymbol(stringRepresentation); ACSymbol s = ACSymbol(stringRepresentation);
assert(s.name.ptr == stringRepresentation.ptr);
// writefln(">> %s %016X", s.name, s.name.ptr);
return builtinSymbols.equalRange(&s).front(); return builtinSymbols.equalRange(&s).front();
} }
shared(StringCache)* stringCache;
} }

@ -1 +1 @@
Subproject commit 8b4b2b342f4e3c8dbead90353c6f7aa4800c2ce4 Subproject commit 19dc7c707f857b104144e909d77543b2db1521b8

View File

@ -32,7 +32,7 @@ import std.path;
import actypes; import actypes;
import semantic; import semantic;
import memory.allocators; import memory.allocators;
import containers.karytree; import containers.ttree;
import containers.hashset; import containers.hashset;
import containers.unrolledlist; import containers.unrolledlist;
import conversion.astconverter; import conversion.astconverter;
@ -74,7 +74,6 @@ bool existanceCheck(A)(A path)
static this() static this()
{ {
ModuleCache.stringCache = new shared StringCache(StringCache.defaultBucketCount);
ModuleCache.symbolAllocator = new CAllocatorImpl!(BlockAllocator!(1024 * 16)); ModuleCache.symbolAllocator = new CAllocatorImpl!(BlockAllocator!(1024 * 16));
} }
@ -115,6 +114,7 @@ struct ModuleCache
*/ */
static ACSymbol*[] getSymbolsInModule(string location) static ACSymbol*[] getSymbolsInModule(string location)
{ {
import string_interning;
assert (location !is null); assert (location !is null);
if (!needsReparsing(location)) if (!needsReparsing(location))
{ {
@ -126,7 +126,7 @@ struct ModuleCache
return []; return [];
} }
string cachedLocation = stringCache.intern(location); string cachedLocation = internString(location);
Log.info("Getting symbols for ", cachedLocation); Log.info("Getting symbols for ", cachedLocation);
@ -145,7 +145,7 @@ struct ModuleCache
f.rawRead(source); f.rawRead(source);
LexerConfig config; LexerConfig config;
config.fileName = cachedLocation; config.fileName = cachedLocation;
shared parseStringCache = shared StringCache(StringCache.defaultBucketCount); auto parseStringCache = StringCache(StringCache.defaultBucketCount);
auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 64))); auto semanticAllocator = scoped!(CAllocatorImpl!(BlockAllocator!(1024 * 64)));
DynamicArray!(Token, false) tokens; DynamicArray!(Token, false) tokens;
auto tokenRange = byToken( auto tokenRange = byToken(
@ -158,8 +158,8 @@ struct ModuleCache
Module m = parseModuleSimple(tokens[], cachedLocation, semanticAllocator); Module m = parseModuleSimple(tokens[], cachedLocation, semanticAllocator);
assert (symbolAllocator); assert (symbolAllocator);
auto first = scoped!FirstPass(m, cachedLocation, stringCache, auto first = scoped!FirstPass(m, cachedLocation, symbolAllocator,
symbolAllocator, semanticAllocator); semanticAllocator);
first.run(); first.run();
SecondPass second = SecondPass(first); SecondPass second = SecondPass(first);
@ -234,8 +234,6 @@ struct ModuleCache
return importPaths[]; return importPaths[];
} }
static shared(StringCache)* stringCache;
static uint symbolsAllocated; static uint symbolsAllocated;
private: private:
@ -264,7 +262,7 @@ private:
} }
// Mapping of file paths to their cached symbols. // Mapping of file paths to their cached symbols.
static KAryTree!(CacheEntry*) cache; static TTree!(CacheEntry*) cache;
static HashSet!string recursionGuard; static HashSet!string recursionGuard;

View File

@ -100,11 +100,9 @@ int main(string[] args)
sw.stop(); sw.stop();
Log.info("Startup completed in ", sw.peek().to!("msecs", float), " milliseconds"); Log.info("Startup completed in ", sw.peek().to!("msecs", float), " milliseconds");
float internBytes = cast(float) ModuleCache.stringCache.allocated / (1024 * 1024); // float symbolMegs = (cast(float) (ACSymbol.sizeof * ModuleCache.symbolsAllocated)) / (1024f * 1024f);
Log.info("String interning took up ", internBytes, " megabytes"); // Log.info(ModuleCache.symbolsAllocated, " symbols allocated, taking up ",
float symbolMegs = (cast(float) (ACSymbol.sizeof * ModuleCache.symbolsAllocated)) / (1024f * 1024f); // symbolMegs, " megabytes");
Log.info(ModuleCache.symbolsAllocated, " symbols allocated, taking up ",
symbolMegs, " megabytes");
// No relative paths // No relative paths
version (Posix) chdir("/"); version (Posix) chdir("/");

44
string_interning.d Normal file
View File

@ -0,0 +1,44 @@
/**
* This file is part of DCD, a development tool for the D programming language.
* Copyright (C) 2014 Brian Schott
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
module string_interning;
import std.lexer;
string internString(string s)
{
// import std.stdio;
// import std.string;
// size_t* p = s in dupCheck;
// auto r = stringCache.intern(s);
return stringCache.intern(s);
// if (p !is null)
// assert (*p == cast(size_t) r.ptr, format("%s, %016x, %016x", s, *p, r.ptr));
// else
// dupCheck[s] = cast(size_t) r.ptr;
// stderr.writefln("%s\t%016x", r, r.ptr);
// return r;
}
static this()
{
stringCache = StringCache(StringCache.defaultBucketCount);
}
//private size_t[string] dupCheck;
private StringCache stringCache = void;