00001 
00002 
00003 
00004 
00005 
00006 
00007 
00008 
00009 
00010 
00011 
00012 
00013 
00014 
00015 
00016 
00017 
00018 
00019 
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   
00138   for (index = 0; index < primary_cache_size; index ++)
00139     primary[index].clear();
00140   
00141   for (index = 0; index < secondary_cache_size; index ++)
00142     secondary[index].clear();
00143   
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   
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     
00157     
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     
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     
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   
00208   
00209   
00210   
00211   
00212   
00213   
00214   assert(key->verify(), "Lookupkey: verify failed");
00215 
00216   
00217   int primary_index = hash_value(key) % primary_cache_size;
00218 
00219   if (primary[primary_index].key.equal(key)) {
00220 #ifdef DEBUG
00221     
00222     number_of_primary_hits++;
00223 #endif
00224     return primary[primary_index].result;
00225   }
00226 
00227   
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     
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   
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       
00247       
00248       assert(theCompiler, "should only happen during compilation");   
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   
00262   if (TraceLookupAtMiss) {
00263     ResourceMark rm;
00264     key->print();
00265   }
00266 
00267   if (compile && Sweeper::is_running()) {
00268     
00269     
00270     
00271     compile = false;
00272   }
00273 
00274   
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       
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   
00299   nmethod* nm = Universe::code->lookup(key);
00300   if (nm) {
00301     LookupResult result(nm);
00302     return nm;
00303   }
00304 
00305   
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 
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   
00380   
00381   
00382   
00383   
00384 
00385   
00386   
00387   
00388   
00389   
00390   
00391   ResourceMark rm;
00392   frame f = DeltaProcess::active()->last_frame();
00393   assert(f.is_interpreted_frame(), "must be interpreter frame");
00394 
00395   
00396   methodOop sendingMethod = f.method()->home();
00397 
00398   klassOop sendingMethodHolder = f.receiver()->blueprint()->lookup_method_holder_for(sendingMethod);
00399   
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 }