symbolTable.cpp

Go to the documentation of this file.
00001 /* Copyright 1994, 1995 LongView Technologies L.L.C. $Revision: 1.21 $ */
00002 /* Copyright (c) 2006, Sun Microsystems, Inc.
00003 All rights reserved.
00004 
00005 Redistribution and use in source and binary forms, with or without modification, are permitted provided that the 
00006 following conditions are met:
00007 
00008     * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
00009     * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following 
00010           disclaimer in the documentation and/or other materials provided with the distribution.
00011     * Neither the name of Sun Microsystems nor the names of its contributors may be used to endorse or promote products derived 
00012           from this software without specific prior written permission.
00013 
00014 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT 
00015 NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 
00016 THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 
00017 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
00018 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE 
00019 OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE
00020 
00021 
00022 */
00023 
00024 
00025 # include "incls/_precompiled.incl"
00026 # include "incls/_symbolTable.cpp.incl"
00027 
00028 # define FOR_ALL_ENTRIES(entry) \
00029   for (entry = firstBucket(); entry <= lastBucket(); entry ++)
00030 
00031 # define FOR_ALL_SYMBOL_ADDR(bucket, var, code)                         \
00032     { if (bucket->is_symbol()) {                                        \
00033          var = (symbolOop*) bucket; code;                               \
00034       } else {                                                          \
00035         for (symbolTableLink* l = bucket->get_link(); l; l = l->next) { \
00036           var = &l->symbol; code;                                       \
00037         }                                                               \
00038       }                                                                 \
00039     }
00040 
00041 int hash(char* name, int len) {
00042   // hash on at most 32 characters, evenly spaced
00043   int increment;
00044  
00045   if (len < 32) {
00046     increment = 1;
00047   } else {
00048     increment = len >> 5;
00049   }
00050  
00051   // hashpjw from Dragon book (ASU p. 436), except increment differently
00052  
00053   assert(BitsPerByte * BytesPerWord == 32, "assumes 32-bit words");
00054   long unsigned h = 0;
00055   long unsigned g;
00056   char* s = name;
00057   char* end = s + len;
00058   for (; s < end; s = s + increment) {
00059     h = (h << 4) + (long unsigned) *s;
00060     if (g = h & 0xf0000000) h ^= g | (g >> 24);
00061   }
00062   return h;
00063 }
00064 
00065 symbolTable::symbolTable() {
00066   for (int i = 0; i < symbol_table_size; i ++) buckets[i].clear();
00067   free_list = first_free_link = end_block = NULL;
00068 }
00069 
00070 symbolOop symbolTable::basic_add(char *name, int len, int hashValue) {
00071   symbolKlass* sk = (symbolKlass*) Universe::symbolKlassObj()->klass_part();
00072   symbolOop str =   sk->allocateSymbol(name, len);
00073   basic_add(str, hashValue);
00074   return str;
00075 }
00076 
00077 bool symbolTable::is_present(symbolOop sym) {
00078   char* name = (char*) sym->bytes();
00079   int   len  = sym->length();
00080   int hashValue = hash(name, len);
00081   symbolTableEntry* bucket = bucketFor(hashValue);
00082   if (bucket->is_empty()) return false;
00083   if (bucket->is_symbol())
00084     return bucket->get_symbol()->equals(name, len);
00085   for (symbolTableLink* l = bucket->get_link(); l; l = l->next)
00086     if (l->symbol->equals(name, len)) return true;
00087   return false;
00088 }
00089 
00090 symbolOop symbolTable::lookup(char* name, int len) {
00091   int hashValue = hash(name, len);
00092   symbolTableEntry* bucket = bucketFor(hashValue);
00093   if (!bucket->is_empty()) {
00094     if (bucket->is_symbol()) {
00095       if (bucket->get_symbol()->equals(name, len)) return bucket->get_symbol();
00096     } else {
00097       for (symbolTableLink* l = bucket->get_link(); l; l = l->next)
00098         if (l->symbol->equals(name, len)) return l->symbol;
00099     }
00100   }
00101   return basic_add(name, len, hashValue);
00102 }
00103 
00104 void symbolTable::add(symbolOop s) {
00105   assert(s->is_symbol(),
00106          "adding something that's not a symbol to the symbol table");
00107   assert(s->is_old(), "all symbols should be tenured");
00108   int hashValue = hash((char*) s->bytes(), s->length());
00109   basic_add(s, hashValue);
00110 }
00111 
00112 void symbolTable::add_symbol(symbolOop s) {
00113   basic_add(s, hash((char*) s->bytes(), s->length()));
00114 }
00115 
00116 symbolOop symbolTable::basic_add(symbolOop s, int hashValue) {
00117   assert(s->is_symbol(),
00118          "adding something that's not a symbol to the symbol table");
00119   assert(s->is_old(), "all symbols should be tenured");
00120 
00121   // Add the indentity hash for the new symbol
00122   s->hash_value();
00123   assert(!s->mark()->has_valid_hash(), "should not have a hash yet");
00124   s->set_mark(s->mark()->set_hash(s->hash_value()));
00125   assert(s->mark()->has_valid_hash(), "should have a hash now");
00126 
00127   symbolTableEntry* bucket = bucketFor(hashValue);
00128 
00129   if (bucket->is_empty()) {
00130     bucket->set_symbol(s);
00131   } else {
00132     symbolTableLink*  old_link;
00133     if (bucket->is_symbol()) {
00134       old_link = Universe::symbol_table->new_link(bucket->get_symbol());
00135     } else {
00136       old_link = bucket->get_link();
00137     }
00138     bucket->set_link(Universe::symbol_table->new_link(s, old_link));
00139   }
00140   return s;
00141 }
00142 
00143 void symbolTable::switch_pointers(oop from, oop to) {
00144   if (! from->is_symbol()) return;
00145   assert(to->is_symbol(),
00146          "cannot replace a symbol with a non-symbol");
00147 
00148   symbolTableEntry* e;
00149   FOR_ALL_ENTRIES(e) {
00150     symbolOop* addr;
00151     FOR_ALL_SYMBOL_ADDR(e, addr, SWITCH_POINTERS_TEMPLATE(addr));
00152   }
00153 }
00154 
00155 void symbolTable::follow_used_symbols() {
00156   // throw out unreachable symbols
00157   symbolTableEntry* e;
00158   FOR_ALL_ENTRIES(e) {
00159     // If we have a one element list; preserve the symbol but remove the chain
00160     // This moving around cannot take place after follow_root has been called
00161     // since follow_root reverse pointers.
00162     if (e->get_link() && !e->get_link()->next) {
00163       symbolTableLink* old = e->get_link();
00164       e->set_symbol(old->symbol);
00165       delete_link(old);
00166     }
00167 
00168     if (e->is_symbol()) {
00169       if (e->get_symbol()->is_gc_marked()) 
00170         MarkSweep::follow_root((oop*) e);
00171       else
00172         e->clear(); // unreachable; clear entry
00173     } else {
00174       symbolTableLink** p    = (symbolTableLink**) e;
00175       symbolTableLink*  link = e->get_link();
00176       while (link) {
00177         if (link->symbol->is_gc_marked()) {
00178           MarkSweep::follow_root((oop*) &link->symbol);
00179           p    = &link->next;
00180           link = link->next;
00181         } else {
00182           // unreachable; remove from table
00183           symbolTableLink* old = link;
00184           *p   = link->next;
00185           link = link->next;
00186           old->next = NULL;
00187           delete_link(old);
00188         }
00189       }
00190     }
00191   }
00192 }
00193 
00194 void symbolTableEntry::deallocate() {
00195   if(!is_symbol() && get_link()) 
00196     Universe::symbol_table->delete_link(get_link());
00197 }
00198 
00199 bool symbolTableEntry::verify(int i) {
00200   bool flag = true;
00201   if (is_symbol()) {
00202     if (!get_symbol()->is_symbol()) {
00203       error("entry %#lx in symbol table isn't a symbol", get_symbol());
00204       flag = false;
00205     }
00206   } else {
00207     if (get_link()) flag = get_link()->verify(i);
00208   }
00209   return flag;
00210 }
00211 
00212 void symbolTable::verify() {
00213   for (int i = 0; i < symbol_table_size; i ++)
00214     if (!buckets[i].verify(i))
00215       lprintf("\tof bucket %ld of symbol table\n", long(i));
00216 }
00217 
00218 
00219 void symbolTable::relocate() {
00220   symbolTableEntry* e;
00221   FOR_ALL_ENTRIES(e) {
00222     symbolOop* addr;
00223     FOR_ALL_SYMBOL_ADDR(e, addr, RELOCATE_TEMPLATE(addr));
00224   }
00225 }
00226 
00227 bool symbolTableLink::verify(int i) {
00228   bool flag = true;
00229   for (symbolTableLink* l = this; l; l = l->next) {
00230     if (! l->symbol->is_symbol()) {
00231       error("entry %#lx in symbol table isn't a symbol", l->symbol);
00232       flag = false;
00233     } else if (hash((char*) l->symbol->bytes(), l->symbol->length()) 
00234                % symbol_table_size != i) {
00235       error("entry %#lx in symbol table has wrong hash value", l->symbol);
00236       flag = false;
00237     } else if (!l->symbol->is_old()) {
00238       error("entry %#lx in symbol table isn't tenured", l->symbol);
00239       flag = false;
00240     }
00241   }
00242   return flag;
00243 }
00244 
00245 int symbolTableEntry::length() {
00246   if (is_symbol()) return 1;
00247   if (!get_link()) return 0;
00248   int count = 0;
00249   for (symbolTableLink* l = get_link(); l; l = l->next) count ++;
00250   return count;
00251 }
00252 
00253 symbolTableLink* symbolTable::new_link(symbolOop s, symbolTableLink* n) {
00254   symbolTableLink* res;
00255   if (free_list) {
00256     res = free_list;
00257     free_list = free_list->next;
00258   } else {
00259     const int block_size = 500;
00260     if (first_free_link == end_block) {
00261       first_free_link = NEW_C_HEAP_ARRAY(symbolTableLink, block_size);
00262       end_block = first_free_link + block_size;
00263     }
00264     res = first_free_link++;
00265   } 
00266   res->symbol = s;
00267   res->next   = n;
00268   return res;
00269 }
00270 
00271 void symbolTable::delete_link(symbolTableLink* l) {
00272   // Add the link to the freelist
00273   symbolTableLink* end = l;
00274   while(end->next) end = end->next;
00275   end->next = free_list;
00276   free_list = l;
00277 }
00278 
00279 // much of this comes from the print_histogram routine in mapTable.c,
00280 // so if bug fixes are made here, also make them in mapTable.cpp.
00281 void symbolTable::print_histogram() {
00282   const int results_length = 100;
00283   int results[results_length];
00284   
00285   // initialize results to zero
00286   for (int j = 0; j < results_length; j++) {
00287     results[j] = 0;
00288   }
00289 
00290   int total = 0;
00291   int min_symbols = 0;
00292   int max_symbols = 0;
00293   int out_of_range = 0;
00294   for (int i = 0; i < symbol_table_size; i++) {
00295     symbolTableEntry curr = buckets[i];
00296     int counter = curr.length();
00297     total += counter;
00298     if (counter < results_length) {
00299       results[counter]++;
00300     } else {
00301       out_of_range++;
00302     }
00303     min_symbols = min(min_symbols, counter);
00304     max_symbols = max(max_symbols, counter);
00305   }
00306   lprintf("Symbol Table:\n");
00307   lprintf("%8s %5d\n", "Total  ", total);
00308   lprintf("%8s %5d\n", "Minimum", min_symbols);
00309   lprintf("%8s %5d\n", "Maximum", max_symbols);
00310   lprintf("%8s %3.2f\n", "Average",
00311           ((float) total / (float) symbol_table_size));
00312   lprintf("%s\n", "Histogram:");
00313   lprintf(" %s %29s\n", "Length", "Number chains that length");
00314   for (i = 0; i < results_length; i++) {
00315     if (results[i] > 0) {
00316       lprintf("%6d %10d\n", i, results[i]);
00317     }
00318   }
00319   int line_length = 70;    
00320   lprintf("%s %30s\n", " Length", "Number chains that length");
00321   for (i = 0; i < results_length; i++) {
00322     if (results[i] > 0) {
00323       lprintf("%4d", i);
00324       for (j = 0; (j < results[i]) && (j < line_length);  j++) {
00325         lprintf("%1s", "*");
00326       }
00327       if (j == line_length) {
00328         lprintf("%1s", "+");
00329       }
00330       lprintf("\n");
00331     }
00332   }  
00333   lprintf(" %s %d: %d\n", "Number chains longer than",
00334           results_length, out_of_range);
00335 }

Generated on Mon Oct 9 13:37:28 2006 for Strongtalk VM by  doxygen 1.4.7