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 }