]> git.saurik.com Git - apple/xnu.git/blame - libkern/c++/OSSymbol.cpp
xnu-3789.1.32.tar.gz
[apple/xnu.git] / libkern / c++ / OSSymbol.cpp
CommitLineData
1c79356b 1/*
39037602 2 * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
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.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* IOSymbol.cpp created by gvdl on Fri 1998-11-17 */
29
9bccf70c 30#include <string.h>
1c79356b
A
31#include <sys/cdefs.h>
32
fe8ab488 33#include <kern/locks.h>
1c79356b
A
34
35#include <libkern/c++/OSSymbol.h>
36#include <libkern/c++/OSLib.h>
9bccf70c 37#include <string.h>
1c79356b
A
38
39#define super OSString
40
39236c6e 41typedef struct { unsigned int i, j; } OSSymbolPoolState;
1c79356b 42
2d21ac55
A
43#define INITIAL_POOL_SIZE (exp2ml(1 + log2(kInitBucketCount)))
44
45#define GROW_FACTOR (1)
46#define SHRINK_FACTOR (3)
47
48#define GROW_POOL() do \
49 if (count * GROW_FACTOR > nBuckets) { \
50 reconstructSymbols(true); \
51 } \
52while (0)
53
54#define SHRINK_POOL() do \
55 if (count * SHRINK_FACTOR < nBuckets && \
56 nBuckets > INITIAL_POOL_SIZE) { \
57 reconstructSymbols(false); \
58 } \
59while (0)
60
1c79356b
A
61class OSSymbolPool
62{
63private:
64 static const unsigned int kInitBucketCount = 16;
65
66 typedef struct { unsigned int count; OSSymbol **symbolP; } Bucket;
67
68 Bucket *buckets;
69 unsigned int nBuckets;
70 unsigned int count;
b0d623f7 71 lck_mtx_t *poolGate;
1c79356b
A
72
73 static inline void hashSymbol(const char *s,
74 unsigned int *hashP,
75 unsigned int *lenP)
76 {
77 unsigned int hash = 0;
78 unsigned int len = 0;
79
80 /* Unroll the loop. */
81 for (;;) {
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;
86 }
87 *lenP = len;
88 *hashP = hash;
89 }
90
91 static unsigned long log2(unsigned int x);
92 static unsigned long exp2ml(unsigned int x);
93
2d21ac55
A
94 void reconstructSymbols(void);
95 void reconstructSymbols(bool grow);
1c79356b
A
96
97public:
98 static void *operator new(size_t size);
99 static void operator delete(void *mem, size_t size);
100
39037602 101 OSSymbolPool() { }
1c79356b
A
102 OSSymbolPool(const OSSymbolPool *old);
103 virtual ~OSSymbolPool();
104
105 bool init();
106
39037602
A
107 inline void closeGate() { lck_mtx_lock(poolGate); }
108 inline void openGate() { lck_mtx_unlock(poolGate); }
1c79356b 109
55e303ae 110 OSSymbol *findSymbol(const char *cString) const;
1c79356b 111 OSSymbol *insertSymbol(OSSymbol *sym);
9bccf70c 112 void removeSymbol(OSSymbol *sym);
1c79356b
A
113
114 OSSymbolPoolState initHashState();
115 OSSymbol *nextHashState(OSSymbolPoolState *stateP);
116};
117
118void * OSSymbolPool::operator new(size_t size)
119{
3e170ce0
A
120 void *mem = (void *)kalloc_tag(size, VM_KERN_MEMORY_LIBKERN);
121 OSMETA_ACCUMSIZE(size);
1c79356b
A
122 assert(mem);
123 bzero(mem, size);
124
125 return mem;
126}
127
128void OSSymbolPool::operator delete(void *mem, size_t size)
129{
0c530ab8 130 kfree(mem, size);
3e170ce0 131 OSMETA_ACCUMSIZE(-size);
1c79356b
A
132}
133
b0d623f7
A
134extern lck_grp_t *IOLockGroup;
135
1c79356b
A
136bool OSSymbolPool::init()
137{
138 count = 0;
2d21ac55 139 nBuckets = INITIAL_POOL_SIZE;
3e170ce0
A
140 buckets = (Bucket *) kalloc_tag(nBuckets * sizeof(Bucket), VM_KERN_MEMORY_LIBKERN);
141 OSMETA_ACCUMSIZE(nBuckets * sizeof(Bucket));
1c79356b
A
142 if (!buckets)
143 return false;
144
145 bzero(buckets, nBuckets * sizeof(Bucket));
146
b0d623f7 147 poolGate = lck_mtx_alloc_init(IOLockGroup, LCK_ATTR_NULL);
1c79356b
A
148
149 return poolGate != 0;
150}
151
152OSSymbolPool::OSSymbolPool(const OSSymbolPool *old)
153{
154 count = old->count;
155 nBuckets = old->nBuckets;
156 buckets = old->buckets;
157
158 poolGate = 0; // Do not duplicate the poolGate
159}
160
161OSSymbolPool::~OSSymbolPool()
162{
163 if (buckets) {
39236c6e
A
164 Bucket *thisBucket;
165 for (thisBucket = &buckets[0]; thisBucket < &buckets[nBuckets]; thisBucket++) {
166 if (thisBucket->count > 1) {
167 kfree(thisBucket->symbolP, thisBucket->count * sizeof(OSSymbol *));
3e170ce0 168 OSMETA_ACCUMSIZE(-(thisBucket->count * sizeof(OSSymbol *)));
39236c6e
A
169 }
170 }
0c530ab8 171 kfree(buckets, nBuckets * sizeof(Bucket));
3e170ce0 172 OSMETA_ACCUMSIZE(-(nBuckets * sizeof(Bucket)));
1c79356b
A
173 }
174
175 if (poolGate)
b0d623f7 176 lck_mtx_free(poolGate, IOLockGroup);
1c79356b
A
177}
178
179unsigned long OSSymbolPool::log2(unsigned int x)
180{
181 unsigned long i;
182
183 for (i = 0; x > 1 ; i++)
184 x >>= 1;
185 return i;
186}
187
188unsigned long OSSymbolPool::exp2ml(unsigned int x)
189{
190 return (1 << x) - 1;
191}
192
193OSSymbolPoolState OSSymbolPool::initHashState()
194{
195 OSSymbolPoolState newState = { nBuckets, 0 };
196 return newState;
197}
198
199OSSymbol *OSSymbolPool::nextHashState(OSSymbolPoolState *stateP)
200{
201 Bucket *thisBucket = &buckets[stateP->i];
202
203 while (!stateP->j) {
204 if (!stateP->i)
205 return 0;
206 stateP->i--;
207 thisBucket--;
208 stateP->j = thisBucket->count;
209 }
210
211 stateP->j--;
212 if (thisBucket->count == 1)
213 return (OSSymbol *) thisBucket->symbolP;
214 else
215 return thisBucket->symbolP[stateP->j];
216}
217
2d21ac55 218void OSSymbolPool::reconstructSymbols(void)
1c79356b 219{
2d21ac55
A
220 this->reconstructSymbols(true);
221}
222
223void OSSymbolPool::reconstructSymbols(bool grow)
224{
225 unsigned int new_nBuckets = nBuckets;
1c79356b
A
226 OSSymbol *insert;
227 OSSymbolPoolState state;
228
2d21ac55
A
229 if (grow) {
230 new_nBuckets += new_nBuckets + 1;
231 } else {
232 /* Don't shrink the pool below the default initial size.
233 */
234 if (nBuckets <= INITIAL_POOL_SIZE) {
235 return;
236 }
237 new_nBuckets = (new_nBuckets - 1) / 2;
238 }
239
240 /* Create old pool to iterate after doing above check, cause it
241 * gets finalized at return.
242 */
243 OSSymbolPool old(this);
244
1c79356b 245 count = 0;
2d21ac55 246 nBuckets = new_nBuckets;
3e170ce0
A
247 buckets = (Bucket *) kalloc_tag(nBuckets * sizeof(Bucket), VM_KERN_MEMORY_LIBKERN);
248 OSMETA_ACCUMSIZE(nBuckets * sizeof(Bucket));
1c79356b
A
249 /* @@@ gvdl: Zero test and panic if can't set up pool */
250 bzero(buckets, nBuckets * sizeof(Bucket));
251
252 state = old.initHashState();
253 while ( (insert = old.nextHashState(&state)) )
254 insertSymbol(insert);
255}
256
55e303ae 257OSSymbol *OSSymbolPool::findSymbol(const char *cString) const
1c79356b
A
258{
259 Bucket *thisBucket;
260 unsigned int j, inLen, hash;
261 OSSymbol *probeSymbol, **list;
262
263 hashSymbol(cString, &hash, &inLen); inLen++;
264 thisBucket = &buckets[hash % nBuckets];
265 j = thisBucket->count;
266
267 if (!j)
268 return 0;
269
270 if (j == 1) {
271 probeSymbol = (OSSymbol *) thisBucket->symbolP;
272
273 if (inLen == probeSymbol->length
b0d623f7 274 && (strncmp(probeSymbol->string, cString, probeSymbol->length) == 0))
55e303ae 275 return probeSymbol;
9bccf70c 276 return 0;
1c79356b
A
277 }
278
279 for (list = thisBucket->symbolP; j--; list++) {
280 probeSymbol = *list;
281 if (inLen == probeSymbol->length
b0d623f7 282 && (strncmp(probeSymbol->string, cString, probeSymbol->length) == 0))
55e303ae 283 return probeSymbol;
1c79356b
A
284 }
285
286 return 0;
287}
288
289OSSymbol *OSSymbolPool::insertSymbol(OSSymbol *sym)
290{
291 const char *cString = sym->string;
292 Bucket *thisBucket;
293 unsigned int j, inLen, hash;
294 OSSymbol *probeSymbol, **list;
295
296 hashSymbol(cString, &hash, &inLen); inLen++;
297 thisBucket = &buckets[hash % nBuckets];
298 j = thisBucket->count;
299
300 if (!j) {
301 thisBucket->symbolP = (OSSymbol **) sym;
302 thisBucket->count++;
303 count++;
55e303ae 304 return sym;
1c79356b
A
305 }
306
307 if (j == 1) {
308 probeSymbol = (OSSymbol *) thisBucket->symbolP;
309
310 if (inLen == probeSymbol->length
b0d623f7 311 && strncmp(probeSymbol->string, cString, probeSymbol->length) == 0)
1c79356b
A
312 return probeSymbol;
313
3e170ce0
A
314 list = (OSSymbol **) kalloc_tag(2 * sizeof(OSSymbol *), VM_KERN_MEMORY_LIBKERN);
315 OSMETA_ACCUMSIZE(2 * sizeof(OSSymbol *));
1c79356b
A
316 /* @@@ gvdl: Zero test and panic if can't set up pool */
317 list[0] = sym;
318 list[1] = probeSymbol;
319 thisBucket->symbolP = list;
320 thisBucket->count++;
321 count++;
2d21ac55 322 GROW_POOL();
1c79356b 323
55e303ae 324 return sym;
1c79356b
A
325 }
326
327 for (list = thisBucket->symbolP; j--; list++) {
328 probeSymbol = *list;
329 if (inLen == probeSymbol->length
b0d623f7 330 && strncmp(probeSymbol->string, cString, probeSymbol->length) == 0)
1c79356b
A
331 return probeSymbol;
332 }
333
334 j = thisBucket->count++;
335 count++;
3e170ce0
A
336 list = (OSSymbol **) kalloc_tag(thisBucket->count * sizeof(OSSymbol *), VM_KERN_MEMORY_LIBKERN);
337 OSMETA_ACCUMSIZE(thisBucket->count * sizeof(OSSymbol *));
1c79356b
A
338 /* @@@ gvdl: Zero test and panic if can't set up pool */
339 list[0] = sym;
340 bcopy(thisBucket->symbolP, list + 1, j * sizeof(OSSymbol *));
0c530ab8 341 kfree(thisBucket->symbolP, j * sizeof(OSSymbol *));
3e170ce0 342 OSMETA_ACCUMSIZE(-(j * sizeof(OSSymbol *)));
1c79356b 343 thisBucket->symbolP = list;
2d21ac55 344 GROW_POOL();
1c79356b 345
55e303ae 346 return sym;
1c79356b
A
347}
348
9bccf70c 349void OSSymbolPool::removeSymbol(OSSymbol *sym)
1c79356b
A
350{
351 Bucket *thisBucket;
352 unsigned int j, inLen, hash;
353 OSSymbol *probeSymbol, **list;
354
9bccf70c 355 hashSymbol(sym->string, &hash, &inLen); inLen++;
1c79356b
A
356 thisBucket = &buckets[hash % nBuckets];
357 j = thisBucket->count;
358 list = thisBucket->symbolP;
359
6d2010ae
A
360 if (!j) {
361 // couldn't find the symbol; probably means string hash changed
39236c6e 362 panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count);
1c79356b 363 return;
6d2010ae 364 }
1c79356b
A
365
366 if (j == 1) {
367 probeSymbol = (OSSymbol *) list;
368
9bccf70c 369 if (probeSymbol == sym) {
1c79356b
A
370 thisBucket->symbolP = 0;
371 count--;
372 thisBucket->count--;
2d21ac55 373 SHRINK_POOL();
1c79356b
A
374 return;
375 }
6d2010ae 376 // couldn't find the symbol; probably means string hash changed
39236c6e 377 panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count);
1c79356b
A
378 return;
379 }
380
381 if (j == 2) {
382 probeSymbol = list[0];
9bccf70c 383 if (probeSymbol == sym) {
1c79356b 384 thisBucket->symbolP = (OSSymbol **) list[1];
0c530ab8 385 kfree(list, 2 * sizeof(OSSymbol *));
3e170ce0 386 OSMETA_ACCUMSIZE(-(2 * sizeof(OSSymbol *)));
1c79356b
A
387 count--;
388 thisBucket->count--;
2d21ac55 389 SHRINK_POOL();
1c79356b
A
390 return;
391 }
392
393 probeSymbol = list[1];
9bccf70c 394 if (probeSymbol == sym) {
1c79356b 395 thisBucket->symbolP = (OSSymbol **) list[0];
0c530ab8 396 kfree(list, 2 * sizeof(OSSymbol *));
3e170ce0 397 OSMETA_ACCUMSIZE(-(2 * sizeof(OSSymbol *)));
1c79356b
A
398 count--;
399 thisBucket->count--;
2d21ac55 400 SHRINK_POOL();
1c79356b
A
401 return;
402 }
6d2010ae 403 // couldn't find the symbol; probably means string hash changed
39236c6e 404 panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count);
1c79356b
A
405 return;
406 }
407
408 for (; j--; list++) {
409 probeSymbol = *list;
9bccf70c 410 if (probeSymbol == sym) {
1c79356b
A
411
412 list = (OSSymbol **)
3e170ce0
A
413 kalloc_tag((thisBucket->count-1) * sizeof(OSSymbol *), VM_KERN_MEMORY_LIBKERN);
414 OSMETA_ACCUMSIZE((thisBucket->count-1) * sizeof(OSSymbol *));
1c79356b
A
415 if (thisBucket->count-1 != j)
416 bcopy(thisBucket->symbolP, list,
417 (thisBucket->count-1-j) * sizeof(OSSymbol *));
418 if (j)
419 bcopy(thisBucket->symbolP + thisBucket->count-j,
420 list + thisBucket->count-1-j,
421 j * sizeof(OSSymbol *));
0c530ab8 422 kfree(thisBucket->symbolP, thisBucket->count * sizeof(OSSymbol *));
3e170ce0 423 OSMETA_ACCUMSIZE(-(thisBucket->count * sizeof(OSSymbol *)));
1c79356b
A
424 thisBucket->symbolP = list;
425 count--;
426 thisBucket->count--;
427 return;
428 }
429 }
6d2010ae 430 // couldn't find the symbol; probably means string hash changed
39236c6e 431 panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count);
1c79356b
A
432}
433
434/*
435 *********************************************************************
436 * From here on we are actually implementing the OSSymbol class
437 *********************************************************************
438 */
439OSDefineMetaClassAndStructorsWithInit(OSSymbol, OSString,
440 OSSymbol::initialize())
441OSMetaClassDefineReservedUnused(OSSymbol, 0);
442OSMetaClassDefineReservedUnused(OSSymbol, 1);
443OSMetaClassDefineReservedUnused(OSSymbol, 2);
444OSMetaClassDefineReservedUnused(OSSymbol, 3);
445OSMetaClassDefineReservedUnused(OSSymbol, 4);
446OSMetaClassDefineReservedUnused(OSSymbol, 5);
447OSMetaClassDefineReservedUnused(OSSymbol, 6);
448OSMetaClassDefineReservedUnused(OSSymbol, 7);
449
450static OSSymbolPool *pool;
451
452void OSSymbol::initialize()
453{
454 pool = new OSSymbolPool;
455 assert(pool);
456
fe8ab488 457 if (pool && !pool->init()) {
1c79356b
A
458 delete pool;
459 assert(false);
460 };
461}
462
463bool OSSymbol::initWithCStringNoCopy(const char *) { return false; }
464bool OSSymbol::initWithCString(const char *) { return false; }
465bool OSSymbol::initWithString(const OSString *) { return false; }
466
467const OSSymbol *OSSymbol::withString(const OSString *aString)
468{
469 // This string may be a OSSymbol already, cheap check.
470 if (OSDynamicCast(OSSymbol, aString)) {
471 aString->retain();
472 return (const OSSymbol *) aString;
473 }
474 else if (((const OSSymbol *) aString)->flags & kOSStringNoCopy)
475 return OSSymbol::withCStringNoCopy(aString->getCStringNoCopy());
476 else
477 return OSSymbol::withCString(aString->getCStringNoCopy());
478}
479
480const OSSymbol *OSSymbol::withCString(const char *cString)
481{
482 pool->closeGate();
483
55e303ae
A
484 OSSymbol *oldSymb = pool->findSymbol(cString);
485 if (!oldSymb) {
486 OSSymbol *newSymb = new OSSymbol;
487 if (!newSymb) {
488 pool->openGate();
489 return newSymb;
490 }
491
492 if (newSymb->OSString::initWithCString(cString))
493 oldSymb = pool->insertSymbol(newSymb);
494
495 if (newSymb == oldSymb) {
496 pool->openGate();
497 return newSymb; // return the newly created & inserted symbol.
498 }
499 else
500 // Somebody else inserted the new symbol so free our copy
9bccf70c 501 newSymb->OSString::free();
1c79356b 502 }
55e303ae
A
503
504 oldSymb->retain(); // Retain the old symbol before releasing the lock.
1c79356b 505
55e303ae
A
506 pool->openGate();
507 return oldSymb;
1c79356b
A
508}
509
510const OSSymbol *OSSymbol::withCStringNoCopy(const char *cString)
511{
512 pool->closeGate();
513
55e303ae
A
514 OSSymbol *oldSymb = pool->findSymbol(cString);
515 if (!oldSymb) {
516 OSSymbol *newSymb = new OSSymbol;
517 if (!newSymb) {
518 pool->openGate();
519 return newSymb;
520 }
521
522 if (newSymb->OSString::initWithCStringNoCopy(cString))
523 oldSymb = pool->insertSymbol(newSymb);
524
525 if (newSymb == oldSymb) {
526 pool->openGate();
527 return newSymb; // return the newly created & inserted symbol.
528 }
529 else
530 // Somebody else inserted the new symbol so free our copy
9bccf70c 531 newSymb->OSString::free();
1c79356b 532 }
55e303ae
A
533
534 oldSymb->retain(); // Retain the old symbol before releasing the lock.
1c79356b 535
55e303ae
A
536 pool->openGate();
537 return oldSymb;
1c79356b
A
538}
539
540void OSSymbol::checkForPageUnload(void *startAddr, void *endAddr)
541{
542 OSSymbol *probeSymbol;
543 OSSymbolPoolState state;
544
545 pool->closeGate();
546 state = pool->initHashState();
547 while ( (probeSymbol = pool->nextHashState(&state)) ) {
548 if (probeSymbol->string >= startAddr && probeSymbol->string < endAddr) {
3e170ce0 549 probeSymbol->OSString::initWithCString(probeSymbol->string);
1c79356b
A
550 }
551 }
552 pool->openGate();
553}
554
55e303ae
A
555void OSSymbol::taggedRelease(const void *tag) const
556{
557 super::taggedRelease(tag);
558}
559
560void OSSymbol::taggedRelease(const void *tag, const int when) const
1c79356b
A
561{
562 pool->closeGate();
55e303ae 563 super::taggedRelease(tag, when);
1c79356b 564 pool->openGate();
55e303ae
A
565}
566
567void OSSymbol::free()
568{
569 pool->removeSymbol(this);
1c79356b
A
570 super::free();
571}
572
573bool OSSymbol::isEqualTo(const char *aCString) const
574{
575 return super::isEqualTo(aCString);
576}
577
578bool OSSymbol::isEqualTo(const OSSymbol *aSymbol) const
579{
580 return aSymbol == this;
581}
582
583bool OSSymbol::isEqualTo(const OSMetaClassBase *obj) const
584{
585 OSSymbol * sym;
586 OSString * str;
587
588 if ((sym = OSDynamicCast(OSSymbol, obj)))
589 return isEqualTo(sym);
590 else if ((str = OSDynamicCast(OSString, obj)))
591 return super::isEqualTo(str);
592 else
593 return false;
594}
316670eb
A
595
596unsigned int
597OSSymbol::bsearch(
598 const void * key,
599 const void * array,
600 unsigned int arrayCount,
601 size_t memberSize)
602{
603 const void **p;
604 unsigned int baseIdx = 0;
605 unsigned int lim;
606
607 for (lim = arrayCount; lim; lim >>= 1)
608 {
609 p = (typeof(p)) (((uintptr_t) array) + (baseIdx + (lim >> 1)) * memberSize);
610 if (key == *p)
611 {
612 return (baseIdx + (lim >> 1));
613 }
614 if (key > *p)
615 {
616 // move right
617 baseIdx += (lim >> 1) + 1;
618 lim--;
619 }
620 // else move left
621 }
622 // not found, insertion point here
623 return (baseIdx + (lim >> 1));
624}