2  * Copyright (c) 2000-2016 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
; 
  43 #define INITIAL_POOL_SIZE  (exp2ml(1 + log2(kInitBucketCount))) 
  45 #define GROW_FACTOR   (1) 
  46 #define SHRINK_FACTOR (3) 
  48 #define GROW_POOL()     do \ 
  49     if (count * GROW_FACTOR > nBuckets) { \ 
  50         reconstructSymbols(true); \ 
  54 #define SHRINK_POOL()     do \ 
  55     if (count * SHRINK_FACTOR < nBuckets && \ 
  56         nBuckets > INITIAL_POOL_SIZE) { \ 
  57         reconstructSymbols(false); \ 
  64     static const unsigned int kInitBucketCount 
= 16; 
  66     typedef struct { unsigned int count
; OSSymbol 
**symbolP
; } Bucket
; 
  69     unsigned int nBuckets
; 
  73     static inline void hashSymbol(const char *s
, 
  77         unsigned int hash 
= 0; 
  80         /* Unroll the loop. */ 
  82             if (!*s
) break; len
++; hash 
^= *s
++; 
  83             if (!*s
) break; len
++; hash 
^= *s
++ <<  8; 
  84             if (!*s
) break; len
++; hash 
^= *s
++ << 16; 
  85             if (!*s
) break; len
++; hash 
^= *s
++ << 24; 
  91     static unsigned long log2(unsigned int x
); 
  92     static unsigned long exp2ml(unsigned int x
); 
  94     void reconstructSymbols(void); 
  95     void reconstructSymbols(bool grow
); 
  98     static void *operator new(size_t size
); 
  99     static void operator delete(void *mem
, size_t size
); 
 102     OSSymbolPool(const OSSymbolPool 
*old
); 
 103     virtual ~OSSymbolPool(); 
 107     inline void closeGate() { lck_mtx_lock(poolGate
); } 
 108     inline void openGate()  { lck_mtx_unlock(poolGate
); } 
 110     OSSymbol 
*findSymbol(const char *cString
) const; 
 111     OSSymbol 
*insertSymbol(OSSymbol 
*sym
); 
 112     void removeSymbol(OSSymbol 
*sym
); 
 114     OSSymbolPoolState 
initHashState(); 
 115     OSSymbol 
*nextHashState(OSSymbolPoolState 
*stateP
); 
 118 void * OSSymbolPool::operator new(size_t size
) 
 120     void *mem 
= (void *)kalloc_tag(size
, VM_KERN_MEMORY_LIBKERN
); 
 121     OSMETA_ACCUMSIZE(size
); 
 128 void OSSymbolPool::operator delete(void *mem
, size_t size
) 
 131     OSMETA_ACCUMSIZE(-size
); 
 134 extern lck_grp_t 
*IOLockGroup
; 
 136 bool OSSymbolPool::init() 
 139     nBuckets 
= INITIAL_POOL_SIZE
; 
 140     buckets 
= (Bucket 
*) kalloc_tag(nBuckets 
* sizeof(Bucket
), VM_KERN_MEMORY_LIBKERN
); 
 141     OSMETA_ACCUMSIZE(nBuckets 
* sizeof(Bucket
)); 
 145     bzero(buckets
, nBuckets 
* sizeof(Bucket
)); 
 147     poolGate 
= lck_mtx_alloc_init(IOLockGroup
, LCK_ATTR_NULL
); 
 149     return poolGate 
!= 0; 
 152 OSSymbolPool::OSSymbolPool(const OSSymbolPool 
*old
) 
 155     nBuckets 
= old
->nBuckets
; 
 156     buckets 
= old
->buckets
; 
 158     poolGate 
= 0;       // Do not duplicate the poolGate 
 161 OSSymbolPool::~OSSymbolPool() 
 165         for (thisBucket 
= &buckets
[0]; thisBucket 
< &buckets
[nBuckets
]; thisBucket
++) { 
 166             if (thisBucket
->count 
> 1) { 
 167                 kfree(thisBucket
->symbolP
, thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 168                 OSMETA_ACCUMSIZE(-(thisBucket
->count 
* sizeof(OSSymbol 
*))); 
 171         kfree(buckets
, nBuckets 
* sizeof(Bucket
)); 
 172         OSMETA_ACCUMSIZE(-(nBuckets 
* sizeof(Bucket
))); 
 176         lck_mtx_free(poolGate
, IOLockGroup
); 
 179 unsigned long OSSymbolPool::log2(unsigned int x
) 
 183     for (i 
= 0; x 
> 1 ; i
++) 
 188 unsigned long OSSymbolPool::exp2ml(unsigned int x
) 
 193 OSSymbolPoolState 
OSSymbolPool::initHashState() 
 195     OSSymbolPoolState newState 
= { nBuckets
, 0 }; 
 199 OSSymbol 
*OSSymbolPool::nextHashState(OSSymbolPoolState 
*stateP
) 
 201     Bucket 
*thisBucket 
= &buckets
[stateP
->i
]; 
 208         stateP
->j 
= thisBucket
->count
; 
 212     if (thisBucket
->count 
== 1) 
 213         return (OSSymbol 
*) thisBucket
->symbolP
; 
 215         return thisBucket
->symbolP
[stateP
->j
]; 
 218 void OSSymbolPool::reconstructSymbols(void) 
 220     this->reconstructSymbols(true); 
 223 void OSSymbolPool::reconstructSymbols(bool grow
) 
 225     unsigned int new_nBuckets 
= nBuckets
; 
 227     OSSymbolPoolState state
; 
 230         new_nBuckets 
+= new_nBuckets 
+ 1; 
 232        /* Don't shrink the pool below the default initial size. 
 234         if (nBuckets 
<= INITIAL_POOL_SIZE
) { 
 237         new_nBuckets 
= (new_nBuckets 
- 1) / 2; 
 240    /* Create old pool to iterate after doing above check, cause it 
 241     * gets finalized at return. 
 243     OSSymbolPool 
old(this); 
 246     nBuckets 
= new_nBuckets
; 
 247     buckets 
= (Bucket 
*) kalloc_tag(nBuckets 
* sizeof(Bucket
), VM_KERN_MEMORY_LIBKERN
); 
 248     OSMETA_ACCUMSIZE(nBuckets 
* sizeof(Bucket
)); 
 249     /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 250     bzero(buckets
, nBuckets 
* sizeof(Bucket
)); 
 252     state 
= old
.initHashState(); 
 253     while ( (insert 
= old
.nextHashState(&state
)) ) 
 254         insertSymbol(insert
); 
 257 OSSymbol 
*OSSymbolPool::findSymbol(const char *cString
) const 
 260     unsigned int j
, inLen
, hash
; 
 261     OSSymbol 
*probeSymbol
, **list
; 
 263     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 264     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 265     j 
= thisBucket
->count
; 
 271         probeSymbol 
= (OSSymbol 
*) thisBucket
->symbolP
; 
 273         if (inLen 
== probeSymbol
->length
 
 274         &&  (strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0)) 
 279     for (list 
= thisBucket
->symbolP
; j
--; list
++) { 
 281         if (inLen 
== probeSymbol
->length
 
 282         &&  (strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0)) 
 289 OSSymbol 
*OSSymbolPool::insertSymbol(OSSymbol 
*sym
) 
 291     const char *cString 
= sym
->string
; 
 293     unsigned int j
, inLen
, hash
; 
 294     OSSymbol 
*probeSymbol
, **list
; 
 296     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 297     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 298     j 
= thisBucket
->count
; 
 301         thisBucket
->symbolP 
= (OSSymbol 
**) sym
; 
 308         probeSymbol 
= (OSSymbol 
*) thisBucket
->symbolP
; 
 310         if (inLen 
== probeSymbol
->length
 
 311         &&  strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0) 
 314         list 
= (OSSymbol 
**) kalloc_tag(2 * sizeof(OSSymbol 
*), VM_KERN_MEMORY_LIBKERN
); 
 315         OSMETA_ACCUMSIZE(2 * sizeof(OSSymbol 
*)); 
 316         /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 318         list
[1] = probeSymbol
; 
 319         thisBucket
->symbolP 
= list
; 
 327     for (list 
= thisBucket
->symbolP
; j
--; list
++) { 
 329         if (inLen 
== probeSymbol
->length
 
 330         &&  strncmp(probeSymbol
->string
, cString
, probeSymbol
->length
) == 0) 
 334     j 
= thisBucket
->count
++; 
 336     list 
= (OSSymbol 
**) kalloc_tag(thisBucket
->count 
* sizeof(OSSymbol 
*), VM_KERN_MEMORY_LIBKERN
); 
 337     OSMETA_ACCUMSIZE(thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 338     /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 340     bcopy(thisBucket
->symbolP
, list 
+ 1, j 
* sizeof(OSSymbol 
*)); 
 341     kfree(thisBucket
->symbolP
, j 
* sizeof(OSSymbol 
*)); 
 342     OSMETA_ACCUMSIZE(-(j 
* sizeof(OSSymbol 
*))); 
 343     thisBucket
->symbolP 
= list
; 
 349 void OSSymbolPool::removeSymbol(OSSymbol 
*sym
) 
 352     unsigned int j
, inLen
, hash
; 
 353     OSSymbol 
*probeSymbol
, **list
; 
 355     hashSymbol(sym
->string
, &hash
, &inLen
); inLen
++; 
 356     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 357     j 
= thisBucket
->count
; 
 358     list 
= thisBucket
->symbolP
; 
 361         // couldn't find the symbol; probably means string hash changed 
 362         panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 367         probeSymbol 
= (OSSymbol 
*) list
; 
 369         if (probeSymbol 
== sym
) { 
 370             thisBucket
->symbolP 
= 0; 
 376         // couldn't find the symbol; probably means string hash changed 
 377         panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 382         probeSymbol 
= list
[0]; 
 383         if (probeSymbol 
== sym
) { 
 384             thisBucket
->symbolP 
= (OSSymbol 
**) list
[1]; 
 385             kfree(list
, 2 * sizeof(OSSymbol 
*)); 
 386             OSMETA_ACCUMSIZE(-(2 * sizeof(OSSymbol 
*))); 
 393         probeSymbol 
= list
[1]; 
 394         if (probeSymbol 
== sym
) { 
 395             thisBucket
->symbolP 
= (OSSymbol 
**) list
[0]; 
 396             kfree(list
, 2 * sizeof(OSSymbol 
*)); 
 397             OSMETA_ACCUMSIZE(-(2 * sizeof(OSSymbol 
*))); 
 403         // couldn't find the symbol; probably means string hash changed 
 404         panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 408     for (; j
--; list
++) { 
 410         if (probeSymbol 
== sym
) { 
 413                 kalloc_tag((thisBucket
->count
-1) * sizeof(OSSymbol 
*), VM_KERN_MEMORY_LIBKERN
); 
 414             OSMETA_ACCUMSIZE((thisBucket
->count
-1) * sizeof(OSSymbol 
*)); 
 415             if (thisBucket
->count
-1 != j
) 
 416                 bcopy(thisBucket
->symbolP
, list
, 
 417                       (thisBucket
->count
-1-j
) * sizeof(OSSymbol 
*)); 
 419                 bcopy(thisBucket
->symbolP 
+ thisBucket
->count
-j
, 
 420                       list 
+ thisBucket
->count
-1-j
, 
 421                       j 
* sizeof(OSSymbol 
*)); 
 422             kfree(thisBucket
->symbolP
, thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 423             OSMETA_ACCUMSIZE(-(thisBucket
->count 
* sizeof(OSSymbol 
*))); 
 424             thisBucket
->symbolP 
= list
; 
 430     // couldn't find the symbol; probably means string hash changed 
 431     panic("removeSymbol %s count %d ", sym
->string 
? sym
->string 
: "no string", count
); 
 435  ********************************************************************* 
 436  * From here on we are actually implementing the OSSymbol class 
 437  ********************************************************************* 
 439 OSDefineMetaClassAndStructorsWithInit(OSSymbol
, OSString
, 
 440                                       OSSymbol::initialize()) 
 441 OSMetaClassDefineReservedUnused(OSSymbol
, 0); 
 442 OSMetaClassDefineReservedUnused(OSSymbol
, 1); 
 443 OSMetaClassDefineReservedUnused(OSSymbol
, 2); 
 444 OSMetaClassDefineReservedUnused(OSSymbol
, 3); 
 445 OSMetaClassDefineReservedUnused(OSSymbol
, 4); 
 446 OSMetaClassDefineReservedUnused(OSSymbol
, 5); 
 447 OSMetaClassDefineReservedUnused(OSSymbol
, 6); 
 448 OSMetaClassDefineReservedUnused(OSSymbol
, 7); 
 450 static OSSymbolPool 
*pool
; 
 452 void OSSymbol::initialize() 
 454     pool 
= new OSSymbolPool
; 
 457     if (pool 
&& !pool
->init()) { 
 463 bool OSSymbol::initWithCStringNoCopy(const char *) { return false; } 
 464 bool OSSymbol::initWithCString(const char *) { return false; } 
 465 bool OSSymbol::initWithString(const OSString 
*) { return false; } 
 467 const OSSymbol 
*OSSymbol::withString(const OSString 
*aString
) 
 469     // This string may be a OSSymbol already, cheap check. 
 470     if (OSDynamicCast(OSSymbol
, aString
)) { 
 472         return (const OSSymbol 
*) aString
; 
 474     else if (((const OSSymbol 
*) aString
)->flags 
& kOSStringNoCopy
) 
 475         return OSSymbol::withCStringNoCopy(aString
->getCStringNoCopy()); 
 477         return OSSymbol::withCString(aString
->getCStringNoCopy()); 
 480 const OSSymbol 
*OSSymbol::withCString(const char *cString
) 
 484     OSSymbol 
*oldSymb 
= pool
->findSymbol(cString
); 
 486         OSSymbol 
*newSymb 
= new OSSymbol
; 
 492         if (newSymb
->OSString::initWithCString(cString
)) 
 493             oldSymb 
= pool
->insertSymbol(newSymb
); 
 495         if (newSymb 
== oldSymb
) { 
 497             return newSymb
;     // return the newly created & inserted symbol. 
 500             // Somebody else inserted the new symbol so free our copy 
 501             newSymb
->OSString::free(); 
 504     oldSymb
->retain();  // Retain the old symbol before releasing the lock. 
 510 const OSSymbol 
*OSSymbol::withCStringNoCopy(const char *cString
) 
 514     OSSymbol 
*oldSymb 
= pool
->findSymbol(cString
); 
 516         OSSymbol 
*newSymb 
= new OSSymbol
; 
 522         if (newSymb
->OSString::initWithCStringNoCopy(cString
)) 
 523             oldSymb 
= pool
->insertSymbol(newSymb
); 
 525         if (newSymb 
== oldSymb
) { 
 527             return newSymb
;     // return the newly created & inserted symbol. 
 530             // Somebody else inserted the new symbol so free our copy 
 531             newSymb
->OSString::free(); 
 534     oldSymb
->retain();  // Retain the old symbol before releasing the lock. 
 540 void OSSymbol::checkForPageUnload(void *startAddr
, void *endAddr
) 
 542     OSSymbol 
*probeSymbol
; 
 543     OSSymbolPoolState state
; 
 546     state 
= pool
->initHashState(); 
 547     while ( (probeSymbol 
= pool
->nextHashState(&state
)) ) { 
 548         if (probeSymbol
->string 
>= startAddr 
&& probeSymbol
->string 
< endAddr
) { 
 549             probeSymbol
->OSString::initWithCString(probeSymbol
->string
); 
 555 void OSSymbol::taggedRelease(const void *tag
) const 
 557     super::taggedRelease(tag
); 
 560 void OSSymbol::taggedRelease(const void *tag
, const int when
) const 
 563     super::taggedRelease(tag
, when
); 
 567 void OSSymbol::free() 
 569     pool
->removeSymbol(this); 
 573 bool OSSymbol::isEqualTo(const char *aCString
) const 
 575     return super::isEqualTo(aCString
); 
 578 bool OSSymbol::isEqualTo(const OSSymbol 
*aSymbol
) const 
 580     return aSymbol 
== this; 
 583 bool OSSymbol::isEqualTo(const OSMetaClassBase 
*obj
) const 
 588     if ((sym 
= OSDynamicCast(OSSymbol
, obj
))) 
 589         return isEqualTo(sym
); 
 590     else if ((str 
= OSDynamicCast(OSString
, obj
))) 
 591         return super::isEqualTo(str
); 
 600         unsigned int  arrayCount
, 
 604     unsigned int baseIdx 
= 0; 
 607     for (lim 
= arrayCount
; lim
; lim 
>>= 1) 
 609         p 
= (typeof(p
)) (((uintptr_t) array
) + (baseIdx 
+ (lim 
>> 1)) * memberSize
); 
 612             return (baseIdx 
+ (lim 
>> 1)); 
 617             baseIdx 
+= (lim 
>> 1) + 1; 
 622     // not found, insertion point here 
 623     return (baseIdx 
+ (lim 
>> 1));