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 
00026 # include "incls/_inliningdb.cpp.incl"
00027 
00028 char* InliningDatabase::_directory = NULL;
00029 
00030 char* InliningDatabase::default_directory() {
00031   return ".\\Inlining";
00032 }
00033 
00034 void InliningDatabase::set_directory(char* dir) {
00035   _directory = dir;
00036 }
00037 
00038 char* InliningDatabase::directory() {
00039   return _directory == NULL 
00040        ? default_directory() 
00041        : _directory;
00042 }
00043 
00044 # include <ctype.h>
00045 
00046 const char  quote = '_';
00047 const char* quote_string = "_\\/:; *?~|><,+=@%&!-";
00048 
00049 char* InliningDatabase::mangle_name(char *str) {
00050   char* result = NEW_RESOURCE_ARRAY(char, 100);
00051   int i = 0;
00052   int j = 0;
00053   while (str[i] != '\0') {
00054     int c = str[i];
00055     if (strchr(quote_string,c)) {
00056       result[j++] = quote;
00057       result[j++] = get_unsigned_bitfield(c, 6, 3) + '0';
00058       result[j++] = get_unsigned_bitfield(c, 3, 3) + '0';
00059       result[j++] = get_unsigned_bitfield(c, 0, 3) + '0';
00060     } else if (isupper(c)) {
00061       result[j++] = quote;
00062       result[j++] = c + ('a' - 'A');
00063     } else {
00064       result[j++] = c;
00065     } 
00066     i++;
00067   }
00068   result[j++] = '\0';
00069   return result;
00070 }
00071 
00072 char* InliningDatabase::unmangle_name(char* str) {
00073   char* result = NEW_RESOURCE_ARRAY(char, 100);
00074   int i = 0;
00075   int j = 0;
00076   while (str[i] != '\0') {
00077     int c = str[i];
00078     if (c == quote) {
00079       i++;
00080       assert(str[i] != '\0', "we cannot end with a quote");
00081       c = str[i];
00082       if (isdigit(c)) {
00083         int value = (c - '0') << 6;
00084         i++;
00085         assert(str[i] != '\0', "we cannot end with a quote");
00086         c = str[i];
00087         value += (c - '0') << 3;
00088         i++;
00089         assert(str[i] != '\0', "we cannot end with a quote");
00090         c = str[i];
00091         value += (c - '0');
00092         result[j++] = value;
00093       } else {
00094         result[j++] = c - ('a' - 'A');
00095       }
00096     } else {
00097       result[j++] = c;
00098     }
00099     i++;
00100   }
00101   result[j++] = '\0';
00102   return result;
00103 }
00104 
00105 char* InliningDatabase::selector_string(symbolOop selector) {
00106   stringStream st(100);
00107   selector->print_symbol_on(&st);
00108   return st.as_string();
00109 }
00110 
00111 char* InliningDatabase::method_string(methodOop method) {
00112   stringStream st(100);
00113   method->print_inlining_database_on(&st);
00114   return st.as_string();
00115 }
00116 
00117 char* InliningDatabase::klass_string(klassOop klass) {
00118   stringStream st(100);
00119   klass->klass_part()->print_name_on(&st);
00120   return st.as_string();
00121 }
00122 
00123 bool check_directory(char* dir_name) {
00124   return os::check_directory(dir_name);
00125 }
00126 
00127 char* InliningDatabase::compute_file_name(LookupKey* outer, LookupKey* inner, bool create_directories) {
00128   char* name = NEW_RESOURCE_ARRAY(char, 1024);
00129 
00130   
00131   char* outer_klass_name    = mangle_name(klass_string(outer->klass()));
00132   char* outer_selector_name = mangle_name(selector_string(outer->selector()));
00133 
00134   if (create_directories) {
00135     if (!check_directory(directory())) return NULL;
00136   }
00137 
00138   strcpy(name, directory());
00139   strcat(name, "\\");
00140   strcat(name, outer_klass_name);
00141 
00142   if (create_directories) {
00143     if (!check_directory(name)) return NULL;
00144   }
00145 
00146   strcat(name, "\\");
00147   strcat(name, outer_selector_name);
00148 
00149   if (inner) {
00150     
00151     char* inner_klass_name  = mangle_name(klass_string(inner->klass()));
00152     char* inner_method_name = mangle_name(method_string(inner->method()));
00153 
00154     if (create_directories) {
00155       if (!check_directory(name)) return NULL;
00156     }
00157     strcat(name, "\\");
00158     strcat(name, inner_klass_name);
00159 
00160     if (create_directories) {
00161       if (!check_directory(name)) return NULL;
00162     }
00163     strcat(name, "\\");
00164     strcat(name, inner_method_name);
00165   }
00166   strcat(name, ".txt");
00167   return name;
00168 }
00169 
00170 bool InliningDatabase::file_out(nmethod* nm, outputStream* index_st) {
00171   ResourceMark rm;
00172 
00173   LookupKey* outer_key = NULL;
00174   LookupKey* inner_key = NULL;
00175 
00176   if (nm->is_block()) {
00177     nmethod* outer = nm->outermost();
00178     if (outer->isZombie()) return false;
00179     outer_key = &outer->key;
00180     inner_key = &nm->key;
00181   } else {
00182     outer_key = &nm->key;
00183     inner_key = NULL;
00184   }
00185 
00186 
00187   
00188   RScope* rs = RNonDummyScope::constructRScopes(nm, false);
00189   
00190   if (rs->inlining_database_size() < InliningDatabasePruningLimit) return false;
00191   
00192 
00193   add_lookup_entry(outer_key, inner_key);
00194 
00195   if (index_st) {
00196     if (inner_key) {
00197       inner_key->print_inlining_database_on(index_st);
00198       index_st->cr();
00199     }
00200     outer_key->print_inlining_database_on(index_st);
00201     index_st->cr();
00202   }
00203 
00204   char* file_name = compute_file_name(outer_key, inner_key, true);
00205   if (file_name == NULL) return false;
00206 
00207   if (TraceInliningDatabase) {
00208     std->print_cr("Dumping %s", file_name);
00209   }
00210   fileStream out(file_name);
00211   if (out.is_open()) {
00212     GrowableArray<PcDesc*>* uncommon = nm->uncommonBranchList();
00213     
00214     rs->print_inlining_database_on(&out, uncommon);
00215     return true;
00216   }
00217   return false;
00218 }
00219 
00220 char* find_type(char* line, bool* is_super, bool* is_block) {
00221   
00222   char* sub = strstr(line+1, "::");
00223   if (sub) {
00224     *is_super = false;
00225     *is_block = false;
00226     return sub;
00227   }
00228 
00229   sub = strstr(line+1, "^^");
00230   if (sub) {
00231     *is_super = true;
00232     *is_block = false;
00233     return sub;
00234   }
00235 
00236   sub = strstr(line+1, "->");
00237   if (sub) {
00238     *is_super = false;
00239     *is_block = true;
00240     return sub;
00241   }
00242 
00243   return NULL;
00244 }
00245 
00246 
00247 bool scan_key(RScope* sender, char* line, klassOop* receiver_klass, methodOop* method) {
00248   bool is_super;
00249   bool is_block;
00250 
00251   char* sub = find_type(line, &is_super, &is_block);
00252   if (sub == NULL)
00253     return false;
00254 
00255   *sub = '\0';
00256 
00257   char* class_name = line;
00258   char* method_id  = sub + 2;
00259   
00260   bool class_side = false;
00261   char* class_start = strstr(class_name, " class");
00262   if (class_start != NULL) {
00263     *class_start = '\0';
00264     class_side = true;
00265   }
00266 
00267   klassOop rec = klassOop(Universe::find_global(class_name, true));
00268   if (rec == NULL || !rec->is_klass()) return false;
00269   if (class_side) rec = rec->klass();
00270   *receiver_klass = rec;
00271  
00272   GrowableArray<int>* bcis = new GrowableArray<int>(10);
00273 
00274   char* bcis_string = strstr(method_id, " ");
00275 
00276   if (bcis_string) {
00277     *bcis_string++ = '\0';
00278     while (*bcis_string != '\0') {
00279       int index;
00280       int bci;
00281       if (sscanf(bcis_string, "%d%n", &bci, &index) != 1) return 0;
00282       bcis->push(bci);
00283       bcis_string += index;
00284       if (*bcis_string == ' ') 
00285         bcis_string++;
00286     }
00287   }
00288   symbolOop selector = oopFactory::new_symbol(method_id);
00289 
00290 
00291   if (is_super) {
00292     assert(sender, "sender must be present");
00293     klassOop method_holder = sender->receiverKlass()->klass_part()->lookup_method_holder_for(sender->method());
00294     
00295     if (method_holder) {
00296       methodOop met = method_holder->klass_part()->superKlass()->klass_part()->lookup(selector);
00297       if (met) {
00298         *method = met;
00299         return true;
00300       }
00301     }
00302     return false;
00303   }
00304 
00305   methodOop met = rec->klass_part()->lookup(selector);
00306   if (met == NULL) return false;
00307 
00308   for (int index = 0; index < bcis->length(); index++) {
00309     int bci = bcis->at(index);
00310     met = met->block_method_at(bci);
00311     if (met == NULL) return false;
00312   }
00313 
00314   *method = met;
00315   return true;
00316 }
00317 
00318 
00319 
00320 int scan_prefix(char* line, int* bci, int* level) {
00321   int index;
00322 
00323   int l = 0;
00324   while (*line == ' ') {
00325     line++;
00326     l++;
00327   }
00328   if (sscanf(line, "%d %n", bci, &index) != 1) return 0;
00329   *level = l / 2;
00330   return l + index;
00331 }
00332 
00333 
00334 bool scan_uncommon(char* line) {
00335   return strcmp(line, "uncommon") == 0;
00336 }
00337 
00338 static bool create_rscope(char* line, GrowableArray<RDatabaseScope*>* stack) {
00339   
00340   int len = strlen(line);
00341   if (len > 1 && line[len-1] == '\n') 
00342     line[len-1] = '\0';
00343 
00344   int       bci            = 0;
00345   int       level          = 0;
00346   methodOop method         = NULL;
00347   klassOop  receiver_klass = NULL;
00348 
00349   RScope* result = NULL;
00350 
00351   if (stack->isEmpty()) {
00352     
00353     if (!scan_key(NULL, line, &receiver_klass, &method)) return false;
00354     stack->push(new RDatabaseScope(NULL, -1, receiver_klass, method, 0));
00355   } else {
00356     
00357     int index = scan_prefix(line, &bci, &level);
00358     if (index <= 0) return false;
00359 
00360     while (stack->length() > level) 
00361       stack->pop();
00362     RDatabaseScope* sender = stack->top();
00363     if (scan_uncommon(&line[index])) {
00364       sender->mark_as_uncommon(bci);
00365     } else if (scan_key(sender, &line[index], &receiver_klass, &method)) {
00366       stack->push(new RDatabaseScope(sender, bci, receiver_klass, method, level));
00367     } else {
00368       return false;
00369     }
00370   }
00371   return true;
00372 }
00373 
00374 outputStream* InliningDatabase::index_st = NULL;
00375 
00376 int      InliningDatabase::local_number_of_nmethods_written = 0;
00377 klassOop InliningDatabase::local_klass                      = NULL;
00378 
00379 void InliningDatabase::local_file_out_all(nmethod* nm) {
00380   if (nm->isZombie()) return;
00381   if (file_out(nm)) {
00382     local_number_of_nmethods_written++;
00383   }
00384 }
00385 
00386 char* InliningDatabase::index_file_name() {
00387   char* name = NEW_RESOURCE_ARRAY(char, 1024);
00388   if (!check_directory(directory())) return NULL;
00389   strcpy(name, directory());
00390   strcat(name, "\\index.txt");
00391   return name;
00392 }
00393 
00394 bool scan_key(char* line, LookupKey* key) {
00395   int len = strlen(line);
00396   if (len > 1 && line[len-1] == '\n') 
00397     line[len-1] = '\0';
00398 
00399   bool is_super;
00400   bool is_block;
00401 
00402   char* sub = find_type(line, &is_super, &is_block);
00403   if (sub == NULL)
00404     return false;
00405 
00406   *sub = '\0';
00407 
00408   char* class_name = line;
00409   char* method_id  = sub + 2;
00410   
00411   bool class_side = false;
00412   char* class_start = strstr(class_name, " class");
00413   if (class_start != NULL) {
00414     *class_start = '\0';
00415     class_side = true;
00416   }
00417 
00418   klassOop rec = klassOop(Universe::find_global(class_name, true));
00419   if (rec == NULL || !rec->is_klass()) return false;
00420   if (class_side) rec = rec->klass();
00421 
00422 
00423   GrowableArray<int>* bcis = new GrowableArray<int>(10);
00424 
00425   char* bcis_string = strstr(method_id, " ");
00426 
00427   if (bcis_string) {
00428     *bcis_string++ = '\0';
00429     while (*bcis_string != '\0') {
00430       int index;
00431       int bci;
00432       if (sscanf(bcis_string, "%d%n", &bci, &index) != 1) return 0;
00433       bcis->push(bci);
00434       bcis_string += index;
00435       if (*bcis_string == ' ') 
00436         bcis_string++;
00437     }
00438   }
00439   symbolOop selector = oopFactory::new_symbol(method_id);
00440  
00441   if (is_block) {
00442     methodOop met = rec->klass_part()->lookup(selector);
00443     if (met == NULL) return false;
00444     for (int index = 0; index < bcis->length(); index++) {
00445       int bci = bcis->at(index);
00446       met = met->block_method_at(bci);
00447       if (met == NULL) return false;
00448     }
00449     key->initialize(rec, met);
00450   } else {
00451     key->initialize(rec, selector);
00452   }
00453   return true;
00454 }
00455 
00456 
00457 void InliningDatabase::load_index_file() {
00458   ResourceMark rm;
00459   TraceTime t("Loading index for inlining database");
00460 
00461   
00462   FILE* stream = fopen(index_file_name(), "rt");
00463   if (!stream) return;
00464 
00465   char line[1000];
00466 
00467   LookupKey first;
00468   LookupKey second;
00469 
00470   while (fgets( line, 1000, stream)) {
00471     if (scan_key(line, &first)) {
00472       if (first.is_block_type()) {
00473         if (fgets( line, 1000, stream)) {
00474           if (scan_key(line, &second)) {
00475             
00476             
00477             
00478             
00479             
00480             add_lookup_entry(&second, &first);
00481           } else {
00482             std->print_cr("Index file parsing block failed for %s", line);
00483           }
00484         }
00485       } else {
00486         
00487         
00488         
00489         add_lookup_entry(&first);
00490       }
00491     } else {
00492       std->print_cr("Index file parsing failed for %s", line);
00493     }
00494   }
00495   fclose(stream);
00496 }
00497 
00498 void InliningDatabase::local_file_out_klass(nmethod* nm) {
00499   if (nm->isZombie()) return;
00500   if (nm->receiver_klass() == local_klass) {
00501     if (file_out(nm)) {
00502       local_number_of_nmethods_written++;
00503     }
00504   }
00505 }
00506 
00507 int InliningDatabase::file_out(klassOop klass) {
00508   local_number_of_nmethods_written = 0;
00509   local_klass                      = klass;
00510   Universe::code->nmethods_do(local_file_out_klass);
00511   return local_number_of_nmethods_written;
00512 }
00513 
00514 RScope* InliningDatabase::file_in_from(FILE* stream) {
00515   GrowableArray<RDatabaseScope*>* stack = new GrowableArray<RDatabaseScope*>(10);
00516 
00517   char line[1000];
00518 
00519   
00520   if (!fgets( line, 1000, stream)) return NULL;
00521   if (!create_rscope(line, stack)) return NULL;
00522 
00523   
00524   while (fgets( line, 1000, stream)) {
00525     if (!create_rscope(line, stack)) return NULL;
00526   }
00527 
00528   
00529   return stack->at(0);
00530 }
00531 
00532 RScope* InliningDatabase::file_in(char* file_path) {
00533   
00534   FILE* stream = fopen(file_path, "rt");
00535 
00536   if (!stream) {
00537     return NULL;
00538   }
00539   RScope* result = file_in_from(stream);
00540   fclose(stream);
00541   return result;
00542 }
00543 
00544 RScope* InliningDatabase::file_in(LookupKey* outer, LookupKey* inner) {
00545   char* file_name = compute_file_name(outer, inner, false);
00546   if (file_name == NULL) {
00547     if (TraceInliningDatabase) {
00548       std->print("Failed opening file for ");
00549       if (inner) {
00550         inner->print();
00551         std->print(" ");
00552       }
00553       outer->print();
00554       std->cr();
00555     }
00556     return NULL;
00557   }
00558   RScope* result = file_in(file_name);
00559   
00560   if (TraceInliningDatabase && result == NULL) {
00561     std->print("Failed parsing file for ");
00562     if (inner) {
00563       inner->print();
00564       std->print(" ");
00565     }
00566     outer->print();
00567     std->cr();
00568   }
00569  
00570   return result;
00571 }
00572 
00573 class InliningDatabaseKey {
00574  public:
00575   LookupKey outer;
00576   LookupKey inner;
00577 
00578   bool is_empty()   const { return outer.selector_or_method() == smiOop_zero; }
00579   bool is_filled()  const { return smiOop(outer.klass())      != smiOop_zero; }
00580   bool is_deleted() const { return outer.selector_or_method() == smiOop_one;  }
00581 
00582   bool is_inner()   const { return inner.selector_or_method() != smiOop_zero; }
00583   bool is_outer()   const { return !is_inner(); }
00584 
00585   void clear() {
00586     outer.initialize(NULL, smiOop_zero);
00587     inner.initialize(NULL, smiOop_zero);
00588   }
00589 
00590   void set_deleted() {
00591     outer.initialize(NULL, smiOop_one);
00592   }
00593 
00594   bool equal(LookupKey* o, LookupKey* i) {
00595     return outer.equal(o) && (is_outer() || inner.equal(i));
00596   }
00597 
00598   void oops_do(void f(oop*)) {
00599     if (is_filled()) {
00600      outer.oops_do(f);
00601      if(is_inner()) 
00602        inner.oops_do(f);
00603     }
00604   }
00605 };
00606 
00607 InliningDatabaseKey*   InliningDatabase::table = NULL;
00608 unsigned int InliningDatabase::table_size      = 0;
00609 unsigned int InliningDatabase::table_size_mask = 0;
00610 unsigned int InliningDatabase::table_no        = 0;
00611 
00612 inline unsigned int InliningDatabase::index_for(LookupKey* outer, LookupKey* inner) {
00613   unsigned int hash = (unsigned int) outer->klass()->identity_hash() ^ (unsigned int) outer->selector()->identity_hash();
00614   if (inner) {
00615     hash ^= (unsigned int) inner->klass()->identity_hash() ^ (unsigned int) inner->selector()->identity_hash();
00616   }
00617   return hash & table_size_mask;
00618 }
00619 
00620 inline unsigned int InliningDatabase::next_index(unsigned int index) {
00621   return (index + 1) & table_size_mask;
00622 }
00623 
00624 void InliningDatabase::reset_lookup_table() {
00625   if (table) {
00626     FreeHeap(table);
00627     table           = NULL;
00628     table_size      = 0;
00629     table_size_mask = 0;
00630     table_no        = 0;
00631   }
00632 }
00633 
00634 RScope* InliningDatabase::select_and_remove(bool* end_of_table) {
00635   if (table_no == 0) return NULL;  
00636 
00637   for (unsigned int index = 0 ; index < table_size; index++) {
00638     if (table[index].is_filled() && table[index].is_outer()) {
00639       RScope* result = file_in(&table[index].outer);
00640       table[index].set_deleted();
00641       table_no--;
00642       *end_of_table = false;
00643       return result;
00644     }
00645   }
00646   *end_of_table = true;
00647   return NULL;
00648 }
00649 
00650 void InliningDatabase::allocate_table(unsigned int size) {
00651   if (TraceInliningDatabase) {
00652     std->print_cr("InliningDatabase::allocate_table(%d)", size);
00653   }
00654   table_size      = size;
00655   table_size_mask = size - 1;
00656   table_no        = 0;
00657   table           = NEW_C_HEAP_ARRAY(InliningDatabaseKey, table_size);
00658   
00659   for (unsigned int index = 0 ; index < table_size; index++) {
00660     table[index].clear();
00661   }
00662 }
00663 
00664 void InliningDatabase::add_lookup_entry(LookupKey* outer, LookupKey* inner) {
00665   if (table_no * 2 >= table_size) {
00666     if (table == NULL) {
00667       allocate_table(4 * K);
00668     } else {
00669       
00670       InliningDatabaseKey* old_table      = table;
00671       unsigned int         old_table_size = table_size;
00672       allocate_table(table_size * 2);
00673       for (unsigned int index = 0 ; index < old_table_size; index++) {
00674         if (old_table[index].is_filled())
00675           add_lookup_entry(&old_table[index].outer, &old_table[index].inner);
00676       }
00677       FreeHeap(old_table);
00678     }
00679   }
00680   assert(table_no * 2 < table_size, "just checking density");
00681   
00682   unsigned int index = index_for(outer, inner);
00683 
00684   while (table[index].is_filled()) {
00685     if (table[index].equal(outer, inner)) return;
00686     index = next_index(index);
00687   }
00688 
00689   table[index].outer = *outer;
00690   if (inner) {
00691     table[index].inner = *inner;
00692   }
00693   table_no++;
00694 
00695   if (TraceInliningDatabase) {
00696     std->print_cr("InliningDatabase::add_lookup_entry @ %d", index);
00697     if (inner) {
00698       inner->print();
00699       std->print(" ");
00700     }
00701     outer->print();
00702     std->cr();
00703   }
00704 }
00705 
00706 bool InliningDatabase::lookup(LookupKey* outer, LookupKey* inner) {
00707   if (table_no == 0) return NULL;  
00708 
00709   unsigned int index = index_for(outer, inner);
00710   if (!table[index].is_filled()) return false; 
00711   while (!table[index].equal(outer, inner)) {
00712     index = next_index(index);
00713     if (table[index].is_empty()) return false;
00714   }
00715   return true;
00716 }
00717 
00718 
00719 RScope* InliningDatabase::lookup_and_remove(LookupKey* outer, LookupKey* inner) {
00720   if (table_no == 0) return NULL;  
00721 
00722   unsigned int index = index_for(outer, inner);
00723   if (!table[index].is_filled()) return NULL; 
00724   while (!table[index].equal(outer, inner)) {
00725     index = next_index(index);
00726     if (table[index].is_empty()) return NULL;
00727   }
00728   table[index].set_deleted();
00729   table_no--;
00730   return file_in(outer, inner);
00731 }
00732 
00733 void InliningDatabase::oops_do(void f(oop*)) {
00734   for (unsigned int index = 0; index < table_size; index++) {
00735     table[index].oops_do(f);
00736   }
00737 }
00738 
00739 int InliningDatabase::file_out_all() {
00740   ResourceMark rm;
00741 
00742   
00743 
00744   
00745   reset_lookup_table();
00746 
00747   
00748   load_index_file();
00749 
00750   local_number_of_nmethods_written = 0;
00751   Universe::code->nmethods_do(local_file_out_all);
00752 
00753   fileStream index(index_file_name());
00754 
00755   
00756   for (unsigned int i = 0 ; i < table_size; i++) {
00757     if (table[i].is_filled()) {
00758       if (table[i].is_inner()) {
00759         table[i].inner.print_inlining_database_on(&index);
00760         index.cr();
00761       }
00762       table[i].outer.print_inlining_database_on(&index);
00763       index.cr();
00764     }
00765   }
00766 
00767   
00768   reset_lookup_table();
00769 
00770   return local_number_of_nmethods_written;
00771 }