]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
39037602 | 2 | * Copyright (c) 2000-2016 Apple Inc. All rights reserved. |
1c79356b | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
0a7de745 | 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. | |
0a7de745 | 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. | |
0a7de745 | 17 | * |
2d21ac55 A |
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. | |
0a7de745 | 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 | 41 | typedef 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) { \ | |
0a7de745 | 50 | reconstructSymbols(true); \ |
2d21ac55 A |
51 | } \ |
52 | while (0) | |
53 | ||
54 | #define SHRINK_POOL() do \ | |
55 | if (count * SHRINK_FACTOR < nBuckets && \ | |
0a7de745 A |
56 | nBuckets > INITIAL_POOL_SIZE) { \ |
57 | reconstructSymbols(false); \ | |
2d21ac55 A |
58 | } \ |
59 | while (0) | |
60 | ||
1c79356b A |
61 | class OSSymbolPool |
62 | { | |
63 | private: | |
0a7de745 A |
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; | |
71 | lck_rw_t *poolGate; | |
72 | ||
73 | static inline void | |
74 | hashSymbol(const char *s, | |
75 | unsigned int *hashP, | |
76 | unsigned int *lenP) | |
77 | { | |
78 | unsigned int hash = 0; | |
79 | unsigned int len = 0; | |
80 | ||
81 | /* Unroll the loop. */ | |
82 | for (;;) { | |
83 | if (!*s) { | |
84 | break; | |
85 | } | |
86 | len++; hash ^= *s++; | |
87 | if (!*s) { | |
88 | break; | |
89 | } | |
90 | len++; hash ^= *s++ << 8; | |
91 | if (!*s) { | |
92 | break; | |
93 | } | |
94 | len++; hash ^= *s++ << 16; | |
95 | if (!*s) { | |
96 | break; | |
97 | } | |
98 | len++; hash ^= *s++ << 24; | |
99 | } | |
100 | *lenP = len; | |
101 | *hashP = hash; | |
102 | } | |
103 | ||
104 | static unsigned long log2(unsigned int x); | |
105 | static unsigned long exp2ml(unsigned int x); | |
106 | ||
107 | void reconstructSymbols(void); | |
108 | void reconstructSymbols(bool grow); | |
1c79356b A |
109 | |
110 | public: | |
0a7de745 A |
111 | static void *operator new(size_t size); |
112 | static void operator delete(void *mem, size_t size); | |
1c79356b | 113 | |
0a7de745 A |
114 | OSSymbolPool() |
115 | { | |
116 | } | |
117 | OSSymbolPool(const OSSymbolPool *old); | |
118 | virtual | |
119 | ~OSSymbolPool(); | |
1c79356b | 120 | |
0a7de745 | 121 | bool init(); |
1c79356b | 122 | |
0a7de745 A |
123 | inline void |
124 | closeReadGate() | |
125 | { | |
126 | lck_rw_lock(poolGate, LCK_RW_TYPE_SHARED); | |
127 | } | |
128 | ||
129 | inline void | |
130 | openReadGate() | |
131 | { | |
132 | lck_rw_unlock(poolGate, LCK_RW_TYPE_SHARED); | |
133 | } | |
134 | ||
135 | ||
136 | inline void | |
137 | closeWriteGate() | |
138 | { | |
139 | lck_rw_lock(poolGate, LCK_RW_TYPE_EXCLUSIVE); | |
140 | } | |
141 | ||
142 | inline void | |
143 | openWriteGate() | |
144 | { | |
145 | lck_rw_unlock(poolGate, LCK_RW_TYPE_EXCLUSIVE); | |
146 | } | |
1c79356b | 147 | |
0a7de745 A |
148 | LIBKERN_RETURNS_RETAINED OSSymbol *findSymbol(const char *cString) const; |
149 | LIBKERN_RETURNS_RETAINED OSSymbol *insertSymbol(OSSymbol *sym); | |
150 | void removeSymbol(OSSymbol *sym); | |
1c79356b | 151 | |
0a7de745 A |
152 | OSSymbolPoolState initHashState(); |
153 | LIBKERN_RETURNS_NOT_RETAINED OSSymbol *nextHashState(OSSymbolPoolState *stateP); | |
1c79356b A |
154 | }; |
155 | ||
0a7de745 A |
156 | void * |
157 | OSSymbolPool::operator new(size_t size) | |
1c79356b | 158 | { |
0a7de745 A |
159 | void *mem = (void *)kalloc_tag(size, VM_KERN_MEMORY_LIBKERN); |
160 | OSMETA_ACCUMSIZE(size); | |
161 | assert(mem); | |
162 | bzero(mem, size); | |
1c79356b | 163 | |
0a7de745 | 164 | return mem; |
1c79356b A |
165 | } |
166 | ||
0a7de745 A |
167 | void |
168 | OSSymbolPool::operator delete(void *mem, size_t size) | |
1c79356b | 169 | { |
0a7de745 A |
170 | kfree(mem, size); |
171 | OSMETA_ACCUMSIZE(-size); | |
1c79356b A |
172 | } |
173 | ||
b0d623f7 A |
174 | extern lck_grp_t *IOLockGroup; |
175 | ||
0a7de745 A |
176 | bool |
177 | OSSymbolPool::init() | |
1c79356b | 178 | { |
0a7de745 A |
179 | count = 0; |
180 | nBuckets = INITIAL_POOL_SIZE; | |
181 | buckets = (Bucket *) kalloc_tag(nBuckets * sizeof(Bucket), VM_KERN_MEMORY_LIBKERN); | |
182 | OSMETA_ACCUMSIZE(nBuckets * sizeof(Bucket)); | |
183 | if (!buckets) { | |
184 | return false; | |
185 | } | |
1c79356b | 186 | |
0a7de745 | 187 | bzero(buckets, nBuckets * sizeof(Bucket)); |
1c79356b | 188 | |
0a7de745 | 189 | poolGate = lck_rw_alloc_init(IOLockGroup, LCK_ATTR_NULL); |
1c79356b | 190 | |
cb323159 | 191 | return poolGate != NULL; |
1c79356b A |
192 | } |
193 | ||
194 | OSSymbolPool::OSSymbolPool(const OSSymbolPool *old) | |
195 | { | |
0a7de745 A |
196 | count = old->count; |
197 | nBuckets = old->nBuckets; | |
198 | buckets = old->buckets; | |
1c79356b | 199 | |
cb323159 | 200 | poolGate = NULL; // Do not duplicate the poolGate |
1c79356b A |
201 | } |
202 | ||
203 | OSSymbolPool::~OSSymbolPool() | |
204 | { | |
0a7de745 A |
205 | if (buckets) { |
206 | Bucket *thisBucket; | |
207 | for (thisBucket = &buckets[0]; thisBucket < &buckets[nBuckets]; thisBucket++) { | |
208 | if (thisBucket->count > 1) { | |
209 | kfree(thisBucket->symbolP, thisBucket->count * sizeof(OSSymbol *)); | |
210 | OSMETA_ACCUMSIZE(-(thisBucket->count * sizeof(OSSymbol *))); | |
211 | } | |
212 | } | |
213 | kfree(buckets, nBuckets * sizeof(Bucket)); | |
214 | OSMETA_ACCUMSIZE(-(nBuckets * sizeof(Bucket))); | |
215 | } | |
216 | ||
217 | if (poolGate) { | |
218 | lck_rw_free(poolGate, IOLockGroup); | |
219 | } | |
1c79356b A |
220 | } |
221 | ||
0a7de745 A |
222 | unsigned long |
223 | OSSymbolPool::log2(unsigned int x) | |
1c79356b | 224 | { |
0a7de745 | 225 | unsigned long i; |
1c79356b | 226 | |
0a7de745 A |
227 | for (i = 0; x > 1; i++) { |
228 | x >>= 1; | |
229 | } | |
230 | return i; | |
1c79356b A |
231 | } |
232 | ||
0a7de745 A |
233 | unsigned long |
234 | OSSymbolPool::exp2ml(unsigned int x) | |
1c79356b | 235 | { |
0a7de745 | 236 | return (1 << x) - 1; |
1c79356b A |
237 | } |
238 | ||
0a7de745 A |
239 | OSSymbolPoolState |
240 | OSSymbolPool::initHashState() | |
1c79356b | 241 | { |
0a7de745 A |
242 | OSSymbolPoolState newState = { nBuckets, 0 }; |
243 | return newState; | |
1c79356b A |
244 | } |
245 | ||
0a7de745 A |
246 | OSSymbol * |
247 | OSSymbolPool::nextHashState(OSSymbolPoolState *stateP) | |
1c79356b | 248 | { |
0a7de745 A |
249 | Bucket *thisBucket = &buckets[stateP->i]; |
250 | ||
251 | while (!stateP->j) { | |
252 | if (!stateP->i) { | |
cb323159 | 253 | return NULL; |
0a7de745 A |
254 | } |
255 | stateP->i--; | |
256 | thisBucket--; | |
257 | stateP->j = thisBucket->count; | |
258 | } | |
1c79356b | 259 | |
0a7de745 A |
260 | stateP->j--; |
261 | if (thisBucket->count == 1) { | |
262 | return (OSSymbol *) thisBucket->symbolP; | |
263 | } else { | |
264 | return thisBucket->symbolP[stateP->j]; | |
265 | } | |
1c79356b A |
266 | } |
267 | ||
0a7de745 A |
268 | void |
269 | OSSymbolPool::reconstructSymbols(void) | |
1c79356b | 270 | { |
0a7de745 | 271 | this->reconstructSymbols(true); |
2d21ac55 A |
272 | } |
273 | ||
0a7de745 A |
274 | void |
275 | OSSymbolPool::reconstructSymbols(bool grow) | |
276 | { | |
277 | unsigned int new_nBuckets = nBuckets; | |
278 | OSSymbol *insert; | |
279 | OSSymbolPoolState state; | |
280 | ||
281 | if (grow) { | |
282 | new_nBuckets += new_nBuckets + 1; | |
283 | } else { | |
284 | /* Don't shrink the pool below the default initial size. | |
285 | */ | |
286 | if (nBuckets <= INITIAL_POOL_SIZE) { | |
287 | return; | |
288 | } | |
289 | new_nBuckets = (new_nBuckets - 1) / 2; | |
290 | } | |
291 | ||
292 | /* Create old pool to iterate after doing above check, cause it | |
293 | * gets finalized at return. | |
294 | */ | |
295 | OSSymbolPool old(this); | |
296 | ||
297 | count = 0; | |
298 | nBuckets = new_nBuckets; | |
299 | buckets = (Bucket *) kalloc_tag(nBuckets * sizeof(Bucket), VM_KERN_MEMORY_LIBKERN); | |
300 | OSMETA_ACCUMSIZE(nBuckets * sizeof(Bucket)); | |
301 | /* @@@ gvdl: Zero test and panic if can't set up pool */ | |
302 | bzero(buckets, nBuckets * sizeof(Bucket)); | |
303 | ||
304 | state = old.initHashState(); | |
305 | while ((insert = old.nextHashState(&state))) { | |
306 | insertSymbol(insert); | |
307 | } | |
1c79356b A |
308 | } |
309 | ||
0a7de745 A |
310 | OSSymbol * |
311 | OSSymbolPool::findSymbol(const char *cString) const | |
1c79356b | 312 | { |
0a7de745 A |
313 | Bucket *thisBucket; |
314 | unsigned int j, inLen, hash; | |
315 | OSSymbol *probeSymbol, **list; | |
1c79356b | 316 | |
0a7de745 A |
317 | hashSymbol(cString, &hash, &inLen); inLen++; |
318 | thisBucket = &buckets[hash % nBuckets]; | |
319 | j = thisBucket->count; | |
1c79356b | 320 | |
0a7de745 | 321 | if (!j) { |
cb323159 | 322 | return NULL; |
0a7de745 | 323 | } |
1c79356b | 324 | |
0a7de745 A |
325 | if (j == 1) { |
326 | probeSymbol = (OSSymbol *) thisBucket->symbolP; | |
1c79356b | 327 | |
0a7de745 A |
328 | if (inLen == probeSymbol->length |
329 | && strncmp(probeSymbol->string, cString, probeSymbol->length) == 0 | |
330 | && probeSymbol->taggedTryRetain(nullptr)) { | |
331 | return probeSymbol; | |
332 | } | |
cb323159 | 333 | return NULL; |
0a7de745 | 334 | } |
1c79356b | 335 | |
0a7de745 A |
336 | for (list = thisBucket->symbolP; j--; list++) { |
337 | probeSymbol = *list; | |
338 | if (inLen == probeSymbol->length | |
339 | && strncmp(probeSymbol->string, cString, probeSymbol->length) == 0 | |
340 | && probeSymbol->taggedTryRetain(nullptr)) { | |
341 | return probeSymbol; | |
342 | } | |
343 | } | |
1c79356b | 344 | |
cb323159 | 345 | return NULL; |
1c79356b A |
346 | } |
347 | ||
0a7de745 A |
348 | OSSymbol * |
349 | OSSymbolPool::insertSymbol(OSSymbol *sym) | |
350 | { | |
351 | const char *cString = sym->string; | |
352 | Bucket *thisBucket; | |
353 | unsigned int j, inLen, hash; | |
354 | OSSymbol *probeSymbol, **list; | |
355 | ||
356 | hashSymbol(cString, &hash, &inLen); inLen++; | |
357 | thisBucket = &buckets[hash % nBuckets]; | |
358 | j = thisBucket->count; | |
359 | ||
360 | if (!j) { | |
361 | thisBucket->symbolP = (OSSymbol **) sym; | |
362 | thisBucket->count++; | |
363 | count++; | |
364 | return nullptr; | |
365 | } | |
366 | ||
367 | if (j == 1) { | |
368 | probeSymbol = (OSSymbol *) thisBucket->symbolP; | |
369 | ||
370 | if (inLen == probeSymbol->length | |
371 | && strncmp(probeSymbol->string, cString, probeSymbol->length) == 0 | |
372 | && probeSymbol->taggedTryRetain(nullptr)) { | |
373 | return probeSymbol; | |
374 | } | |
375 | ||
376 | list = (OSSymbol **) kalloc_tag(2 * sizeof(OSSymbol *), VM_KERN_MEMORY_LIBKERN); | |
377 | OSMETA_ACCUMSIZE(2 * sizeof(OSSymbol *)); | |
378 | /* @@@ gvdl: Zero test and panic if can't set up pool */ | |
379 | list[0] = sym; | |
380 | list[1] = probeSymbol; | |
381 | thisBucket->symbolP = list; | |
382 | thisBucket->count++; | |
383 | count++; | |
384 | GROW_POOL(); | |
385 | ||
386 | return nullptr; | |
387 | } | |
388 | ||
389 | for (list = thisBucket->symbolP; j--; list++) { | |
390 | probeSymbol = *list; | |
391 | if (inLen == probeSymbol->length | |
392 | && strncmp(probeSymbol->string, cString, probeSymbol->length) == 0 | |
393 | && probeSymbol->taggedTryRetain(nullptr)) { | |
394 | return probeSymbol; | |
395 | } | |
396 | } | |
397 | ||
398 | j = thisBucket->count++; | |
399 | count++; | |
400 | list = (OSSymbol **) kalloc_tag(thisBucket->count * sizeof(OSSymbol *), VM_KERN_MEMORY_LIBKERN); | |
401 | OSMETA_ACCUMSIZE(thisBucket->count * sizeof(OSSymbol *)); | |
402 | /* @@@ gvdl: Zero test and panic if can't set up pool */ | |
403 | list[0] = sym; | |
404 | bcopy(thisBucket->symbolP, list + 1, j * sizeof(OSSymbol *)); | |
405 | kfree(thisBucket->symbolP, j * sizeof(OSSymbol *)); | |
406 | OSMETA_ACCUMSIZE(-(j * sizeof(OSSymbol *))); | |
407 | thisBucket->symbolP = list; | |
408 | GROW_POOL(); | |
409 | ||
410 | return nullptr; | |
1c79356b A |
411 | } |
412 | ||
0a7de745 A |
413 | void |
414 | OSSymbolPool::removeSymbol(OSSymbol *sym) | |
1c79356b | 415 | { |
0a7de745 A |
416 | Bucket *thisBucket; |
417 | unsigned int j, inLen, hash; | |
418 | OSSymbol *probeSymbol, **list; | |
419 | ||
420 | hashSymbol(sym->string, &hash, &inLen); inLen++; | |
421 | thisBucket = &buckets[hash % nBuckets]; | |
422 | j = thisBucket->count; | |
423 | list = thisBucket->symbolP; | |
424 | ||
425 | if (!j) { | |
426 | // couldn't find the symbol; probably means string hash changed | |
427 | panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count); | |
428 | return; | |
429 | } | |
1c79356b | 430 | |
0a7de745 A |
431 | if (j == 1) { |
432 | probeSymbol = (OSSymbol *) list; | |
433 | ||
434 | if (probeSymbol == sym) { | |
cb323159 | 435 | thisBucket->symbolP = NULL; |
0a7de745 A |
436 | count--; |
437 | thisBucket->count--; | |
438 | SHRINK_POOL(); | |
439 | return; | |
440 | } | |
441 | // couldn't find the symbol; probably means string hash changed | |
442 | panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count); | |
443 | return; | |
444 | } | |
1c79356b | 445 | |
0a7de745 A |
446 | if (j == 2) { |
447 | probeSymbol = list[0]; | |
448 | if (probeSymbol == sym) { | |
449 | thisBucket->symbolP = (OSSymbol **) list[1]; | |
450 | kfree(list, 2 * sizeof(OSSymbol *)); | |
451 | OSMETA_ACCUMSIZE(-(2 * sizeof(OSSymbol *))); | |
452 | count--; | |
453 | thisBucket->count--; | |
454 | SHRINK_POOL(); | |
455 | return; | |
456 | } | |
457 | ||
458 | probeSymbol = list[1]; | |
459 | if (probeSymbol == sym) { | |
460 | thisBucket->symbolP = (OSSymbol **) list[0]; | |
461 | kfree(list, 2 * sizeof(OSSymbol *)); | |
462 | OSMETA_ACCUMSIZE(-(2 * sizeof(OSSymbol *))); | |
463 | count--; | |
464 | thisBucket->count--; | |
465 | SHRINK_POOL(); | |
466 | return; | |
467 | } | |
468 | // couldn't find the symbol; probably means string hash changed | |
469 | panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count); | |
470 | return; | |
471 | } | |
472 | ||
473 | for (; j--; list++) { | |
474 | probeSymbol = *list; | |
475 | if (probeSymbol == sym) { | |
476 | list = (OSSymbol **) | |
477 | kalloc_tag((thisBucket->count - 1) * sizeof(OSSymbol *), VM_KERN_MEMORY_LIBKERN); | |
478 | OSMETA_ACCUMSIZE((thisBucket->count - 1) * sizeof(OSSymbol *)); | |
479 | if (thisBucket->count - 1 != j) { | |
480 | bcopy(thisBucket->symbolP, list, | |
481 | (thisBucket->count - 1 - j) * sizeof(OSSymbol *)); | |
482 | } | |
483 | if (j) { | |
484 | bcopy(thisBucket->symbolP + thisBucket->count - j, | |
485 | list + thisBucket->count - 1 - j, | |
486 | j * sizeof(OSSymbol *)); | |
487 | } | |
488 | kfree(thisBucket->symbolP, thisBucket->count * sizeof(OSSymbol *)); | |
489 | OSMETA_ACCUMSIZE(-(thisBucket->count * sizeof(OSSymbol *))); | |
490 | thisBucket->symbolP = list; | |
491 | count--; | |
492 | thisBucket->count--; | |
493 | return; | |
494 | } | |
495 | } | |
6d2010ae | 496 | // couldn't find the symbol; probably means string hash changed |
0a7de745 | 497 | panic("removeSymbol %s count %d ", sym->string ? sym->string : "no string", count); |
1c79356b A |
498 | } |
499 | ||
500 | /* | |
501 | ********************************************************************* | |
502 | * From here on we are actually implementing the OSSymbol class | |
503 | ********************************************************************* | |
504 | */ | |
505 | OSDefineMetaClassAndStructorsWithInit(OSSymbol, OSString, | |
0a7de745 | 506 | OSSymbol::initialize()) |
1c79356b A |
507 | OSMetaClassDefineReservedUnused(OSSymbol, 0); |
508 | OSMetaClassDefineReservedUnused(OSSymbol, 1); | |
509 | OSMetaClassDefineReservedUnused(OSSymbol, 2); | |
510 | OSMetaClassDefineReservedUnused(OSSymbol, 3); | |
511 | OSMetaClassDefineReservedUnused(OSSymbol, 4); | |
512 | OSMetaClassDefineReservedUnused(OSSymbol, 5); | |
513 | OSMetaClassDefineReservedUnused(OSSymbol, 6); | |
514 | OSMetaClassDefineReservedUnused(OSSymbol, 7); | |
515 | ||
516 | static OSSymbolPool *pool; | |
517 | ||
0a7de745 A |
518 | void |
519 | OSSymbol::initialize() | |
1c79356b | 520 | { |
0a7de745 A |
521 | pool = new OSSymbolPool; |
522 | assert(pool); | |
1c79356b | 523 | |
0a7de745 A |
524 | if (pool && !pool->init()) { |
525 | delete pool; | |
526 | assert(false); | |
527 | } | |
528 | ; | |
1c79356b A |
529 | } |
530 | ||
0a7de745 A |
531 | bool |
532 | OSSymbol::initWithCStringNoCopy(const char *) | |
533 | { | |
534 | return false; | |
535 | } | |
536 | bool | |
537 | OSSymbol::initWithCString(const char *) | |
538 | { | |
539 | return false; | |
540 | } | |
541 | bool | |
542 | OSSymbol::initWithString(const OSString *) | |
543 | { | |
544 | return false; | |
545 | } | |
546 | ||
547 | const OSSymbol * | |
548 | OSSymbol::withString(const OSString *aString) | |
549 | { | |
550 | // This string may be a OSSymbol already, cheap check. | |
551 | if (OSDynamicCast(OSSymbol, aString)) { | |
552 | aString->retain(); | |
553 | return (const OSSymbol *) aString; | |
554 | } else if (((const OSSymbol *) aString)->flags & kOSStringNoCopy) { | |
555 | return OSSymbol::withCStringNoCopy(aString->getCStringNoCopy()); | |
556 | } else { | |
557 | return OSSymbol::withCString(aString->getCStringNoCopy()); | |
558 | } | |
559 | } | |
560 | ||
561 | const OSSymbol * | |
562 | OSSymbol::withCString(const char *cString) | |
563 | { | |
564 | const OSSymbol *symbol; | |
565 | ||
566 | // Check if the symbol exists already, we don't need to take a lock here, | |
567 | // since existingSymbolForCString will take the shared lock. | |
568 | symbol = OSSymbol::existingSymbolForCString(cString); | |
569 | if (symbol) { | |
570 | return symbol; | |
571 | } | |
572 | ||
573 | OSSymbol *newSymb = new OSSymbol; | |
574 | if (!newSymb) { | |
575 | return newSymb; | |
576 | } | |
577 | ||
578 | if (newSymb->OSString::initWithCString(cString)) { | |
579 | pool->closeWriteGate(); | |
580 | symbol = pool->insertSymbol(newSymb); | |
581 | pool->openWriteGate(); | |
582 | ||
583 | if (symbol) { | |
584 | // Somebody must have inserted the new symbol so free our copy | |
585 | newSymb->OSString::free(); | |
586 | return symbol; | |
587 | } | |
588 | } | |
589 | ||
590 | return newSymb; // return the newly created & inserted symbol. | |
1c79356b A |
591 | } |
592 | ||
0a7de745 A |
593 | const OSSymbol * |
594 | OSSymbol::withCStringNoCopy(const char *cString) | |
595 | { | |
596 | const OSSymbol *symbol; | |
597 | OSSymbol *newSymb; | |
598 | ||
599 | // Check if the symbol exists already, we don't need to take a lock here, | |
600 | // since existingSymbolForCString will take the shared lock. | |
601 | symbol = OSSymbol::existingSymbolForCString(cString); | |
602 | if (symbol) { | |
603 | return symbol; | |
604 | } | |
605 | ||
606 | newSymb = new OSSymbol; | |
607 | if (!newSymb) { | |
608 | return newSymb; | |
609 | } | |
610 | ||
611 | if (newSymb->OSString::initWithCStringNoCopy(cString)) { | |
612 | pool->closeWriteGate(); | |
613 | symbol = pool->insertSymbol(newSymb); | |
614 | pool->openWriteGate(); | |
615 | ||
616 | if (symbol) { | |
617 | // Somebody must have inserted the new symbol so free our copy | |
618 | newSymb->OSString::free(); | |
619 | return symbol; | |
620 | } | |
621 | } | |
622 | ||
623 | return newSymb; // return the newly created & inserted symbol. | |
1c79356b A |
624 | } |
625 | ||
0a7de745 A |
626 | const OSSymbol * |
627 | OSSymbol::existingSymbolForString(const OSString *aString) | |
628 | { | |
629 | if (OSDynamicCast(OSSymbol, aString)) { | |
630 | aString->retain(); | |
631 | return (const OSSymbol *) aString; | |
632 | } | |
633 | ||
634 | return OSSymbol::existingSymbolForCString(aString->getCStringNoCopy()); | |
1c79356b A |
635 | } |
636 | ||
0a7de745 A |
637 | const OSSymbol * |
638 | OSSymbol::existingSymbolForCString(const char *cString) | |
1c79356b | 639 | { |
0a7de745 | 640 | OSSymbol *symbol; |
1c79356b | 641 | |
0a7de745 A |
642 | pool->closeReadGate(); |
643 | symbol = pool->findSymbol(cString); | |
644 | pool->openReadGate(); | |
645 | ||
646 | return symbol; | |
1c79356b A |
647 | } |
648 | ||
0a7de745 A |
649 | void |
650 | OSSymbol::checkForPageUnload(void *startAddr, void *endAddr) | |
55e303ae | 651 | { |
0a7de745 A |
652 | OSSymbol *probeSymbol; |
653 | OSSymbolPoolState state; | |
654 | ||
655 | pool->closeWriteGate(); | |
656 | state = pool->initHashState(); | |
657 | while ((probeSymbol = pool->nextHashState(&state))) { | |
658 | if (probeSymbol->string >= startAddr && probeSymbol->string < endAddr) { | |
659 | probeSymbol->OSString::initWithCString(probeSymbol->string); | |
660 | } | |
661 | } | |
662 | pool->openWriteGate(); | |
55e303ae A |
663 | } |
664 | ||
0a7de745 A |
665 | void |
666 | OSSymbol::taggedRelease(const void *tag) const | |
1c79356b | 667 | { |
0a7de745 | 668 | super::taggedRelease(tag); |
55e303ae A |
669 | } |
670 | ||
0a7de745 A |
671 | void |
672 | OSSymbol::taggedRelease(const void *tag, const int when) const | |
55e303ae | 673 | { |
0a7de745 | 674 | super::taggedRelease(tag, when); |
1c79356b A |
675 | } |
676 | ||
0a7de745 A |
677 | void |
678 | OSSymbol::free() | |
1c79356b | 679 | { |
0a7de745 A |
680 | pool->closeWriteGate(); |
681 | pool->removeSymbol(this); | |
682 | pool->openWriteGate(); | |
683 | super::free(); | |
1c79356b A |
684 | } |
685 | ||
0a7de745 A |
686 | bool |
687 | OSSymbol::isEqualTo(const char *aCString) const | |
1c79356b | 688 | { |
0a7de745 | 689 | return super::isEqualTo(aCString); |
1c79356b A |
690 | } |
691 | ||
0a7de745 A |
692 | bool |
693 | OSSymbol::isEqualTo(const OSSymbol *aSymbol) const | |
1c79356b | 694 | { |
0a7de745 A |
695 | return aSymbol == this; |
696 | } | |
1c79356b | 697 | |
0a7de745 A |
698 | bool |
699 | OSSymbol::isEqualTo(const OSMetaClassBase *obj) const | |
700 | { | |
701 | OSSymbol * sym; | |
702 | OSString * str; | |
703 | ||
704 | if ((sym = OSDynamicCast(OSSymbol, obj))) { | |
705 | return isEqualTo(sym); | |
706 | } else if ((str = OSDynamicCast(OSString, obj))) { | |
707 | return super::isEqualTo(str); | |
708 | } else { | |
709 | return false; | |
710 | } | |
1c79356b | 711 | } |
316670eb A |
712 | |
713 | unsigned int | |
714 | OSSymbol::bsearch( | |
715 | const void * key, | |
716 | const void * array, | |
717 | unsigned int arrayCount, | |
718 | size_t memberSize) | |
719 | { | |
0a7de745 A |
720 | const void **p; |
721 | unsigned int baseIdx = 0; | |
722 | unsigned int lim; | |
723 | ||
724 | for (lim = arrayCount; lim; lim >>= 1) { | |
725 | p = (typeof(p))(((uintptr_t) array) + (baseIdx + (lim >> 1)) * memberSize); | |
726 | if (key == *p) { | |
727 | return baseIdx + (lim >> 1); | |
728 | } | |
729 | if (key > *p) { | |
730 | // move right | |
731 | baseIdx += (lim >> 1) + 1; | |
732 | lim--; | |
733 | } | |
734 | // else move left | |
735 | } | |
736 | // not found, insertion point here | |
737 | return baseIdx + (lim >> 1); | |
316670eb | 738 | } |