2  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. 
   4  * @APPLE_LICENSE_HEADER_START@ 
   6  * The contents of this file constitute Original Code as defined in and 
   7  * are subject to the Apple Public Source License Version 1.1 (the 
   8  * "License").  You may not use this file except in compliance with the 
   9  * License.  Please obtain a copy of the License at 
  10  * http://www.apple.com/publicsource and read it before using this file. 
  12  * This Original Code and all software distributed under the License are 
  13  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER 
  14  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 
  15  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 
  16  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the 
  17  * License for the specific language governing rights and limitations 
  20  * @APPLE_LICENSE_HEADER_END@ 
  22 /* IOSymbol.cpp created by gvdl on Fri 1998-11-17 */ 
  24 #include <sys/cdefs.h> 
  27 #include <kern/lock.h> 
  30 #include <libkern/c++/OSSymbol.h> 
  31 #include <libkern/c++/OSLib.h> 
  33 #define super OSString 
  35 typedef struct { int i
, j
; } OSSymbolPoolState
; 
  39     extern int debug_container_malloc_size
; 
  41 #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0) 
  49     static const unsigned int kInitBucketCount 
= 16; 
  51     typedef struct { unsigned int count
; OSSymbol 
**symbolP
; } Bucket
; 
  54     unsigned int nBuckets
; 
  58     static inline void hashSymbol(const char *s
, 
  62         unsigned int hash 
= 0; 
  65         /* Unroll the loop. */ 
  67             if (!*s
) break; len
++; hash 
^= *s
++; 
  68             if (!*s
) break; len
++; hash 
^= *s
++ <<  8; 
  69             if (!*s
) break; len
++; hash 
^= *s
++ << 16; 
  70             if (!*s
) break; len
++; hash 
^= *s
++ << 24; 
  76     static unsigned long log2(unsigned int x
); 
  77     static unsigned long exp2ml(unsigned int x
); 
  79     void reconstructSymbols(); 
  82     static void *operator new(size_t size
); 
  83     static void operator delete(void *mem
, size_t size
); 
  86     OSSymbolPool(const OSSymbolPool 
*old
); 
  87     virtual ~OSSymbolPool(); 
  91     inline void closeGate() { mutex_lock(poolGate
); }; 
  92     inline void openGate()  { mutex_unlock(poolGate
); }; 
  94     OSSymbol 
*findSymbol(const char *cString
) const; 
  95     OSSymbol 
*insertSymbol(OSSymbol 
*sym
); 
  96     void removeSymbol(const char *cString
); 
  98     OSSymbolPoolState 
initHashState(); 
  99     OSSymbol 
*nextHashState(OSSymbolPoolState 
*stateP
); 
 102 void * OSSymbolPool::operator new(size_t size
) 
 104     void *mem 
= (void *)kalloc(size
); 
 112 void OSSymbolPool::operator delete(void *mem
, size_t size
) 
 114     kfree((vm_offset_t
)mem
, size
); 
 118 bool OSSymbolPool::init() 
 121     nBuckets 
= exp2ml(1 + log2(kInitBucketCount
)); 
 122     buckets 
= (Bucket 
*) kalloc(nBuckets 
* sizeof(Bucket
)); 
 123     ACCUMSIZE(nBuckets 
* sizeof(Bucket
)); 
 127     bzero(buckets
, nBuckets 
* sizeof(Bucket
)); 
 129     poolGate 
= mutex_alloc(0); 
 131     return poolGate 
!= 0; 
 134 OSSymbolPool::OSSymbolPool(const OSSymbolPool 
*old
) 
 137     nBuckets 
= old
->nBuckets
; 
 138     buckets 
= old
->buckets
; 
 140     poolGate 
= 0;       // Do not duplicate the poolGate 
 143 OSSymbolPool::~OSSymbolPool() 
 146         kfree((vm_offset_t
)buckets
, nBuckets 
* sizeof(Bucket
)); 
 147         ACCUMSIZE(-(nBuckets 
* sizeof(Bucket
))); 
 151         kfree((vm_offset_t
) poolGate
, 36 * 4); 
 154 unsigned long OSSymbolPool::log2(unsigned int x
) 
 158     for (i 
= 0; x 
> 1 ; i
++) 
 163 unsigned long OSSymbolPool::exp2ml(unsigned int x
) 
 168 OSSymbolPoolState 
OSSymbolPool::initHashState() 
 170     OSSymbolPoolState newState 
= { nBuckets
, 0 }; 
 174 OSSymbol 
*OSSymbolPool::nextHashState(OSSymbolPoolState 
*stateP
) 
 176     Bucket 
*thisBucket 
= &buckets
[stateP
->i
]; 
 183         stateP
->j 
= thisBucket
->count
; 
 187     if (thisBucket
->count 
== 1) 
 188         return (OSSymbol 
*) thisBucket
->symbolP
; 
 190         return thisBucket
->symbolP
[stateP
->j
]; 
 193 void OSSymbolPool::reconstructSymbols() 
 195     OSSymbolPool 
old(this); 
 197     OSSymbolPoolState state
; 
 199     nBuckets 
+= nBuckets 
+ 1; 
 201     buckets 
= (Bucket 
*) kalloc(nBuckets 
* sizeof(Bucket
)); 
 202     ACCUMSIZE(nBuckets 
* sizeof(Bucket
)); 
 203     /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 204     bzero(buckets
, nBuckets 
* sizeof(Bucket
)); 
 206     state 
= old
.initHashState(); 
 207     while ( (insert 
= old
.nextHashState(&state
)) ) 
 208         insertSymbol(insert
); 
 211 OSSymbol 
*OSSymbolPool::findSymbol(const char *cString
) const 
 214     unsigned int j
, inLen
, hash
; 
 215     OSSymbol 
*probeSymbol
, **list
; 
 217     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 218     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 219     j 
= thisBucket
->count
; 
 225         probeSymbol 
= (OSSymbol 
*) thisBucket
->symbolP
; 
 227         if (inLen 
== probeSymbol
->length
 
 228         &&  (strcmp(probeSymbol
->string
, cString
) == 0) 
 229         &&  (probeSymbol
->getRetainCount() >= 1))       // WRONG need when 
 235     for (list 
= thisBucket
->symbolP
; j
--; list
++) { 
 237         if (inLen 
== probeSymbol
->length
 
 238         &&  (strcmp(probeSymbol
->string
, cString
) == 0) 
 239         &&  (probeSymbol
->getRetainCount() >= 1))       // WRONG need when 
 246 OSSymbol 
*OSSymbolPool::insertSymbol(OSSymbol 
*sym
) 
 248     const char *cString 
= sym
->string
; 
 250     unsigned int j
, inLen
, hash
; 
 251     OSSymbol 
*probeSymbol
, **list
; 
 253     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 254     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 255     j 
= thisBucket
->count
; 
 258         thisBucket
->symbolP 
= (OSSymbol 
**) sym
; 
 265         probeSymbol 
= (OSSymbol 
*) thisBucket
->symbolP
; 
 267         if (inLen 
== probeSymbol
->length
 
 268         &&  strcmp(probeSymbol
->string
, cString
) == 0) 
 271         list 
= (OSSymbol 
**) kalloc(2 * sizeof(OSSymbol 
*)); 
 272         ACCUMSIZE(2 * sizeof(OSSymbol 
*)); 
 273         /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 275         list
[1] = probeSymbol
; 
 276         thisBucket
->symbolP 
= list
; 
 279         if (count 
> nBuckets
) 
 280             reconstructSymbols(); 
 285     for (list 
= thisBucket
->symbolP
; j
--; list
++) { 
 287         if (inLen 
== probeSymbol
->length
 
 288         &&  strcmp(probeSymbol
->string
, cString
) == 0) 
 292     j 
= thisBucket
->count
++; 
 294     list 
= (OSSymbol 
**) kalloc(thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 295     ACCUMSIZE(thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 296     /* @@@ gvdl: Zero test and panic if can't set up pool */ 
 298     bcopy(thisBucket
->symbolP
, list 
+ 1, j 
* sizeof(OSSymbol 
*)); 
 299     kfree((vm_offset_t
)thisBucket
->symbolP
, j 
* sizeof(OSSymbol 
*)); 
 300     ACCUMSIZE(-(j 
* sizeof(OSSymbol 
*))); 
 301     thisBucket
->symbolP 
= list
; 
 302     if (count 
> nBuckets
) 
 303         reconstructSymbols(); 
 308 void OSSymbolPool::removeSymbol(const char *cString
) 
 311     unsigned int j
, inLen
, hash
; 
 312     OSSymbol 
*probeSymbol
, **list
; 
 314     hashSymbol(cString
, &hash
, &inLen
); inLen
++; 
 315     thisBucket 
= &buckets
[hash 
% nBuckets
]; 
 316     j 
= thisBucket
->count
; 
 317     list 
= thisBucket
->symbolP
; 
 323         probeSymbol 
= (OSSymbol 
*) list
; 
 325         if (inLen 
== probeSymbol
->length
 
 326         &&  strcmp(probeSymbol
->string
, cString
) == 0) { 
 327             thisBucket
->symbolP 
= 0; 
 336         probeSymbol 
= list
[0]; 
 337         if (inLen 
== probeSymbol
->length
 
 338         &&  strcmp(probeSymbol
->string
, cString
) == 0) { 
 339             thisBucket
->symbolP 
= (OSSymbol 
**) list
[1]; 
 340             kfree((vm_offset_t
)list
, 2 * sizeof(OSSymbol 
*)); 
 341             ACCUMSIZE(-(2 * sizeof(OSSymbol 
*))); 
 347         probeSymbol 
= list
[1]; 
 348         if (inLen 
== probeSymbol
->length
 
 349         &&  strcmp(probeSymbol
->string
, cString
) == 0) { 
 350             thisBucket
->symbolP 
= (OSSymbol 
**) list
[0]; 
 351             kfree((vm_offset_t
)list
, 2 * sizeof(OSSymbol 
*)); 
 352             ACCUMSIZE(-(2 * sizeof(OSSymbol 
*))); 
 360     for (; j
--; list
++) { 
 362         if (inLen 
== probeSymbol
->length
 
 363         &&  strcmp(probeSymbol
->string
, cString
) == 0) { 
 366                 kalloc((thisBucket
->count
-1) * sizeof(OSSymbol 
*)); 
 367             ACCUMSIZE((thisBucket
->count
-1) * sizeof(OSSymbol 
*)); 
 368             if (thisBucket
->count
-1 != j
) 
 369                 bcopy(thisBucket
->symbolP
, list
, 
 370                       (thisBucket
->count
-1-j
) * sizeof(OSSymbol 
*)); 
 372                 bcopy(thisBucket
->symbolP 
+ thisBucket
->count
-j
, 
 373                       list 
+ thisBucket
->count
-1-j
, 
 374                       j 
* sizeof(OSSymbol 
*)); 
 375             kfree((vm_offset_t
)thisBucket
->symbolP
, thisBucket
->count 
* sizeof(OSSymbol 
*)); 
 376             ACCUMSIZE(-(thisBucket
->count 
* sizeof(OSSymbol 
*))); 
 377             thisBucket
->symbolP 
= list
; 
 386  ********************************************************************* 
 387  * From here on we are actually implementing the OSSymbol class 
 388  ********************************************************************* 
 390 OSDefineMetaClassAndStructorsWithInit(OSSymbol
, OSString
, 
 391                                       OSSymbol::initialize()) 
 392 OSMetaClassDefineReservedUnused(OSSymbol
, 0); 
 393 OSMetaClassDefineReservedUnused(OSSymbol
, 1); 
 394 OSMetaClassDefineReservedUnused(OSSymbol
, 2); 
 395 OSMetaClassDefineReservedUnused(OSSymbol
, 3); 
 396 OSMetaClassDefineReservedUnused(OSSymbol
, 4); 
 397 OSMetaClassDefineReservedUnused(OSSymbol
, 5); 
 398 OSMetaClassDefineReservedUnused(OSSymbol
, 6); 
 399 OSMetaClassDefineReservedUnused(OSSymbol
, 7); 
 401 static OSSymbolPool 
*pool
; 
 403 void OSSymbol::initialize() 
 405     pool 
= new OSSymbolPool
; 
 414 bool OSSymbol::initWithCStringNoCopy(const char *) { return false; } 
 415 bool OSSymbol::initWithCString(const char *) { return false; } 
 416 bool OSSymbol::initWithString(const OSString 
*) { return false; } 
 418 const OSSymbol 
*OSSymbol::withString(const OSString 
*aString
) 
 420     // This string may be a OSSymbol already, cheap check. 
 421     if (OSDynamicCast(OSSymbol
, aString
)) { 
 423         return (const OSSymbol 
*) aString
; 
 425     else if (((const OSSymbol 
*) aString
)->flags 
& kOSStringNoCopy
) 
 426         return OSSymbol::withCStringNoCopy(aString
->getCStringNoCopy()); 
 428         return OSSymbol::withCString(aString
->getCStringNoCopy()); 
 431 const OSSymbol 
*OSSymbol::withCString(const char *cString
) 
 435     OSSymbol 
*newSymb 
= pool
->findSymbol(cString
); 
 438     else if ( (newSymb 
= new OSSymbol
) ) { 
 439         if (newSymb
->OSString::initWithCString(cString
)) 
 440             pool
->insertSymbol(newSymb
); 
 451 const OSSymbol 
*OSSymbol::withCStringNoCopy(const char *cString
) 
 455     OSSymbol 
*newSymb 
= pool
->findSymbol(cString
); 
 458     else if ( (newSymb 
= new OSSymbol
) ) { 
 459         if (newSymb
->OSString::initWithCStringNoCopy(cString
)) 
 460             pool
->insertSymbol(newSymb
); 
 471 void OSSymbol::checkForPageUnload(void *startAddr
, void *endAddr
) 
 473     OSSymbol 
*probeSymbol
; 
 474     OSSymbolPoolState state
; 
 477     state 
= pool
->initHashState(); 
 478     while ( (probeSymbol 
= pool
->nextHashState(&state
)) ) { 
 479         if (probeSymbol
->string 
>= startAddr 
&& probeSymbol
->string 
< endAddr
) { 
 480             const char *oldString 
= probeSymbol
->string
; 
 482             probeSymbol
->string 
= (char *) kalloc(probeSymbol
->length
); 
 483             ACCUMSIZE(probeSymbol
->length
); 
 484             bcopy(oldString
, probeSymbol
->string
, probeSymbol
->length
); 
 485             probeSymbol
->flags 
&= ~kOSStringNoCopy
; 
 491 void OSSymbol::free() 
 494     pool
->removeSymbol(string
); 
 500 bool OSSymbol::isEqualTo(const char *aCString
) const 
 502     return super::isEqualTo(aCString
); 
 505 bool OSSymbol::isEqualTo(const OSSymbol 
*aSymbol
) const 
 507     return aSymbol 
== this; 
 510 bool OSSymbol::isEqualTo(const OSMetaClassBase 
*obj
) const 
 515     if ((sym 
= OSDynamicCast(OSSymbol
, obj
))) 
 516         return isEqualTo(sym
); 
 517     else if ((str 
= OSDynamicCast(OSString
, obj
))) 
 518         return super::isEqualTo(str
);