lookupCache.cpp

Go to the documentation of this file.
00001 /* Copyright 1994 - 1996 LongView Technologies L.L.C. $Revision: 1.75 $ */
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 # include "incls/_precompiled.incl"
00025 # include "incls/_lookupCache.cpp.incl"
00026 
00027 int lookupCache::number_of_primary_hits;
00028 int lookupCache::number_of_secondary_hits;
00029 int lookupCache::number_of_misses;
00030 
00031 methodOop LookupResult::method() const {
00032   assert(!is_empty(), "connot be empty");
00033   if (is_method())
00034     return methodOop(_result);
00035   return get_nmethod()->method();
00036 }
00037 
00038 methodOop LookupResult::method_or_null() const {
00039   if (is_empty())  return NULL;
00040   if (is_method()) return methodOop(_result);
00041   return get_nmethod()->method();  
00042 }
00043 
00044 jumpTableEntry* LookupResult::entry() const {
00045   assert(!is_empty(), "cannot be empty");  
00046   return is_entry() ? (jumpTableEntry*) _result : NULL;
00047 }
00048 
00049 nmethod* LookupResult::get_nmethod() const {
00050   jumpTableEntry* e = entry();
00051   return e ? e->method() : NULL;
00052 }
00053 
00054 bool LookupResult::matches(methodOop m) const {
00055   if (is_empty()) return false;
00056   return is_method() ? method() == m : false; 
00057 }
00058 
00059 bool LookupResult::matches(nmethod* nm) const {
00060   if (is_empty()) return false;
00061   return is_entry() ? entry()->method() == nm : false;
00062 }
00063 
00064 void LookupResult::print_on(outputStream* st) const {
00065   if (is_empty()) {
00066     st->print("empty");
00067   } else {
00068     method()->print_value_on(st);
00069     st->print(", 0x%lx", value());
00070   }
00071 }
00072 
00073 void LookupResult::print_short_on(outputStream* st) const {
00074   if (is_empty()) {
00075     st->print("empty");
00076   } else {
00077     st->print("0x%lx", value());
00078   }
00079 }
00080 
00081 class cacheElement : ValueObj {
00082  public:
00083   LookupKey    key;
00084   LookupResult result;
00085   int          filler;
00086 
00087   cacheElement() : key(), result() {}
00088 
00089   void verify() {
00090     if (key.klass() || key.selector_or_method()) {
00091       if (result.is_empty()) {
00092          std->print("Verify failed in lookupCache: ");
00093          std->cr();
00094          std->print("  element = (");
00095          key.klass()->print_value_on(std);
00096          std->print("::");
00097          key.selector_or_method()->print_value_on(std);
00098          std->print(")");
00099          std->cr();
00100          std->print("  result = ("); 
00101          result.print_on(std);
00102          std->print_cr(")");
00103          fatal("lookupCache verify failed");
00104       }
00105       nmethod* nm = Universe::code->lookup(&key);
00106       if (result.is_method() && nm) {
00107         error("key %s has interpreted method in lookupTable but should have nmethod %#x", key.print_string(), nm);
00108       } else if (result.is_entry() && result.get_nmethod() != nm) {
00109         error("key %s: nmethod does not match codeTable nmethod", key.print_string());
00110       }
00111       if (UseInliningDatabaseEagerly && result.is_method() && InliningDatabase::lookup(&key) != NULL) {
00112         error("key %s: interpreted method in lookupTable despite inlining DB entry", key.print_string());
00113       }
00114     }
00115   }
00116 
00117 
00118   void clear() {
00119     key.initialize(NULL, NULL);
00120     result.clear();
00121   }
00122 
00123   void initialize(LookupKey* k, LookupResult r) {
00124     key    = *k;
00125     result = r;
00126   }
00127 };
00128 
00129 static cacheElement primary[primary_cache_size];
00130 static cacheElement secondary[secondary_cache_size];
00131 
00132 int lookupCache::primary_cache_address()        { return int(&primary[0]); }
00133 int lookupCache::secondary_cache_address()      { return int(&secondary[0]); }
00134 
00135 void lookupCache::flush() {
00136   int index;
00137   // Clear primary cache
00138   for (index = 0; index < primary_cache_size; index ++)
00139     primary[index].clear();
00140   // Clear secondary cache
00141   for (index = 0; index < secondary_cache_size; index ++)
00142     secondary[index].clear();
00143   // Clear counters
00144   number_of_primary_hits   = 0;
00145   number_of_secondary_hits = 0;
00146   number_of_misses         = 0;
00147 }
00148 
00149 
00150 void lookupCache::flush(LookupKey* key) {
00151   // Flush the entry associated the the lookup key k
00152   int primary_index   = hash_value(key) % primary_cache_size;
00153   int secondary_index = primary_index   % secondary_cache_size;
00154 
00155   if (primary[primary_index].key.equal(key)) {
00156     // If we have a hit in the primary cache
00157     // promoted the secondary entry
00158     primary[primary_index] = secondary[secondary_index];
00159     secondary[secondary_index].clear();
00160     return; 
00161   }
00162 
00163   if (secondary[secondary_index].key.equal(key)) {
00164     // If we have a secondary hit clear the entry
00165     secondary[secondary_index].clear();
00166   }
00167 }
00168 
00169 
00170 void lookupCache::verify() {
00171   int index;
00172   for (index = 0; index < primary_cache_size; index ++)
00173     primary[index].verify();
00174   for (index = 0; index < secondary_cache_size; index ++)
00175     secondary[index].verify();
00176 }
00177 
00178 inline unsigned int lookupCache::hash_value(LookupKey* key) {
00179   return 
00180     ((unsigned int) key->klass() ^ (unsigned int) key->selector_or_method()) 
00181     / sizeof(cacheElement);
00182 }
00183 
00184 inline LookupResult lookupCache::lookup_probe(LookupKey* key) {
00185   assert(key->verify(), "Lookupkey: verify failed");
00186 
00187   int primary_index = hash_value(key) % primary_cache_size;
00188 
00189   if (primary[primary_index].key.equal(key)) {
00190     return primary[primary_index].result;
00191   }
00192 
00193   int secondary_index = primary_index % secondary_cache_size;
00194   if (secondary[secondary_index].key.equal(key)) {
00195     cacheElement tmp;
00196     // swap primary <-> secondary.
00197     tmp                        = primary[primary_index];
00198     primary[primary_index]     = secondary[secondary_index];
00199     secondary[secondary_index] = tmp;
00200     return primary[primary_index].result;
00201   }
00202   LookupResult nothing;
00203   return nothing;
00204 }
00205 
00206 inline LookupResult lookupCache::lookup(LookupKey* key, bool compile) {
00207   // The cache is implemented as a 2-way associative cache.
00208   // Recipe for finding a lookup result.
00209   //  1. Check the primary cache. If hit return result.
00210   //  2. Check the secondary cache.
00211   //     If hit swap primary and secondary and return result.
00212   //  3. Move primary to secondary. Perform a manual lookup, place the result
00213   //     in primary and return the result.
00214   assert(key->verify(), "Lookupkey: verify failed");
00215 
00216   // 1. primary entry
00217   int primary_index = hash_value(key) % primary_cache_size;
00218 
00219   if (primary[primary_index].key.equal(key)) {
00220 #ifdef DEBUG
00221     // this is a good place to put conditional breakpoints using number_of_primary_hits
00222     number_of_primary_hits++;
00223 #endif
00224     return primary[primary_index].result;
00225   }
00226 
00227   // 2. secondary entry
00228   int secondary_index = primary_index % secondary_cache_size;
00229   if (secondary[secondary_index].key.equal(key)) {
00230 #ifdef DEBUG
00231     number_of_secondary_hits++;
00232 #endif
00233     cacheElement tmp;
00234     // swap primary <-> secondary.
00235     tmp                        = primary[primary_index];
00236     primary[primary_index]     = secondary[secondary_index];
00237     secondary[secondary_index] = tmp;
00238     return primary[primary_index].result;
00239   }
00240 
00241   // 3. lookup cache miss
00242   number_of_misses++;
00243   LookupResult result = cache_miss_lookup(key, compile);
00244   if (!result.is_empty()) {
00245     if (UseInliningDatabaseEagerly && result.is_method() && InliningDatabase::lookup(key) != NULL) {
00246       // don't update the cache during inliningDB compiles if the result is a methodOop
00247       // contained in the inlining DB -- otherwise method won't be compiled eagerly
00248       assert(theCompiler, "should only happen during compilation");   // otherwise ic lookup is broken
00249     } else {
00250       secondary[secondary_index] = primary[primary_index];
00251       primary[primary_index].initialize(key, result);
00252 #ifdef ASSERT
00253       primary[primary_index].verify();
00254 #endif
00255     }
00256   }
00257   return result;
00258 }
00259 
00260 LookupResult lookupCache::cache_miss_lookup(LookupKey* key, bool compile) {
00261   // Tracing
00262   if (TraceLookupAtMiss) {
00263     ResourceMark rm;
00264     key->print();
00265   }
00266 
00267   if (compile && Sweeper::is_running()) {
00268     // Do not compile if this is called from the sweeper.
00269     // The system will crash and burn since a compile does a process switch
00270     // Lars Bak, 6-19-96 (I don't like overwriting parameters either!)
00271     compile = false;
00272   }
00273 
00274   // Check Inlining database
00275   if (UseInliningDatabase && UseInliningDatabaseEagerly && compile) {
00276     ResourceMark rm;
00277     RScope* rs = InliningDatabase::lookup_and_remove(key);
00278     if (rs) {
00279       if (TraceInliningDatabase) {
00280         std->print("ID compile: ");
00281         key->print();
00282         std->cr();
00283       }
00284 
00285       // Remove old nmethod if present
00286       nmethod* old_nm = Universe::code->lookup(rs->key());
00287       VM_OptimizeRScope op(rs);
00288       VMProcess::execute(&op);
00289       if (old_nm) old_nm->makeZombie(true);
00290 
00291       if (op.result()) {
00292         LookupResult result(op.result());
00293         return result;
00294       }
00295     }
00296   }
00297  
00298   // Check the code table
00299   nmethod* nm = Universe::code->lookup(key);
00300   if (nm) {
00301     LookupResult result(nm);
00302     return nm;
00303   }
00304 
00305   // Last resort is searching class for the method
00306   methodOop method = key->is_normal_type() 
00307                    ? key->klass()->klass_part()->lookup(key->selector())
00308                    : key->method();
00309 
00310   if (!method) {
00311     LookupResult result;
00312     return result;
00313   }
00314 
00315   if (CompiledCodeOnly && compile) {
00316     nm = compile_method(key, method);
00317     if (nm) {
00318       LookupResult result(nm);
00319       return nm;
00320     }
00321   }
00322 
00323   LookupResult result(method);
00324   return method;
00325 }
00326 
00327 methodOop lookupCache::compile_time_normal_lookup(klassOop receiver_klass, symbolOop selector) {
00328   LookupKey key(receiver_klass, selector);
00329   LookupResult res = lookup(&key, false);
00330   return res.method_or_null();
00331 }
00332 
00333 methodOop lookupCache::compile_time_super_lookup(klassOop receiver_klass, symbolOop selector) {
00334   methodOop method = method_lookup(receiver_klass->klass_part()->superKlass(), selector);
00335   if (method == NULL) return NULL;
00336   LookupKey key(receiver_klass, method);
00337   LookupResult res = lookup(&key, false);
00338   return res.method_or_null();
00339 }
00340 
00341 methodOop lookupCache::method_lookup(klassOop receiver_klass, symbolOop selector) {
00342   LookupKey key(receiver_klass, selector);
00343   methodOop method = key.klass()->klass_part()->lookup(key.selector());
00344   return method;
00345 }
00346 
00347 nmethod* lookupCache::compile_method(LookupKey *key, methodOop method) {
00348   if (!DeltaProcess::active()->in_vm_operation()) {
00349     VM_OptimizeMethod op(key, method);
00350     VMProcess::execute(&op);
00351     assert(op.result(),                 "nmethod must be there");
00352     assert(Universe::code->lookup(key), "nmethod must be there");
00353     return op.result();
00354   }
00355   return NULL;
00356 }
00357 
00358 // Lookup support for inline cache
00359 inline LookupResult lookupCache::ic_lookup(klassOop receiver_klass, oop selector_or_method) {
00360   LookupKey key(receiver_klass, selector_or_method);
00361   return lookup(&key, true);
00362 }
00363 
00364 LookupResult lookupCache::ic_normal_lookup(klassOop receiver_klass, symbolOop selector) {
00365   return lookupCache::ic_lookup(receiver_klass, selector);
00366 }
00367 
00368 LookupResult lookupCache::ic_super_lookup(klassOop receiver_klass, klassOop superKlass, symbolOop selector) {
00369   methodOop method = method_lookup(superKlass, selector);
00370   return ic_lookup(receiver_klass, method);
00371 }
00372 
00373 LookupResult interpreter_normal_lookup(klassOop receiver_klass, symbolOop selector) {
00374   LookupKey key(receiver_klass, selector);
00375   return lookupCache::lookup(&key, true);
00376 }
00377 
00378 LookupResult interpreter_super_lookup(symbolOop selector) {
00379   // super lookup for interpreter: given the receiver and h-code pointer of the current
00380   // method (which is performing the super send), find the superclass and then the method
00381   // Note: the interpreter doesn't store the superclass in the InlineCache in order to
00382   // unify the format of inline caches for normal and super sends (the differences lead to
00383   // several bugs)
00384 
00385   // On request from Robert (6/19/95) this routine must return a methodOop since
00386   // the interpreter's super send cannot cope with compiled code.
00387   // This is a temporary restriction and should be removed soon (please bug Robert)
00388   //
00389   // This should not be a problem anymore (gri 1/24/96), clean up the lookup cache
00390   // interface.
00391   ResourceMark rm;
00392   frame f = DeltaProcess::active()->last_frame();
00393   assert(f.is_interpreted_frame(), "must be interpreter frame");
00394 
00395   // remember to take the home of the executing method.
00396   methodOop sendingMethod = f.method()->home();
00397 
00398   klassOop sendingMethodHolder = f.receiver()->blueprint()->lookup_method_holder_for(sendingMethod);
00399   // NB: lookup for current method can fail if the method was deleted while still on the stack
00400 
00401   if (sendingMethodHolder == NULL) {
00402     fatal("sending method holder cannot be found; this might be caused by a programming change -- fix this");
00403   }
00404   klassOop superKlass = sendingMethodHolder->klass_part()->superKlass();
00405   methodOop superMethod = lookupCache::method_lookup(superKlass, selector);
00406 
00407   LookupResult result(superMethod);
00408   return result;
00409 }
00410 
00411 LookupResult lookupCache::lookup(LookupKey* key) {
00412   return ic_lookup(key->klass(), key->selector_or_method());
00413 }
00414 
00415 oop lookupCache::normal_lookup(klassOop receiver_klass, symbolOop selector) {
00416   VerifyNoScavenge vna;
00417   LookupKey key(receiver_klass, selector);
00418   LookupResult result = ic_normal_lookup(receiver_klass, selector);
00419   assert(result.value() != NULL, "message not understood not implemented yet for compiled code");
00420   return result.value();
00421 }
00422 
00423 static void print_counter(char* title, int counter, int total) {
00424   lprintf("%20s: %3.1f%% (%d)\n",
00425           title,
00426           total == 0 ? 0.0 : 100.0 * (double) counter / (double) total,
00427           counter);
00428 }
00429 
00430 void lookupCache::clear_statistics() {
00431   number_of_primary_hits    = 0;
00432   number_of_secondary_hits  = 0;
00433   number_of_misses          = 0;
00434 }
00435 
00436 void lookupCache::print_statistics() {
00437   int total = number_of_primary_hits
00438             + number_of_secondary_hits
00439             + number_of_misses;
00440   lprintf("Lookup Cache: size(%d, %d)\n",
00441           primary_cache_size, secondary_cache_size);
00442   print_counter("Primary Hit Ratio",   number_of_primary_hits,   total);
00443   print_counter("Secondary Hit Ratio", number_of_secondary_hits, total);
00444   print_counter("Miss Ratio",          number_of_misses,         total);
00445 }

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