mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
[Demangler] Further optimizations for the remangler.
Replace use of `snprintf()` with some custom code (this is around 10x faster on my machine). Move a few of the `Node` member functions to the header so they're inlined. Optimize the `deepEquals()` function by adding an `isSimilarTo()` method on `Node`; the checks that were happening in the `deepEquals()` function could be implemented more efficiently by making use of details of the internal representation of `Node`. rdar://125739630
This commit is contained in:
@@ -206,7 +206,8 @@ private:
|
||||
Kind NodeKind;
|
||||
|
||||
enum class PayloadKind : uint8_t {
|
||||
None, Text, Index, OneChild, TwoChildren, ManyChildren
|
||||
None = 0, OneChild = 1, TwoChildren = 2,
|
||||
Text, Index, ManyChildren
|
||||
};
|
||||
PayloadKind NodePayloadKind;
|
||||
|
||||
@@ -227,6 +228,22 @@ private:
|
||||
public:
|
||||
Kind getKind() const { return NodeKind; }
|
||||
|
||||
bool isSimilarTo(const Node *other) const {
|
||||
if (NodeKind != other->NodeKind
|
||||
|| NodePayloadKind != other->NodePayloadKind)
|
||||
return false;
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::ManyChildren:
|
||||
return Children.Number == other->Children.Number;
|
||||
case PayloadKind::Index:
|
||||
return Index == other->Index;
|
||||
case PayloadKind::Text:
|
||||
return Text == other->Text;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasText() const { return NodePayloadKind == PayloadKind::Text; }
|
||||
llvm::StringRef getText() const {
|
||||
assert(hasText());
|
||||
@@ -241,13 +258,41 @@ public:
|
||||
|
||||
using iterator = const NodePointer *;
|
||||
|
||||
size_t getNumChildren() const;
|
||||
size_t getNumChildren() const {
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::OneChild: return 1;
|
||||
case PayloadKind::TwoChildren: return 2;
|
||||
case PayloadKind::ManyChildren: return Children.Number;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
bool hasChildren() const { return getNumChildren() != 0; }
|
||||
|
||||
iterator begin() const;
|
||||
iterator begin() const {
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::OneChild:
|
||||
case PayloadKind::TwoChildren:
|
||||
return &InlineChildren[0];
|
||||
case PayloadKind::ManyChildren:
|
||||
return Children.Nodes;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
iterator end() const;
|
||||
iterator end() const {
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::OneChild:
|
||||
return &InlineChildren[1];
|
||||
case PayloadKind::TwoChildren:
|
||||
return &InlineChildren[2];
|
||||
case PayloadKind::ManyChildren:
|
||||
return Children.Nodes + Children.Number;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
NodePointer getFirstChild() const {
|
||||
return getChild(0);
|
||||
|
||||
@@ -354,40 +354,6 @@ using namespace Demangle;
|
||||
// Node member functions //
|
||||
//////////////////////////////////
|
||||
|
||||
size_t Node::getNumChildren() const {
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::OneChild: return 1;
|
||||
case PayloadKind::TwoChildren: return 2;
|
||||
case PayloadKind::ManyChildren: return Children.Number;
|
||||
default: return 0;
|
||||
}
|
||||
}
|
||||
|
||||
Node::iterator Node::begin() const {
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::OneChild:
|
||||
case PayloadKind::TwoChildren:
|
||||
return &InlineChildren[0];
|
||||
case PayloadKind::ManyChildren:
|
||||
return Children.Nodes;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
Node::iterator Node::end() const {
|
||||
switch (NodePayloadKind) {
|
||||
case PayloadKind::OneChild:
|
||||
return &InlineChildren[1];
|
||||
case PayloadKind::TwoChildren:
|
||||
return &InlineChildren[2];
|
||||
case PayloadKind::ManyChildren:
|
||||
return Children.Nodes + Children.Number;
|
||||
default:
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
void Node::addChild(NodePointer Child, NodeFactory &Factory) {
|
||||
DEMANGLER_ALWAYS_ASSERT(Child, this);
|
||||
switch (NodePayloadKind) {
|
||||
@@ -635,6 +601,58 @@ NodePointer NodeFactory::createNode(Node::Kind K, const char *Text) {
|
||||
int NodeFactory::nestingLevel = 0;
|
||||
#endif
|
||||
|
||||
// Fast integer formatting
|
||||
namespace {
|
||||
|
||||
// Format an unsigned integer into a buffer
|
||||
template <typename U,
|
||||
typename std::enable_if<std::is_unsigned<U>::value, bool>::type = true>
|
||||
size_t int2str(U n, char *buf) {
|
||||
// The easy case is zero
|
||||
if (n == 0) {
|
||||
*buf++ = '0';
|
||||
*buf++ = '\0';
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Do the digits one a time (for really high speed we could do these in
|
||||
// chunks, but that's probably not necessary here.)
|
||||
char *ptr = buf;
|
||||
while (n) {
|
||||
char digit = '0' + (n % 10);
|
||||
n /= 10;
|
||||
*ptr++ = digit;
|
||||
}
|
||||
size_t len = ptr - buf;
|
||||
|
||||
// Terminate the string
|
||||
*ptr = '\0';
|
||||
|
||||
// Now reverse the digits
|
||||
while (buf < ptr) {
|
||||
char tmp = *--ptr;
|
||||
*ptr = *buf;
|
||||
*buf++ = tmp;
|
||||
}
|
||||
|
||||
return len;
|
||||
}
|
||||
|
||||
// Deal with negative numbers
|
||||
template <typename S,
|
||||
typename std::enable_if<std::is_signed<S>::value, bool>::type = true>
|
||||
size_t int2str(S n, char *buf) {
|
||||
using U = typename std::make_unsigned<S>::type;
|
||||
|
||||
if (n < 0) {
|
||||
*buf++ = '-';
|
||||
return int2str(static_cast<U>(-n), buf);
|
||||
}
|
||||
return int2str(static_cast<U>(n), buf);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
//////////////////////////////////
|
||||
// CharVector member functions //
|
||||
//////////////////////////////////
|
||||
@@ -651,7 +669,7 @@ void CharVector::append(int Number, NodeFactory &Factory) {
|
||||
const int MaxIntPrintSize = 11;
|
||||
if (NumElems + MaxIntPrintSize > Capacity)
|
||||
Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxIntPrintSize);
|
||||
int Length = snprintf(Elems + NumElems, MaxIntPrintSize, "%d", Number);
|
||||
int Length = int2str(Number, Elems + NumElems);
|
||||
assert(Length > 0 && Length < MaxIntPrintSize);
|
||||
NumElems += Length;
|
||||
}
|
||||
@@ -660,7 +678,7 @@ void CharVector::append(unsigned long long Number, NodeFactory &Factory) {
|
||||
const int MaxPrintSize = 21;
|
||||
if (NumElems + MaxPrintSize > Capacity)
|
||||
Factory.Reallocate(Elems, Capacity, /*Growth*/ MaxPrintSize);
|
||||
int Length = snprintf(Elems + NumElems, MaxPrintSize, "%llu", Number);
|
||||
int Length = int2str(Number, Elems + NumElems);
|
||||
assert(Length > 0 && Length < MaxPrintSize);
|
||||
NumElems += Length;
|
||||
}
|
||||
|
||||
@@ -60,23 +60,7 @@ bool SubstitutionEntry::identifierEquals(Node *lhs, Node *rhs) {
|
||||
}
|
||||
|
||||
bool SubstitutionEntry::deepEquals(Node *lhs, Node *rhs) const {
|
||||
if (lhs->getKind() != rhs->getKind())
|
||||
return false;
|
||||
if (lhs->hasIndex()) {
|
||||
if (!rhs->hasIndex())
|
||||
return false;
|
||||
if (lhs->getIndex() != rhs->getIndex())
|
||||
return false;
|
||||
} else if (lhs->hasText()) {
|
||||
if (!rhs->hasText())
|
||||
return false;
|
||||
if (lhs->getText() != rhs->getText())
|
||||
return false;
|
||||
} else if (rhs->hasIndex() || rhs->hasText()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (lhs->getNumChildren() != rhs->getNumChildren())
|
||||
if (!lhs->isSimilarTo(rhs))
|
||||
return false;
|
||||
|
||||
for (auto li = lhs->begin(), ri = rhs->begin(), le = lhs->end();
|
||||
|
||||
Reference in New Issue
Block a user