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