|
|
1.1 root 1: /*
2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3: *
4: * @APPLE_LICENSE_HEADER_START@
5: *
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.
11: *
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
18: * under the License.
19: *
20: * @APPLE_LICENSE_HEADER_END@
21: */
22: /* IOSymbol.cpp created by gvdl on Fri 1998-11-17 */
23:
24: #include <sys/cdefs.h>
25:
26: __BEGIN_DECLS
27: #include <kern/lock.h>
28: __END_DECLS
29:
30: #include <libkern/c++/OSSymbol.h>
31: #include <libkern/c++/OSLib.h>
32:
33: #define super OSString
34:
35: typedef struct { int i, j; } OSSymbolPoolState;
36:
37: #ifdef DEBUG
38: extern "C" {
39: extern int debug_container_malloc_size;
40: };
41: #define ACCUMSIZE(s) do { debug_container_malloc_size += (s); } while(0)
42: #else
43: #define ACCUMSIZE(s)
44: #endif
45:
46: class OSSymbolPool
47: {
48: private:
49: static const unsigned int kInitBucketCount = 16;
50:
51: typedef struct { unsigned int count; OSSymbol **symbolP; } Bucket;
52:
53: Bucket *buckets;
54: unsigned int nBuckets;
55: unsigned int count;
56: mutex_t *poolGate;
57:
58: static inline void hashSymbol(const char *s,
59: unsigned int *hashP,
60: unsigned int *lenP)
61: {
62: unsigned int hash = 0;
63: unsigned int len = 0;
64:
65: /* Unroll the loop. */
66: for (;;) {
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;
71: }
72: *lenP = len;
73: *hashP = hash;
74: }
75:
76: static unsigned long log2(unsigned int x);
77: static unsigned long exp2ml(unsigned int x);
78:
79: void reconstructSymbols();
80:
81: public:
82: static void *operator new(size_t size);
83: static void operator delete(void *mem, size_t size);
84:
85: OSSymbolPool() { };
86: OSSymbolPool(const OSSymbolPool *old);
87: virtual ~OSSymbolPool();
88:
89: bool init();
90:
91: inline void closeGate() { mutex_lock(poolGate); };
92: inline void openGate() { mutex_unlock(poolGate); };
93:
94: OSSymbol *findSymbol(const char *cString) const;
95: OSSymbol *insertSymbol(OSSymbol *sym);
96: void removeSymbol(const char *cString);
97:
98: OSSymbolPoolState initHashState();
99: OSSymbol *nextHashState(OSSymbolPoolState *stateP);
100: };
101:
102: void * OSSymbolPool::operator new(size_t size)
103: {
104: void *mem = (void *)kalloc(size);
105: ACCUMSIZE(size);
106: assert(mem);
107: bzero(mem, size);
108:
109: return mem;
110: }
111:
112: void OSSymbolPool::operator delete(void *mem, size_t size)
113: {
114: kfree((vm_offset_t)mem, size);
115: ACCUMSIZE(-size);
116: }
117:
118: bool OSSymbolPool::init()
119: {
120: count = 0;
121: nBuckets = exp2ml(1 + log2(kInitBucketCount));
122: buckets = (Bucket *) kalloc(nBuckets * sizeof(Bucket));
123: ACCUMSIZE(nBuckets * sizeof(Bucket));
124: if (!buckets)
125: return false;
126:
127: bzero(buckets, nBuckets * sizeof(Bucket));
128:
129: poolGate = mutex_alloc(0);
130:
131: return poolGate != 0;
132: }
133:
134: OSSymbolPool::OSSymbolPool(const OSSymbolPool *old)
135: {
136: count = old->count;
137: nBuckets = old->nBuckets;
138: buckets = old->buckets;
139:
140: poolGate = 0; // Do not duplicate the poolGate
141: }
142:
143: OSSymbolPool::~OSSymbolPool()
144: {
145: if (buckets) {
146: kfree((vm_offset_t)buckets, nBuckets * sizeof(Bucket));
147: ACCUMSIZE(-(nBuckets * sizeof(Bucket)));
148: }
149:
150: if (poolGate)
151: kfree((vm_offset_t) poolGate, 36 * 4);
152: }
153:
154: unsigned long OSSymbolPool::log2(unsigned int x)
155: {
156: unsigned long i;
157:
158: for (i = 0; x > 1 ; i++)
159: x >>= 1;
160: return i;
161: }
162:
163: unsigned long OSSymbolPool::exp2ml(unsigned int x)
164: {
165: return (1 << x) - 1;
166: }
167:
168: OSSymbolPoolState OSSymbolPool::initHashState()
169: {
170: OSSymbolPoolState newState = { nBuckets, 0 };
171: return newState;
172: }
173:
174: OSSymbol *OSSymbolPool::nextHashState(OSSymbolPoolState *stateP)
175: {
176: Bucket *thisBucket = &buckets[stateP->i];
177:
178: while (!stateP->j) {
179: if (!stateP->i)
180: return 0;
181: stateP->i--;
182: thisBucket--;
183: stateP->j = thisBucket->count;
184: }
185:
186: stateP->j--;
187: if (thisBucket->count == 1)
188: return (OSSymbol *) thisBucket->symbolP;
189: else
190: return thisBucket->symbolP[stateP->j];
191: }
192:
193: void OSSymbolPool::reconstructSymbols()
194: {
195: OSSymbolPool old(this);
196: OSSymbol *insert;
197: OSSymbolPoolState state;
198:
199: nBuckets += nBuckets + 1;
200: count = 0;
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));
205:
206: state = old.initHashState();
207: while ( (insert = old.nextHashState(&state)) )
208: insertSymbol(insert);
209: }
210:
211: OSSymbol *OSSymbolPool::findSymbol(const char *cString) const
212: {
213: Bucket *thisBucket;
214: unsigned int j, inLen, hash;
215: OSSymbol *probeSymbol, **list;
216:
217: hashSymbol(cString, &hash, &inLen); inLen++;
218: thisBucket = &buckets[hash % nBuckets];
219: j = thisBucket->count;
220:
221: if (!j)
222: return 0;
223:
224: if (j == 1) {
225: probeSymbol = (OSSymbol *) thisBucket->symbolP;
226:
227: if (inLen == probeSymbol->length
228: && (strcmp(probeSymbol->string, cString) == 0)
229: && (probeSymbol->getRetainCount() >= 1)) // WRONG need when
230: return probeSymbol;
231: else
232: return 0;
233: }
234:
235: for (list = thisBucket->symbolP; j--; list++) {
236: probeSymbol = *list;
237: if (inLen == probeSymbol->length
238: && (strcmp(probeSymbol->string, cString) == 0)
239: && (probeSymbol->getRetainCount() >= 1)) // WRONG need when
240: return probeSymbol;
241: }
242:
243: return 0;
244: }
245:
246: OSSymbol *OSSymbolPool::insertSymbol(OSSymbol *sym)
247: {
248: const char *cString = sym->string;
249: Bucket *thisBucket;
250: unsigned int j, inLen, hash;
251: OSSymbol *probeSymbol, **list;
252:
253: hashSymbol(cString, &hash, &inLen); inLen++;
254: thisBucket = &buckets[hash % nBuckets];
255: j = thisBucket->count;
256:
257: if (!j) {
258: thisBucket->symbolP = (OSSymbol **) sym;
259: thisBucket->count++;
260: count++;
261: return 0;
262: }
263:
264: if (j == 1) {
265: probeSymbol = (OSSymbol *) thisBucket->symbolP;
266:
267: if (inLen == probeSymbol->length
268: && strcmp(probeSymbol->string, cString) == 0)
269: return probeSymbol;
270:
271: list = (OSSymbol **) kalloc(2 * sizeof(OSSymbol *));
272: ACCUMSIZE(2 * sizeof(OSSymbol *));
273: /* @@@ gvdl: Zero test and panic if can't set up pool */
274: list[0] = sym;
275: list[1] = probeSymbol;
276: thisBucket->symbolP = list;
277: thisBucket->count++;
278: count++;
279: if (count > nBuckets)
280: reconstructSymbols();
281:
282: return 0;
283: }
284:
285: for (list = thisBucket->symbolP; j--; list++) {
286: probeSymbol = *list;
287: if (inLen == probeSymbol->length
288: && strcmp(probeSymbol->string, cString) == 0)
289: return probeSymbol;
290: }
291:
292: j = thisBucket->count++;
293: 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 */
297: list[0] = sym;
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();
304:
305: return 0;
306: }
307:
308: void OSSymbolPool::removeSymbol(const char *cString)
309: {
310: Bucket *thisBucket;
311: unsigned int j, inLen, hash;
312: OSSymbol *probeSymbol, **list;
313:
314: hashSymbol(cString, &hash, &inLen); inLen++;
315: thisBucket = &buckets[hash % nBuckets];
316: j = thisBucket->count;
317: list = thisBucket->symbolP;
318:
319: if (!j)
320: return;
321:
322: if (j == 1) {
323: probeSymbol = (OSSymbol *) list;
324:
325: if (inLen == probeSymbol->length
326: && strcmp(probeSymbol->string, cString) == 0) {
327: thisBucket->symbolP = 0;
328: count--;
329: thisBucket->count--;
330: return;
331: }
332: return;
333: }
334:
335: if (j == 2) {
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 *)));
342: count--;
343: thisBucket->count--;
344: return;
345: }
346:
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 *)));
353: count--;
354: thisBucket->count--;
355: return;
356: }
357: return;
358: }
359:
360: for (; j--; list++) {
361: probeSymbol = *list;
362: if (inLen == probeSymbol->length
363: && strcmp(probeSymbol->string, cString) == 0) {
364:
365: list = (OSSymbol **)
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 *));
371: if (j)
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;
378: count--;
379: thisBucket->count--;
380: return;
381: }
382: }
383: }
384:
385: /*
386: *********************************************************************
387: * From here on we are actually implementing the OSSymbol class
388: *********************************************************************
389: */
390: OSDefineMetaClassAndStructorsWithInit(OSSymbol, OSString,
391: OSSymbol::initialize())
392:
393: static OSSymbolPool *pool;
394:
395: void OSSymbol::initialize()
396: {
397: pool = new OSSymbolPool;
398: assert(pool);
399:
400: if (!pool->init()) {
401: delete pool;
402: assert(false);
403: };
404: }
405:
406: bool OSSymbol::initWithCStringNoCopy(const char *) { return false; }
407: bool OSSymbol::initWithCString(const char *) { return false; }
408: bool OSSymbol::initWithString(const OSString *) { return false; }
409:
410: const OSSymbol *OSSymbol::withString(const OSString *aString)
411: {
412: if (((const OSSymbol *) aString)->flags & kOSStringNoCopy)
413: return OSSymbol::withCStringNoCopy(aString->getCStringNoCopy());
414: else
415: return OSSymbol::withCString(aString->getCStringNoCopy());
416: }
417:
418: const OSSymbol *OSSymbol::withCString(const char *cString)
419: {
420: pool->closeGate();
421:
422: OSSymbol *newSymb = pool->findSymbol(cString);
423: if (newSymb)
424: newSymb->retain();
425: else if ( (newSymb = new OSSymbol) ) {
426: if (newSymb->OSString::initWithCString(cString))
427: pool->insertSymbol(newSymb);
428: else {
429: newSymb->free();
430: newSymb = 0;
431: }
432: }
433: pool->openGate();
434:
435: return newSymb;
436: }
437:
438: const OSSymbol *OSSymbol::withCStringNoCopy(const char *cString)
439: {
440: pool->closeGate();
441:
442: OSSymbol *newSymb = pool->findSymbol(cString);
443: if (newSymb)
444: newSymb->retain();
445: else if ( (newSymb = new OSSymbol) ) {
446: if (newSymb->OSString::initWithCStringNoCopy(cString))
447: pool->insertSymbol(newSymb);
448: else {
449: newSymb->free();
450: newSymb = 0;
451: }
452: }
453: pool->openGate();
454:
455: return newSymb;
456: }
457:
458: void OSSymbol::checkForPageUnload(void *startAddr, void *endAddr)
459: {
460: OSSymbol *probeSymbol;
461: OSSymbolPoolState state;
462:
463: pool->closeGate();
464: state = pool->initHashState();
465: while ( (probeSymbol = pool->nextHashState(&state)) ) {
466: if (probeSymbol->string >= startAddr || probeSymbol->string < endAddr) {
467: const char *oldString = probeSymbol->string;
468:
469: probeSymbol->string = (char *) kalloc(probeSymbol->length);
470: ACCUMSIZE(probeSymbol->length);
471: bcopy(oldString, probeSymbol->string, probeSymbol->length);
472: probeSymbol->flags &= ~kOSStringNoCopy;
473: }
474: }
475: pool->openGate();
476: }
477:
478: void OSSymbol::free()
479: {
480: pool->closeGate();
481: pool->removeSymbol(string);
482: pool->openGate();
483:
484: super::free();
485: }
486:
487: bool OSSymbol::isEqualTo(const char *aCString) const
488: {
489: return super::isEqualTo(aCString);
490: }
491:
492: bool OSSymbol::isEqualTo(const OSSymbol *aSymbol) const
493: {
494: return aSymbol == this;
495: }
496:
497: bool OSSymbol::isEqualTo(const OSObject *obj) const
498: {
499: OSSymbol * sym;
500: OSString * str;
501:
502: if ((sym = OSDynamicCast(OSSymbol, (OSObject *)obj )))
503: return isEqualTo(sym);
504: else if ((str = OSDynamicCast(OSString, (OSObject *)obj )))
505: return super::isEqualTo(str);
506: else
507: return false;
508: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.