Loading...
libkern/c++/OSSymbol.cpp xnu-792.22.5 xnu-1228
--- xnu/xnu-792.22.5/libkern/c++/OSSymbol.cpp
+++ xnu/xnu-1228/libkern/c++/OSSymbol.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
+ * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
  *
  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
  * 
@@ -51,6 +51,24 @@
 #define ACCUMSIZE(s)
 #endif
 
+#define INITIAL_POOL_SIZE  (exp2ml(1 + log2(kInitBucketCount)))
+
+#define GROW_FACTOR   (1)
+#define SHRINK_FACTOR (3)
+
+#define GROW_POOL()     do \
+    if (count * GROW_FACTOR > nBuckets) { \
+        reconstructSymbols(true); \
+    } \
+while (0)
+
+#define SHRINK_POOL()     do \
+    if (count * SHRINK_FACTOR < nBuckets && \
+        nBuckets > INITIAL_POOL_SIZE) { \
+        reconstructSymbols(false); \
+    } \
+while (0)
+
 class OSSymbolPool
 {
 private:
@@ -84,7 +102,8 @@
     static unsigned long log2(unsigned int x);
     static unsigned long exp2ml(unsigned int x);
 
-    void reconstructSymbols();
+    void reconstructSymbols(void);
+    void reconstructSymbols(bool grow);
 
 public:
     static void *operator new(size_t size);
@@ -126,7 +145,7 @@
 bool OSSymbolPool::init()
 {
     count = 0;
-    nBuckets = exp2ml(1 + log2(kInitBucketCount));
+    nBuckets = INITIAL_POOL_SIZE;
     buckets = (Bucket *) kalloc(nBuckets * sizeof(Bucket));
     ACCUMSIZE(nBuckets * sizeof(Bucket));
     if (!buckets)
@@ -198,14 +217,35 @@
         return thisBucket->symbolP[stateP->j];
 }
 
-void OSSymbolPool::reconstructSymbols()
-{
-    OSSymbolPool old(this);
+void OSSymbolPool::reconstructSymbols(void)
+{
+    this->reconstructSymbols(true);
+}
+
+void OSSymbolPool::reconstructSymbols(bool grow)
+{
+    unsigned int new_nBuckets = nBuckets;
     OSSymbol *insert;
     OSSymbolPoolState state;
 
-    nBuckets += nBuckets + 1;
+    if (grow) {
+        new_nBuckets += new_nBuckets + 1;
+    } else {
+       /* Don't shrink the pool below the default initial size.
+        */
+        if (nBuckets <= INITIAL_POOL_SIZE) {
+            return;
+        }
+        new_nBuckets = (new_nBuckets - 1) / 2;
+    }
+
+   /* Create old pool to iterate after doing above check, cause it
+    * gets finalized at return.
+    */
+    OSSymbolPool old(this);
+
     count = 0;
+    nBuckets = new_nBuckets;
     buckets = (Bucket *) kalloc(nBuckets * sizeof(Bucket));
     ACCUMSIZE(nBuckets * sizeof(Bucket));
     /* @@@ gvdl: Zero test and panic if can't set up pool */
@@ -281,8 +321,7 @@
         thisBucket->symbolP = list;
         thisBucket->count++;
         count++;
-        if (count > nBuckets)
-            reconstructSymbols();
+        GROW_POOL();
 
         return sym;
     }
@@ -304,8 +343,7 @@
     kfree(thisBucket->symbolP, j * sizeof(OSSymbol *));
     ACCUMSIZE(-(j * sizeof(OSSymbol *)));
     thisBucket->symbolP = list;
-    if (count > nBuckets)
-        reconstructSymbols();
+    GROW_POOL();
 
     return sym;
 }
@@ -331,6 +369,7 @@
             thisBucket->symbolP = 0;
             count--;
             thisBucket->count--;
+            SHRINK_POOL();
             return;
         }
         return;
@@ -344,6 +383,7 @@
 	    ACCUMSIZE(-(2 * sizeof(OSSymbol *)));
             count--;
             thisBucket->count--;
+            SHRINK_POOL();
             return;
         }
 
@@ -354,6 +394,7 @@
 	    ACCUMSIZE(-(2 * sizeof(OSSymbol *)));
             count--;
             thisBucket->count--;
+            SHRINK_POOL();
             return;
         }
         return;