2  * Copyright (c) 2000-2007 Apple Inc. All rights reserved. 
   4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 
   6  * This file contains Original Code and/or Modifications of Original Code 
   7  * as defined in and that are subject to the Apple Public Source License 
   8  * Version 2.0 (the 'License'). You may not use this file except in 
   9  * compliance with the License. The rights granted to you under the License 
  10  * may not be used to create, or enable the creation or redistribution of, 
  11  * unlawful or unlicensed copies of an Apple operating system, or to 
  12  * circumvent, violate, or enable the circumvention or violation of, any 
  13  * terms of an Apple operating system software license agreement. 
  15  * Please obtain a copy of the License at 
  16  * http://www.opensource.apple.com/apsl/ and read it before using this file. 
  18  * The Original Code and all software distributed under the License are 
  19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 
  23  * Please see the License for the specific language governing rights and 
  24  * limitations under the License. 
  26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 
  28 /* IOSymbol.cpp created by gvdl on Fri 1998-11-17 */ 
  31 #include <sys/cdefs.h> 
  33 #include <kern/locks.h> 
  35 #include <libkern/c++/OSSymbol.h> 
  36 #include <libkern/c++/OSLib.h> 
  39 #define super OSString 
  41 typedef struct { unsigned int i
, j
; } OSSymbolPoolState
; 
  45     extern int debug_container_malloc_size
; 
  47 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) 
  52 #define INITIAL_POOL_SIZE  (exp2ml(1 + log2(kInitBucketCount))) 
  54 #define GROW_FACTOR   (1) 
  55 #define SHRINK_FACTOR (3) 
  57 #define GROW_POOL()     do \ 
  58     if (count * GROW_FACTOR > nBuckets) { \ 
  59         reconstructSymbols(true); \ 
  63 #define SHRINK_POOL()     do \ 
  64     if (count * SHRINK_FACTOR < nBuckets && \ 
  65         nBuckets > INITIAL_POOL_SIZE) { \ 
  66         reconstructSymbols(false); \ 
  73     static const unsigned int kInitBucketCount 
= 16; 
  75     typedef struct { unsigned int count
; OSSymbol 
**symbolP
; } Bucket
; 
  78     unsigned int nBuckets
; 
  82     static inline void hashSymbol(const char *s
, 
  86         unsigned int hash 
= 0; 
  89         /* Unroll the loop. */ 
  91             if (!*s
) break; len
++; hash 
^= *s
++; 
  92             if (!*s
) break; len
++; hash 
^= *s
++ <<  8; 
  93             if (!*s
) break; len
++; hash 
^= *s
++ << 16; 
  94             if (!*s
) break; len
++; hash 
^= *s
++ << 24; 
 100     static unsigned long log2(unsigned int x
); 
 101     static unsigned long exp2ml(unsigned int x
); 
 103     void reconstructSymbols(void); 
 104     void reconstructSymbols(bool grow
); 
 107     static void *operator new(size_t size
); 
 108     static void operator delete(void *mem
, size_t size
); 
 111     OSSymbolPool(const OSSymbolPool 
*old
); 
 112     virtual ~OSSymbolPool(); 
 116     inline void closeGate() { lck_mtx_lock(poolGate
); }; 
 117     inline void openGate()  { lck_mtx_unlock(poolGate
); }; 
 119     OSSymbol 
*findSymbol(const char *cString
) const; 
 120     OSSymbol 
*insertSymbol(OSSymbol 
*sym
); 
 121     void removeSymbol(OSSymbol 
*sym
); 
 123     OSSymbolPoolState 
initHashState(); 
 124     OSSymbol 
*nextHashState(OSSymbolPoolState 
*stateP
); 
 127 void * OSSymbolPool::operator new(size_t size
) 
 129     void *mem 
= (void *)kalloc(size
); 
 137 void OSSymbolPool::operator delete(void *mem
, size_t size
) 
 143 extern lck_grp_t 
*IOLockGroup
; 
 145 bool OSSymbolPool::init() 
 148     nBuckets 
= INITIAL_POOL_SIZE
; 
 149     buckets 
= (Bucket 
*) kalloc(nBuckets 
* sizeof(Bucket
)); 
 150     ACCUMSIZE(nBuckets 
* sizeof(Bucket
)); 
 154     bzero(buckets
, nBuckets 
* sizeof(Bucket
)); 
 156     poolGate 
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
); 
 158     return poolGate 
!= 0; 
 161 OSSymbolPool::OSSymbolPool(const OSSymbolPool 
*old
) 
 164     nBuckets 
= old
->nBuckets
; 
 165     buckets 
= old
->buckets
; 
 167     poolGate 
= 0;       // Do not duplicate the poolGate 
 170 OSSymbolPool::~OSSymbolPool() 
 174         for (thisBucket 
= &buckets
[0]; thisBucket 
< &buckets
[nBuckets
]; thisBucket
++) { 
 175             if (thisBucket
->count 
> 1) { 
 176                 kfree(thisBucket
->symbolP
, thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 177                 ACCUMSIZE(-(thisBucket
->count 
* sizeof(OSSymbol 
*))); 
 180         kfree(buckets
, nBuckets 
* sizeof(Bucket
)); 
 181         ACCUMSIZE(-(nBuckets 
* sizeof(Bucket
))); 
 185         lck_mtx_free(poolGate
, IOLockGroup
); 
 188 unsigned long OSSymbolPool::log2(unsigned int x
) 
 192     for (i 
= 0; x 
> 1 ; i
++) 
 197 unsigned long OSSymbolPool::exp2ml(unsigned int x
) 
 202 OSSymbolPoolState 
OSSymbolPool::initHashState() 
 204     OSSymbolPoolState newState 
= { nBuckets
, 0 }; 
 208 OSSymbol 
*OSSymbolPool::nextHashState(OSSymbolPoolState 
*stateP
) 
 210     Bucket 
*thisBucket 
= &buckets
[stateP
->i
]; 
 217         stateP
->j 
= thisBucket
->count
; 
 221     if (thisBucket
->count 
== 1) 
 222         return (OSSymbol 
*) thisBucket
->symbolP
; 
 224         return thisBucket
->symbolP
[stateP
->j
]; 
 227 void OSSymbolPool::reconstructSymbols(void) 
 229     this->reconstructSymbols(true); 
 232 void OSSymbolPool::reconstructSymbols(bool grow
) 
 234     unsigned int new_nBuckets 
= nBuckets
; 
 236     OSSymbolPoolState state
; 
 239         new_nBuckets 
+= new_nBuckets 
+ 1; 
 241        /* Don't shrink the pool below the default initial size. 
 243         if (nBuckets 
<= INITIAL_POOL_SIZE
) { 
 246         new_nBuckets 
= (new_nBuckets 
- 1) / 2; 
 249    /* Create old pool to iterate after doing above check, cause it 
 250     * gets finalized at return. 
 252     OSSymbolPool 
old(this); 
 255     nBuckets 
= new_nBuckets
; 
 256     buckets 
= (Bucket 
*) kalloc(nBuckets 
* sizeof(Bucket
)); 
 257     ACCUMSIZE(nBuckets 
* sizeof(Bucket
)); 
 258     /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 259     bzero(buckets
, nBuckets 
* sizeof(Bucket
)); 
 261     state 
= old
.initHashState(); 
 262     while ( (insert 
= old
.nextHashState(&state
)) ) 
 263         insertSymbol(insert
); 
 266 OSSymbol 
*OSSymbolPool::findSymbol(const char *cString
) const 
 269     unsigned int j
, inLen
, hash
; 
 270     OSSymbol 
*probeSymbol
, **list
; 
 272     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 273     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 274     j 
= thisBucket
->count
; 
 280         probeSymbol 
= (OSSymbol 
*) thisBucket
->symbolP
; 
 282         if (inLen 
== probeSymbol
->length
 
 283         &&  (strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0)) 
 288     for (list 
= thisBucket
->symbolP
; j
--; list
++) { 
 290         if (inLen 
== probeSymbol
->length
 
 291         &&  (strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0)) 
 298 OSSymbol 
*OSSymbolPool::insertSymbol(OSSymbol 
*sym
) 
 300     const char *cString 
= sym
->string
; 
 302     unsigned int j
, inLen
, hash
; 
 303     OSSymbol 
*probeSymbol
, **list
; 
 305     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 306     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 307     j 
= thisBucket
->count
; 
 310         thisBucket
->symbolP 
= (OSSymbol 
**) sym
; 
 317         probeSymbol 
= (OSSymbol 
*) thisBucket
->symbolP
; 
 319         if (inLen 
== probeSymbol
->length
 
 320         &&  strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0) 
 323         list 
= (OSSymbol 
**) kalloc(2 * sizeof(OSSymbol 
*)); 
 324         ACCUMSIZE(2 * sizeof(OSSymbol 
*)); 
 325         /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 327         list
[1] = probeSymbol
; 
 328         thisBucket
->symbolP 
= list
; 
 336     for (list 
= thisBucket
->symbolP
; j
--; list
++) { 
 338         if (inLen 
== probeSymbol
->length
 
 339         &&  strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0) 
 343     j 
= thisBucket
->count
++; 
 345     list 
= (OSSymbol 
**) kalloc(thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 346     ACCUMSIZE(thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 347     /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 349     bcopy(thisBucket
->symbolP
, list 
+ 1, j 
* sizeof(OSSymbol 
*)); 
 350     kfree(thisBucket
->symbolP
, j 
* sizeof(OSSymbol 
*)); 
 351     ACCUMSIZE(-(j 
* sizeof(OSSymbol 
*))); 
 352     thisBucket
->symbolP 
= list
; 
 358 void OSSymbolPool::removeSymbol(OSSymbol 
*sym
) 
 361     unsigned int j
, inLen
, hash
; 
 362     OSSymbol 
*probeSymbol
, **list
; 
 364     hashSymbol(sym
->string
, &hash
, &inLen
); inLen
++; 
 365     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 366     j 
= thisBucket
->count
; 
 367     list 
= thisBucket
->symbolP
; 
 370         // couldn't find the symbol; probably means string hash changed 
 371         panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 376         probeSymbol 
= (OSSymbol 
*) list
; 
 378         if (probeSymbol 
== sym
) { 
 379             thisBucket
->symbolP 
= 0; 
 385         // couldn't find the symbol; probably means string hash changed 
 386         panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 391         probeSymbol 
= list
[0]; 
 392         if (probeSymbol 
== sym
) { 
 393             thisBucket
->symbolP 
= (OSSymbol 
**) list
[1]; 
 394             kfree(list
, 2 * sizeof(OSSymbol 
*)); 
 395             ACCUMSIZE(-(2 * sizeof(OSSymbol 
*))); 
 402         probeSymbol 
= list
[1]; 
 403         if (probeSymbol 
== sym
) { 
 404             thisBucket
->symbolP 
= (OSSymbol 
**) list
[0]; 
 405             kfree(list
, 2 * sizeof(OSSymbol 
*)); 
 406             ACCUMSIZE(-(2 * sizeof(OSSymbol 
*))); 
 412         // couldn't find the symbol; probably means string hash changed 
 413         panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 417     for (; j
--; list
++) { 
 419         if (probeSymbol 
== sym
) { 
 422                 kalloc((thisBucket
->count
-1) * sizeof(OSSymbol 
*)); 
 423             ACCUMSIZE((thisBucket
->count
-1) * sizeof(OSSymbol 
*)); 
 424             if (thisBucket
->count
-1 != j
) 
 425                 bcopy(thisBucket
->symbolP
, list
, 
 426                       (thisBucket
->count
-1-j
) * sizeof(OSSymbol 
*)); 
 428                 bcopy(thisBucket
->symbolP 
+ thisBucket
->count
-j
, 
 429                       list 
+ thisBucket
->count
-1-j
, 
 430                       j 
* sizeof(OSSymbol 
*)); 
 431             kfree(thisBucket
->symbolP
, thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 432             ACCUMSIZE(-(thisBucket
->count 
* sizeof(OSSymbol 
*))); 
 433             thisBucket
->symbolP 
= list
; 
 439     // couldn't find the symbol; probably means string hash changed 
 440     panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 444  ********************************************************************* 
 445  * From here on we are actually implementing the OSSymbol class 
 446  ********************************************************************* 
 448 OSDefineMetaClassAndStructorsWithInit(OSSymbol
, OSString
, 
 449                                       OSSymbol::initialize()) 
 450 OSMetaClassDefineReservedUnused(OSSymbol
, 0); 
 451 OSMetaClassDefineReservedUnused(OSSymbol
, 1); 
 452 OSMetaClassDefineReservedUnused(OSSymbol
, 2); 
 453 OSMetaClassDefineReservedUnused(OSSymbol
, 3); 
 454 OSMetaClassDefineReservedUnused(OSSymbol
, 4); 
 455 OSMetaClassDefineReservedUnused(OSSymbol
, 5); 
 456 OSMetaClassDefineReservedUnused(OSSymbol
, 6); 
 457 OSMetaClassDefineReservedUnused(OSSymbol
, 7); 
 459 static OSSymbolPool 
*pool
; 
 461 void OSSymbol::initialize() 
 463     pool 
= new OSSymbolPool
; 
 466     if (pool 
&& !pool
->init()) { 
 472 bool OSSymbol::initWithCStringNoCopy(const char *) { return false; } 
 473 bool OSSymbol::initWithCString(const char *) { return false; } 
 474 bool OSSymbol::initWithString(const OSString 
*) { return false; } 
 476 const OSSymbol 
*OSSymbol::withString(const OSString 
*aString
) 
 478     // This string may be a OSSymbol already, cheap check. 
 479     if (OSDynamicCast(OSSymbol
, aString
)) { 
 481         return (const OSSymbol 
*) aString
; 
 483     else if (((const OSSymbol 
*) aString
)->flags 
& kOSStringNoCopy
) 
 484         return OSSymbol::withCStringNoCopy(aString
->getCStringNoCopy()); 
 486         return OSSymbol::withCString(aString
->getCStringNoCopy()); 
 489 const OSSymbol 
*OSSymbol::withCString(const char *cString
) 
 493     OSSymbol 
*oldSymb 
= pool
->findSymbol(cString
); 
 495         OSSymbol 
*newSymb 
= new OSSymbol
; 
 501         if (newSymb
->OSString::initWithCString(cString
)) 
 502             oldSymb 
= pool
->insertSymbol(newSymb
); 
 504         if (newSymb 
== oldSymb
) { 
 506             return newSymb
;     // return the newly created & inserted symbol. 
 509             // Somebody else inserted the new symbol so free our copy 
 510             newSymb
->OSString::free(); 
 513     oldSymb
->retain();  // Retain the old symbol before releasing the lock. 
 519 const OSSymbol 
*OSSymbol::withCStringNoCopy(const char *cString
) 
 523     OSSymbol 
*oldSymb 
= pool
->findSymbol(cString
); 
 525         OSSymbol 
*newSymb 
= new OSSymbol
; 
 531         if (newSymb
->OSString::initWithCStringNoCopy(cString
)) 
 532             oldSymb 
= pool
->insertSymbol(newSymb
); 
 534         if (newSymb 
== oldSymb
) { 
 536             return newSymb
;     // return the newly created & inserted symbol. 
 539             // Somebody else inserted the new symbol so free our copy 
 540             newSymb
->OSString::free(); 
 543     oldSymb
->retain();  // Retain the old symbol before releasing the lock. 
 549 void OSSymbol::checkForPageUnload(void *startAddr
, void *endAddr
) 
 551     OSSymbol 
*probeSymbol
; 
 552     OSSymbolPoolState state
; 
 555     state 
= pool
->initHashState(); 
 556     while ( (probeSymbol 
= pool
->nextHashState(&state
)) ) { 
 557         if (probeSymbol
->string 
>= startAddr 
&& probeSymbol
->string 
< endAddr
) { 
 558             const char *oldString 
= probeSymbol
->string
; 
 560             probeSymbol
->string 
= (char *) kalloc(probeSymbol
->length
); 
 561             ACCUMSIZE(probeSymbol
->length
); 
 562             bcopy(oldString
, probeSymbol
->string
, probeSymbol
->length
); 
 563             probeSymbol
->flags 
&= ~kOSStringNoCopy
; 
 569 void OSSymbol::taggedRelease(const void *tag
) const 
 571     super::taggedRelease(tag
); 
 574 void OSSymbol::taggedRelease(const void *tag
, const int when
) const 
 577     super::taggedRelease(tag
, when
); 
 581 void OSSymbol::free() 
 583     pool
->removeSymbol(this); 
 587 bool OSSymbol::isEqualTo(const char *aCString
) const 
 589     return super::isEqualTo(aCString
); 
 592 bool OSSymbol::isEqualTo(const OSSymbol 
*aSymbol
) const 
 594     return aSymbol 
== this; 
 597 bool OSSymbol::isEqualTo(const OSMetaClassBase 
*obj
) const 
 602     if ((sym 
= OSDynamicCast(OSSymbol
, obj
))) 
 603         return isEqualTo(sym
); 
 604     else if ((str 
= OSDynamicCast(OSString
, obj
))) 
 605         return super::isEqualTo(str
); 
 614         unsigned int  arrayCount
, 
 618     unsigned int baseIdx 
= 0; 
 621     for (lim 
= arrayCount
; lim
; lim 
>>= 1) 
 623         p 
= (typeof(p
)) (((uintptr_t) array
) + (baseIdx 
+ (lim 
>> 1)) * memberSize
); 
 626             return (baseIdx 
+ (lim 
>> 1)); 
 631             baseIdx 
+= (lim 
>> 1) + 1; 
 636     // not found, insertion point here 
 637     return (baseIdx 
+ (lim 
>> 1));