Skip to content

Commit 3195297

Browse files
committed
[MachO] Reduce size of Symbol and Defined
We can lay out Symbol more optimally to reduce its size from 56 bytes to 48 bytes by eliminating unnecessary padding, and we can lay out Defined such that its bitfield members are placed in the tail padding of Symbol (on ABIs which support this), to reduce it from 96 bytes to 80 bytes (8 bytes from the Symbol reduction, and 8 bytes from the tail padding reuse). This is perf-neutral for an internal app (results from two different machines): ``` smol-syms baseline difference (95% CI) sys_time 7.430 ± 0.202 7.440 ± 0.193 [ -2.6% .. +2.9%] user_time 21.443 ± 0.513 21.206 ± 0.396 [ -3.3% .. +1.1%] wall_time 20.453 ± 0.534 20.222 ± 0.488 [ -3.7% .. +1.5%] samples 9 8 smol-syms baseline difference (95% CI) sys_time 3.011 ± 0.050 3.040 ± 0.052 [ -0.4% .. +2.3%] user_time 10.416 ± 0.075 10.496 ± 0.091 [ +0.1% .. +1.4%] wall_time 12.229 ± 0.144 12.354 ± 0.192 [ -0.1% .. +2.1%] samples 14 13 ``` However, on the first machine, it reduces maximum resident set size by 65.9 MB (0.8%, from 7.92 GB to 7.85 GB). On the second machine, it reduces it by 92 MB (1.4%, from 6.40 GB to 6.31 GB). Reviewed By: #lld-macho, int3 Differential Revision: https://reviews.llvm.org/D113813
1 parent 637a339 commit 3195297

File tree

2 files changed

+29
-14
lines changed

2 files changed

+29
-14
lines changed

lld/MachO/Symbols.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,12 +36,11 @@ Defined::Defined(StringRefZ name, InputFile *file, InputSection *isec,
3636
bool isPrivateExtern, bool isThumb,
3737
bool isReferencedDynamically, bool noDeadStrip,
3838
bool canOverrideWeakDef, bool isWeakDefCanBeHidden)
39-
: Symbol(DefinedKind, name, file), isec(isec), value(value), size(size),
40-
overridesWeakDef(canOverrideWeakDef), privateExtern(isPrivateExtern),
41-
includeInSymtab(true), thumb(isThumb),
39+
: Symbol(DefinedKind, name, file), overridesWeakDef(canOverrideWeakDef),
40+
privateExtern(isPrivateExtern), includeInSymtab(true), thumb(isThumb),
4241
referencedDynamically(isReferencedDynamically), noDeadStrip(noDeadStrip),
4342
weakDefCanBeHidden(isWeakDefCanBeHidden), weakDef(isWeakDef),
44-
external(isExternal) {
43+
external(isExternal), isec(isec), value(value), size(size) {
4544
if (isec) {
4645
isec->symbols.push_back(this);
4746
// Maintain sorted order.

lld/MachO/Symbols.h

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -92,14 +92,14 @@ class Symbol {
9292

9393
protected:
9494
Symbol(Kind k, StringRefZ name, InputFile *file)
95-
: symbolKind(k), nameData(name.data), nameSize(name.size), file(file),
95+
: symbolKind(k), nameData(name.data), file(file), nameSize(name.size),
9696
isUsedInRegularObj(!file || isa<ObjFile>(file)),
9797
used(!config->deadStrip) {}
9898

9999
Kind symbolKind;
100100
const char *nameData;
101-
mutable uint32_t nameSize;
102101
InputFile *file;
102+
mutable uint32_t nameSize;
103103

104104
public:
105105
// True if this symbol was referenced by a regular (non-bitcode) object.
@@ -109,6 +109,9 @@ class Symbol {
109109
bool used : 1;
110110
};
111111

112+
static_assert(sizeof(void *) != 8 || sizeof(Symbol) == 48,
113+
"Try to minimize Symbol's size; we create many instances");
114+
112115
class Defined : public Symbol {
113116
public:
114117
Defined(StringRefZ name, InputFile *file, InputSection *isec, uint64_t value,
@@ -133,14 +136,8 @@ class Defined : public Symbol {
133136
134137
static bool classof(const Symbol *s) { return s->kind() == DefinedKind; }
135138
136-
InputSection *isec;
137-
// Contains the offset from the containing subsection. Note that this is
138-
// different from nlist::n_value, which is the absolute address of the symbol.
139-
uint64_t value;
140-
// size is only calculated for regular (non-bitcode) symbols.
141-
uint64_t size;
142-
ConcatInputSection *compactUnwind = nullptr;
143-
139+
// Place the bitfields first so that they can get placed in the tail padding
140+
// of the parent class, on platforms which support it.
144141
bool overridesWeakDef : 1;
145142
// Whether this symbol should appear in the output binary's export trie.
146143
bool privateExtern : 1;
@@ -166,8 +163,24 @@ class Defined : public Symbol {
166163
private:
167164
const bool weakDef : 1;
168165
const bool external : 1;
166+
167+
public:
168+
InputSection *isec;
169+
// Contains the offset from the containing subsection. Note that this is
170+
// different from nlist::n_value, which is the absolute address of the symbol.
171+
uint64_t value;
172+
// size is only calculated for regular (non-bitcode) symbols.
173+
uint64_t size;
174+
ConcatInputSection *compactUnwind = nullptr;
169175
};
170176
177+
// The Microsoft ABI doesn't support using parent class tail padding for child
178+
// members, hence the _MSC_VER check.
179+
#if !defined(_MSC_VER)
180+
static_assert(sizeof(void *) != 8 || sizeof(Defined) == 80,
181+
"Try to minimize Defined's size; we create many instances");
182+
#endif
183+
171184
// This enum does double-duty: as a symbol property, it indicates whether & how
172185
// a dylib symbol is referenced. As a DylibFile property, it indicates the kind
173186
// of referenced symbols contained within the file. If there are both weak
@@ -294,6 +307,9 @@ union SymbolUnion {
294307
alignas(LazySymbol) char e[sizeof(LazySymbol)];
295308
};
296309
310+
static_assert(sizeof(SymbolUnion) == sizeof(Defined),
311+
"Defined should be the largest Symbol kind");
312+
297313
template <typename T, typename... ArgT>
298314
T *replaceSymbol(Symbol *s, ArgT &&...arg) {
299315
static_assert(sizeof(T) <= sizeof(SymbolUnion), "SymbolUnion too small");

0 commit comments

Comments
 (0)