1 /* -*- mode: C++; c-basic-offset: 4; tab-width: 4 -*-*
3 * Copyright (c) 2009-2010 Apple Inc. All rights reserved.
5 * @APPLE_LICENSE_HEADER_START@
7 * This file contains Original Code and/or Modifications of Original Code
8 * as defined in and that are subject to the Apple Public Source License
9 * Version 2.0 (the 'License'). You may not use this file except in
10 * compliance with the License. Please obtain a copy of the License at
11 * http://www.opensource.apple.com/apsl/ and read it before using this
14 * The Original Code and all software distributed under the License are
15 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19 * Please see the License for the specific language governing rights and
20 * limitations under the License.
22 * @APPLE_LICENSE_HEADER_END@
27 #include <sys/types.h>
30 #include <sys/sysctl.h>
42 #include <ext/hash_map>
43 #include <ext/hash_set>
48 #include "InputFiles.h"
49 #include "SymbolTable.h"
57 // HACK, I can't find a way to pass values in the compare classes (e.g. ContentFuncs)
58 // so use global variable to pass info.
59 static ld::IndirectBindingTable
* _s_indirectBindingTable
= NULL
;
60 bool SymbolTable::_s_doDemangle
= false;
63 SymbolTable::SymbolTable(const Options
& opts
, std::vector
<const ld::Atom
*>& ibt
)
64 : _options(opts
), _cstringTable(6151), _indirectBindingTable(ibt
), _hasExternalTentativeDefinitions(false)
66 _s_indirectBindingTable
= this;
67 _s_doDemangle
= _options
.demangleSymbols();
71 size_t SymbolTable::ContentFuncs::operator()(const ld::Atom
* atom
) const
73 return atom
->contentHash(*_s_indirectBindingTable
);
76 bool SymbolTable::ContentFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
78 return (memcmp(left
->rawContentPointer(), right
->rawContentPointer(), left
->size()) == 0);
83 size_t SymbolTable::CStringHashFuncs::operator()(const ld::Atom
* atom
) const
85 return atom
->contentHash(*_s_indirectBindingTable
);
88 bool SymbolTable::CStringHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
90 return (strcmp((char*)left
->rawContentPointer(), (char*)right
->rawContentPointer()) == 0);
94 size_t SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom
* atom
) const
96 return atom
->contentHash(*_s_indirectBindingTable
);
99 bool SymbolTable::UTF16StringHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
103 const void* leftContent
= left
->rawContentPointer();
104 const void* rightContent
= right
->rawContentPointer();
105 unsigned int amount
= left
->size()-2;
106 bool result
= (memcmp(leftContent
, rightContent
, amount
) == 0);
111 size_t SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom
* atom
) const
113 return atom
->contentHash(*_s_indirectBindingTable
);
116 bool SymbolTable::ReferencesHashFuncs::operator()(const ld::Atom
* left
, const ld::Atom
* right
) const
118 return left
->canCoalesceWith(*right
, *_s_indirectBindingTable
);
123 bool SymbolTable::addByName(const ld::Atom
& newAtom
, bool ignoreDuplicates
)
126 bool checkVisibilityMismatch
= false;
127 assert(newAtom
.name() != NULL
);
128 const char* name
= newAtom
.name();
129 IndirectBindingSlot slot
= this->findSlotForName(name
);
130 const ld::Atom
* existingAtom
= _indirectBindingTable
[slot
];
131 //fprintf(stderr, "addByName(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
132 if ( existingAtom
!= NULL
) {
133 assert(&newAtom
!= existingAtom
);
134 switch ( existingAtom
->definition() ) {
135 case ld::Atom::definitionRegular
:
136 switch ( newAtom
.definition() ) {
137 case ld::Atom::definitionRegular
:
138 if ( existingAtom
->combine() == ld::Atom::combineByName
) {
139 if ( newAtom
.combine() == ld::Atom::combineByName
) {
140 // both weak, prefer non-auto-hide one
141 if ( newAtom
.autoHide() != existingAtom
->autoHide() ) {
142 // <rdar://problem/6783167> support auto hidden weak symbols: .weak_def_can_be_hidden
143 useNew
= existingAtom
->autoHide();
144 // don't check for visibility mismatch
146 else if ( newAtom
.autoHide() && existingAtom
->autoHide() ) {
147 // both have auto-hide, so use one with greater alignment
148 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
151 // neither auto-hide, check visibility
152 if ( newAtom
.scope() != existingAtom
->scope() ) {
153 // <rdar://problem/8304984> use more visible weak def symbol
154 useNew
= (newAtom
.scope() == ld::Atom::scopeGlobal
);
157 // both have same visibility, use one with greater alignment
158 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
163 // existing weak, new is not-weak
168 if ( newAtom
.combine() == ld::Atom::combineByName
) {
169 // existing not-weak, new is weak
173 // existing not-weak, new is not-weak
174 if ( ignoreDuplicates
) {
176 static bool fullWarning
= false;
177 if ( ! fullWarning
) {
178 warning("-dead_strip with lazy loaded static (library) archives "
179 "has resulted in a duplicate symbol. You can change your "
180 "source code to rename symbols to avoid the collision. "
181 "This will be an error in a future linker.");
184 warning("duplicate symbol %s originally in %s now lazily loaded from %s",
185 SymbolTable::demangle(name
), existingAtom
->file()->path(), newAtom
.file()->path());
188 throwf("duplicate symbol %s in %s and %s",
189 SymbolTable::demangle(name
), newAtom
.file()->path(), existingAtom
->file()->path());
194 case ld::Atom::definitionTentative
:
195 // ignore new tentative atom, because we already have a regular one
197 checkVisibilityMismatch
= true;
198 if ( newAtom
.size() > existingAtom
->size() ) {
199 warning("for symbol %s tentative definition of size %llu from %s is "
200 "is smaller than the real definition of size %llu from %s",
201 newAtom
.name(), newAtom
.size(), newAtom
.file()->path(),
202 existingAtom
->size(), existingAtom
->file()->path());
205 case ld::Atom::definitionAbsolute
:
206 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.file()->path(), existingAtom
->file()->path());
207 case ld::Atom::definitionProxy
:
208 // ignore external atom, because we already have a one
213 case ld::Atom::definitionTentative
:
214 switch ( newAtom
.definition() ) {
215 case ld::Atom::definitionRegular
:
216 // replace existing tentative atom with regular one
217 checkVisibilityMismatch
= true;
218 if ( newAtom
.size() < existingAtom
->size() ) {
219 warning("for symbol %s tentative definition of size %llu from %s is "
220 "being replaced by a real definition of size %llu from %s",
221 newAtom
.name(), existingAtom
->size(), existingAtom
->file()->path(),
222 newAtom
.size(), newAtom
.file()->path());
225 case ld::Atom::definitionTentative
:
226 // new and existing are both tentative definitions, use largest
227 checkVisibilityMismatch
= true;
228 if ( newAtom
.size() < existingAtom
->size() ) {
232 if ( newAtom
.alignment().trailingZeros() < existingAtom
->alignment().trailingZeros() )
233 warning("alignment lost in merging tentative definition %s", newAtom
.name());
236 case ld::Atom::definitionAbsolute
:
237 // replace tentative with absolute
240 case ld::Atom::definitionProxy
:
241 // a tentative definition and a dylib definition, so commons-mode decides how to handle
242 switch ( _options
.commonsMode() ) {
243 case Options::kCommonsIgnoreDylibs
:
244 if ( _options
.warnCommons() )
245 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
246 existingAtom
->name(), existingAtom
->file()->path(), newAtom
.file()->path());
249 case Options::kCommonsOverriddenByDylibs
:
250 if ( _options
.warnCommons() )
251 warning("replacing common symbol %s from %s with true definition from dylib %s",
252 existingAtom
->name(), existingAtom
->file()->path(), newAtom
.file()->path());
254 case Options::kCommonsConflictsDylibsError
:
255 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
256 existingAtom
->name(), existingAtom
->file()->path(), newAtom
.file()->path());
261 case ld::Atom::definitionAbsolute
:
262 switch ( newAtom
.definition() ) {
263 case ld::Atom::definitionRegular
:
264 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.file()->path(), existingAtom
->file()->path());
265 case ld::Atom::definitionTentative
:
266 // ignore new tentative atom, because we already have a regular one
269 case ld::Atom::definitionAbsolute
:
270 throwf("duplicate symbol %s in %s and %s", name
, newAtom
.file()->path(), existingAtom
->file()->path());
271 case ld::Atom::definitionProxy
:
272 // ignore external atom, because we already have a one
277 case ld::Atom::definitionProxy
:
278 switch ( newAtom
.definition() ) {
279 case ld::Atom::definitionRegular
:
280 // replace external atom with regular one
283 case ld::Atom::definitionTentative
:
284 // a tentative definition and a dylib definition, so commons-mode decides how to handle
285 switch ( _options
.commonsMode() ) {
286 case Options::kCommonsIgnoreDylibs
:
287 if ( _options
.warnCommons() )
288 warning("using common symbol %s from %s and ignoring defintion from dylib %s",
289 newAtom
.name(), newAtom
.file()->path(), existingAtom
->file()->path());
291 case Options::kCommonsOverriddenByDylibs
:
292 if ( _options
.warnCommons() )
293 warning("replacing defintion of %s from dylib %s with common symbol from %s",
294 newAtom
.name(), existingAtom
->file()->path(), newAtom
.file()->path());
297 case Options::kCommonsConflictsDylibsError
:
298 throwf("common symbol %s from %s conflicts with defintion from dylib %s",
299 newAtom
.name(), newAtom
.file()->path(), existingAtom
->file()->path());
302 case ld::Atom::definitionAbsolute
:
303 // replace external atom with absolute one
306 case ld::Atom::definitionProxy
:
307 // <rdar://problem/5137732> ld should keep looking when it finds a weak definition in a dylib
308 if ( newAtom
.combine() == ld::Atom::combineByName
) {
312 if ( existingAtom
->combine() == ld::Atom::combineByName
)
315 throwf("symbol %s exported from both %s and %s\n", name
, newAtom
.file()->path(), existingAtom
->file()->path());
322 if ( (existingAtom
!= NULL
) && checkVisibilityMismatch
&& (newAtom
.scope() != existingAtom
->scope()) ) {
323 warning("%s has different visibility (%s) in %s and (%s) in %s",
324 SymbolTable::demangle(newAtom
.name()), (newAtom
.scope() == 1 ? "hidden" : "default"), newAtom
.file()->path(), (existingAtom
->scope() == 1 ? "hidden" : "default"), existingAtom
->file()->path());
327 _indirectBindingTable
[slot
] = &newAtom
;
328 if ( existingAtom
!= NULL
) {
329 markCoalescedAway(existingAtom
);
330 // if ( fOwner.fInitialLoadsDone ) {
331 // //fprintf(stderr, "existing %p %s overridden by %p\n", existingAtom, existingAtom->name(), &newAtom);
332 // fOwner.fAtomsOverriddenByLateLoads.insert(existingAtom);
335 if ( newAtom
.scope() == ld::Atom::scopeGlobal
) {
336 if ( newAtom
.definition() == ld::Atom::definitionTentative
) {
337 _hasExternalTentativeDefinitions
= true;
342 markCoalescedAway(&newAtom
);
344 // return if existing atom in symbol table was replaced
345 return useNew
&& (existingAtom
!= NULL
);
349 bool SymbolTable::addByContent(const ld::Atom
& newAtom
)
352 const ld::Atom
* existingAtom
;
353 IndirectBindingSlot slot
= this->findSlotForContent(&newAtom
, &existingAtom
);
354 //fprintf(stderr, "addByContent(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
355 if ( existingAtom
!= NULL
) {
356 // use existing unless new one has greater alignment requirements
357 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
360 _indirectBindingTable
[slot
] = &newAtom
;
361 if ( existingAtom
!= NULL
)
362 markCoalescedAway(existingAtom
);
365 _indirectBindingTable
[slot
] = existingAtom
;
366 if ( existingAtom
!= &newAtom
)
367 markCoalescedAway(&newAtom
);
369 // return if existing atom in symbol table was replaced
370 return useNew
&& (existingAtom
!= NULL
);
373 bool SymbolTable::addByReferences(const ld::Atom
& newAtom
)
376 const ld::Atom
* existingAtom
;
377 IndirectBindingSlot slot
= this->findSlotForReferences(&newAtom
, &existingAtom
);
378 //fprintf(stderr, "addByReferences(%p) name=%s, slot=%u, existing=%p\n", &newAtom, newAtom.name(), slot, existingAtom);
379 if ( existingAtom
!= NULL
) {
380 // use existing unless new one has greater alignment requirements
381 useNew
= ( newAtom
.alignment().trailingZeros() > existingAtom
->alignment().trailingZeros() );
384 _indirectBindingTable
[slot
] = &newAtom
;
385 if ( existingAtom
!= NULL
)
386 markCoalescedAway(existingAtom
);
389 if ( existingAtom
!= &newAtom
)
390 markCoalescedAway(&newAtom
);
392 // return if existing atom in symbol table was replaced
393 return useNew
&& (existingAtom
!= NULL
);
397 bool SymbolTable::add(const ld::Atom
& atom
, bool ignoreDuplicates
)
399 //fprintf(stderr, "SymbolTable::add(%p), name=%s\n", &atom, atom.name());
400 assert(atom
.scope() != ld::Atom::scopeTranslationUnit
);
401 switch ( atom
.combine() ) {
402 case ld::Atom::combineNever
:
403 case ld::Atom::combineByName
:
404 return this->addByName(atom
, ignoreDuplicates
);
406 case ld::Atom::combineByNameAndContent
:
407 return this->addByContent(atom
);
409 case ld::Atom::combineByNameAndReferences
:
410 return this->addByReferences(atom
);
417 void SymbolTable::markCoalescedAway(const ld::Atom
* atom
)
419 // remove this from list of all atoms used
420 //fprintf(stderr, "markCoalescedAway(%p) from %s\n", atom, atom->file()->path());
421 (const_cast<ld::Atom
*>(atom
))->setCoalescedAway();
424 // The fixupNoneGroupSubordinate* fixup kind is used to model group comdat.
425 // The "signature" atom in the group has a fixupNoneGroupSubordinate* fixup to
426 // all other members of the group. So, if the signature atom is
427 // coalesced away, all other atoms in the group should also be removed.
429 for (ld::Fixup::iterator fit
=atom
->fixupsBegin(), fend
=atom
->fixupsEnd(); fit
!= fend
; ++fit
) {
430 switch ( fit
->kind
) {
431 case ld::Fixup::kindNoneGroupSubordinate
:
432 case ld::Fixup::kindNoneGroupSubordinateFDE
:
433 case ld::Fixup::kindNoneGroupSubordinateLSDA
:
434 assert(fit
->binding
== ld::Fixup::bindingDirectlyBound
);
435 this->markCoalescedAway(fit
->u
.target
);
444 void SymbolTable::undefines(std::vector
<const char*>& undefs
)
446 // return all names in _byNameTable that have no associated atom
447 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
448 //fprintf(stderr, " _byNameTable[%s] = slot %d which has atom %p\n", it->first, it->second, _indirectBindingTable[it->second]);
449 if ( _indirectBindingTable
[it
->second
] == NULL
)
450 undefs
.push_back(it
->first
);
452 // sort so that undefines are in a stable order (not dependent on hashing functions)
453 std::sort(undefs
.begin(), undefs
.end());
457 void SymbolTable::tentativeDefs(std::vector
<const char*>& tents
)
459 // return all names in _byNameTable that have no associated atom
460 for (NameToSlot::iterator it
=_byNameTable
.begin(); it
!= _byNameTable
.end(); ++it
) {
461 const char* name
= it
->first
;
462 const ld::Atom
* atom
= _indirectBindingTable
[it
->second
];
463 if ( (atom
!= NULL
) && (atom
->definition() == ld::Atom::definitionTentative
) )
464 tents
.push_back(name
);
466 std::sort(tents
.begin(), tents
.end());
470 bool SymbolTable::hasName(const char* name
)
472 NameToSlot::iterator pos
= _byNameTable
.find(name
);
473 if ( pos
== _byNameTable
.end() )
475 return (_indirectBindingTable
[pos
->second
] != NULL
);
478 // find existing or create new slot
479 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForName(const char* name
)
481 NameToSlot::iterator pos
= _byNameTable
.find(name
);
482 if ( pos
!= _byNameTable
.end() )
484 // create new slot for this name
485 SymbolTable::IndirectBindingSlot slot
= _indirectBindingTable
.size();
486 _indirectBindingTable
.push_back(NULL
);
487 _byNameTable
[name
] = slot
;
488 _byNameReverseTable
[slot
] = name
;
493 // find existing or create new slot
494 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForContent(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
496 //fprintf(stderr, "findSlotForContent(%p)\n", atom);
497 SymbolTable::IndirectBindingSlot slot
= 0;
498 UTF16StringToSlot::iterator upos
;
499 CStringToSlot::iterator cspos
;
500 ContentToSlot::iterator pos
;
501 switch ( atom
->section().type() ) {
502 case ld::Section::typeCString
:
503 cspos
= _cstringTable
.find(atom
);
504 if ( cspos
!= _cstringTable
.end() ) {
505 *existingAtom
= _indirectBindingTable
[cspos
->second
];
506 return cspos
->second
;
508 slot
= _indirectBindingTable
.size();
509 _cstringTable
[atom
] = slot
;
511 case ld::Section::typeNonStdCString
:
513 // use seg/sect name is key to map to avoid coalescing across segments and sections
515 sprintf(segsect
, "%s/%s", atom
->section().segmentName(), atom
->section().sectionName());
516 NameToMap::iterator mpos
= _nonStdCStringSectionToMap
.find(segsect
);
517 CStringToSlot
* map
= NULL
;
518 if ( mpos
== _nonStdCStringSectionToMap
.end() ) {
519 map
= new CStringToSlot();
520 _nonStdCStringSectionToMap
[strdup(segsect
)] = map
;
525 cspos
= map
->find(atom
);
526 if ( cspos
!= map
->end() ) {
527 *existingAtom
= _indirectBindingTable
[cspos
->second
];
528 return cspos
->second
;
530 slot
= _indirectBindingTable
.size();
531 map
->operator[](atom
) = slot
;
534 case ld::Section::typeUTF16Strings
:
535 upos
= _utf16Table
.find(atom
);
536 if ( upos
!= _utf16Table
.end() ) {
537 *existingAtom
= _indirectBindingTable
[upos
->second
];
540 slot
= _indirectBindingTable
.size();
541 _utf16Table
[atom
] = slot
;
543 case ld::Section::typeLiteral4
:
544 pos
= _literal4Table
.find(atom
);
545 if ( pos
!= _literal4Table
.end() ) {
546 *existingAtom
= _indirectBindingTable
[pos
->second
];
549 slot
= _indirectBindingTable
.size();
550 _literal4Table
[atom
] = slot
;
552 case ld::Section::typeLiteral8
:
553 pos
= _literal8Table
.find(atom
);
554 if ( pos
!= _literal8Table
.end() ) {
555 *existingAtom
= _indirectBindingTable
[pos
->second
];
558 slot
= _indirectBindingTable
.size();
559 _literal8Table
[atom
] = slot
;
561 case ld::Section::typeLiteral16
:
562 pos
= _literal16Table
.find(atom
);
563 if ( pos
!= _literal16Table
.end() ) {
564 *existingAtom
= _indirectBindingTable
[pos
->second
];
567 slot
= _indirectBindingTable
.size();
568 _literal16Table
[atom
] = slot
;
571 assert(0 && "section type does not support coalescing by content");
573 _indirectBindingTable
.push_back(atom
);
574 *existingAtom
= NULL
;
580 // find existing or create new slot
581 SymbolTable::IndirectBindingSlot
SymbolTable::findSlotForReferences(const ld::Atom
* atom
, const ld::Atom
** existingAtom
)
583 //fprintf(stderr, "findSlotForReferences(%p)\n", atom);
585 SymbolTable::IndirectBindingSlot slot
= 0;
586 ReferencesToSlot::iterator pos
;
587 switch ( atom
->section().type() ) {
588 case ld::Section::typeNonLazyPointer
:
589 pos
= _nonLazyPointerTable
.find(atom
);
590 if ( pos
!= _nonLazyPointerTable
.end() ) {
591 *existingAtom
= _indirectBindingTable
[pos
->second
];
594 slot
= _indirectBindingTable
.size();
595 _nonLazyPointerTable
[atom
] = slot
;
597 case ld::Section::typeCFString
:
598 pos
= _cfStringTable
.find(atom
);
599 if ( pos
!= _cfStringTable
.end() ) {
600 *existingAtom
= _indirectBindingTable
[pos
->second
];
603 slot
= _indirectBindingTable
.size();
604 _cfStringTable
[atom
] = slot
;
606 case ld::Section::typeObjCClassRefs
:
607 pos
= _objc2ClassRefTable
.find(atom
);
608 if ( pos
!= _objc2ClassRefTable
.end() ) {
609 *existingAtom
= _indirectBindingTable
[pos
->second
];
612 slot
= _indirectBindingTable
.size();
613 _objc2ClassRefTable
[atom
] = slot
;
615 case ld::Section::typeCStringPointer
:
616 pos
= _pointerToCStringTable
.find(atom
);
617 if ( pos
!= _pointerToCStringTable
.end() ) {
618 *existingAtom
= _indirectBindingTable
[pos
->second
];
621 slot
= _indirectBindingTable
.size();
622 _pointerToCStringTable
[atom
] = slot
;
625 assert(0 && "section type does not support coalescing by references");
627 _indirectBindingTable
.push_back(atom
);
628 *existingAtom
= NULL
;
633 const char* SymbolTable::indirectName(IndirectBindingSlot slot
) const
635 assert(slot
< _indirectBindingTable
.size());
636 const ld::Atom
* target
= _indirectBindingTable
[slot
];
637 if ( target
!= NULL
) {
638 return target
->name();
640 // handle case when by-name reference is indirected and no atom yet in _byNameTable
641 SlotToName::const_iterator pos
= _byNameReverseTable
.find(slot
);
642 if ( pos
!= _byNameReverseTable
.end() )
648 const ld::Atom
* SymbolTable::indirectAtom(IndirectBindingSlot slot
) const
650 assert(slot
< _indirectBindingTable
.size());
651 return _indirectBindingTable
[slot
];
654 extern "C" char* __cxa_demangle (const char* mangled_name
,
659 const char* SymbolTable::demangle(const char* sym
)
661 // only try to demangle symbols if -demangle on command line
662 if ( !_s_doDemangle
)
665 // only try to demangle symbols that look like C++ symbols
666 if ( strncmp(sym
, "__Z", 3) != 0 )
669 static size_t size
= 1024;
670 static char* buff
= (char*)malloc(size
);
673 char* result
= __cxa_demangle(&sym
[1], buff
, &size
, &status
);
674 if ( result
!= NULL
) {
675 // if demangling succesful, keep buffer for next demangle
683 void SymbolTable::printStatistics()
685 // fprintf(stderr, "cstring table size: %lu, bucket count: %lu, hash func called %u times\n",
686 // _cstringTable.size(), _cstringTable.bucket_count(), cstringHashCount);
688 for(unsigned int b
=0; b
< 11; ++b
) {
691 for(unsigned int i
=0; i
< _cstringTable
.bucket_count(); ++i
) {
692 unsigned int n
= _cstringTable
.elems_in_bucket(i
);
698 fprintf(stderr
, "cstring table distribution\n");
699 for(unsigned int b
=0; b
< 11; ++b
) {
700 fprintf(stderr
, "%u buckets have %u elements\n", count
[b
], b
);
702 fprintf(stderr
, "indirect table size: %lu\n", _indirectBindingTable
.size());
703 fprintf(stderr
, "by-name table size: %lu\n", _byNameTable
.size());
704 // fprintf(stderr, "by-content table size: %lu, hash count: %u, equals count: %u, lookup count: %u\n",
705 // _byContentTable.size(), contentHashCount, contentEqualCount, contentLookupCount);
706 // fprintf(stderr, "by-ref table size: %lu, hashed count: %u, equals count: %u, lookup count: %u, insert count: %u\n",
707 // _byReferencesTable.size(), refHashCount, refEqualsCount, refLookupCount, refInsertCount);
709 //ReferencesHash obj;
710 //for(ReferencesHashToSlot::iterator it=_byReferencesTable.begin(); it != _byReferencesTable.end(); ++it) {
711 // if ( obj.operator()(it->first) == 0x2F3AC0EAC744EA70 ) {
712 // fprintf(stderr, "hash=0x2F3AC0EAC744EA70 for %p %s from %s\n", it->first, it->first->name(), it->first->file()->path());