--- old/src/share/vm/ci/ciReplay.cpp 2013-12-27 17:10:19.000000000 -0800 +++ new/src/share/vm/ci/ciReplay.cpp 2013-12-27 17:10:19.000000000 -0800 @@ -24,6 +24,8 @@ #include "precompiled.hpp" #include "ci/ciMethodData.hpp" #include "ci/ciReplay.hpp" +#include "ci/ciSymbol.hpp" +#include "ci/ciKlass.hpp" #include "ci/ciUtilities.hpp" #include "compiler/compileBroker.hpp" #include "memory/allocation.inline.hpp" @@ -62,6 +64,14 @@ int backedge_counter; } ciMethodRecord; +typedef struct _ciInlineRecord { + const char* klass; + const char* method; + const char* signature; + int inline_depth; + int bci; +} ciInlineRecord; + class CompileReplay; static CompileReplay* replay_state; @@ -74,6 +84,9 @@ GrowableArray ci_method_records; GrowableArray ci_method_data_records; + // Use pointer because we may need to retirn inline records + // without destroying. + GrowableArray* ci_inline_records; const char* _error_message; @@ -273,7 +286,12 @@ const char* str = parse_escaped_string(); Symbol* klass_name = SymbolTable::lookup(str, (int)strlen(str), CHECK_NULL); if (klass_name != NULL) { - Klass* k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD); + Klass* k = NULL; + if (_iklass != NULL) { + k = (Klass*)_iklass->find_klass(ciSymbol::make(klass_name->as_C_string()))->constant_encoding(); + } else { + k = SystemDictionary::resolve_or_fail(klass_name, loader, protection_domain, true, THREAD); + } if (HAS_PENDING_EXCEPTION) { oop throwable = PENDING_EXCEPTION; java_lang_Throwable::print(throwable, tty); @@ -307,6 +325,11 @@ // Process each line of the replay file executing each command until // the file ends. void process(TRAPS) { + _imethod = NULL; + _iklass = NULL; + _entry_bci = 0; + _comp_level = 0; + line_no = 1; int pos = 0; int c = getc(stream); @@ -396,7 +419,62 @@ return true; } - // compile + ciKlass* _iklass; + Method* _imethod; + int _entry_bci; + int _comp_level; + + // compile inline ... + void* process_inline(ciMethod* imethod, Method* m, int entry_bci, int comp_level, TRAPS) { + _imethod = m; + _iklass = imethod->holder(); + _entry_bci = entry_bci; + _comp_level = comp_level; + line_no = 1; + int pos = 0; + int c = getc(stream); + while(c != EOF) { + if (pos + 1 >= buffer_length) { + int newl = buffer_length * 2; + char* newb = NEW_RESOURCE_ARRAY(char, newl); + memcpy(newb, buffer, pos); + buffer = newb; + buffer_length = newl; + } + if (c == '\n') { + // null terminate it, reset the pointer and process the line + buffer[pos] = '\0'; + buffer_end = pos++; + bufptr = buffer; + { + char* cmd = parse_string(); + if (cmd == NULL || strcmp("compile", cmd) != 0) { + return NULL; + } + process_compile(CHECK_NULL); + if (ci_inline_records != NULL && ci_inline_records->length() > 0) { + return ci_inline_records; + } + } + if (had_error()) { + tty->print_cr("Error while parsing line %d: %s\n", line_no, _error_message); + tty->print_cr("%s", buffer); + return NULL; + } + pos = 0; + buffer_end = 0; + line_no++; + } else if (c == '\r') { + // skip LF + } else { + buffer[pos++] = c; + } + c = getc(stream); + } + return NULL; + } + + // compile inline ... void process_compile(TRAPS) { Method* method = parse_method(CHECK); if (had_error()) return; @@ -410,6 +488,43 @@ if (!is_valid_comp_level(comp_level)) { return; } + if (_imethod != NULL) { + // Replay Inlinig + if (entry_bci != _entry_bci || comp_level != _comp_level) { + return; + } + const char* iklass_name = _imethod->method_holder()->name()->as_utf8(); + const char* imethod_name = _imethod->name()->as_utf8(); + const char* isignature = _imethod->signature()->as_utf8(); + const char* klass_name = method->method_holder()->name()->as_utf8(); + const char* method_name = method->name()->as_utf8(); + const char* signature = method->signature()->as_utf8(); + if (strcmp(iklass_name, klass_name) != 0 || + strcmp(imethod_name, method_name) != 0 || + strcmp(isignature, signature) != 0) { + return; + } + } + int inline_count = 0; + if (parse_tag_and_count("inline", inline_count)) { + // Record inlining data + ci_inline_records = new GrowableArray(); + for (int i = 0; i < inline_count; i++) { + int depth = parse_int("inline_depth"); + int bci = parse_int("inline_bci"); + if (had_error()) { + break; + } + Method* inl_method = parse_method(CHECK); + if (had_error()) { + break; + } + new_ciInlineRecord(inl_method, bci, depth); + } + } + if (_imethod != NULL) { + return; // Replay Inlining + } Klass* k = method->method_holder(); ((InstanceKlass*)k)->initialize(THREAD); if (HAS_PENDING_EXCEPTION) { @@ -570,6 +685,9 @@ case JVM_CONSTANT_Utf8: case JVM_CONSTANT_Integer: case JVM_CONSTANT_Float: + case JVM_CONSTANT_MethodHandle: + case JVM_CONSTANT_MethodType: + case JVM_CONSTANT_InvokeDynamic: if (tag != cp->tag_at(i).value()) { report_error("tag mismatch: wrong class files?"); return; @@ -778,6 +896,58 @@ return NULL; } + // Create and initialize a record for a ciInlineRecord + ciInlineRecord* new_ciInlineRecord(Method* method, int bci, int depth) { + ciInlineRecord* rec = NEW_RESOURCE_OBJ(ciInlineRecord); + rec->klass = method->method_holder()->name()->as_utf8(); + rec->method = method->name()->as_utf8(); + rec->signature = method->signature()->as_utf8(); + rec->bci = bci; + rec->inline_depth = depth; + ci_inline_records->append(rec); + return rec; + } + + // Lookup inlining data for a ciMethod + ciInlineRecord* find_ciInlineRecord(Method* method, int bci, int inline_depth) { + if (ci_inline_records != NULL) { + const char* klass_name = method->method_holder()->name()->as_utf8(); + const char* method_name = method->name()->as_utf8(); + const char* signature = method->signature()->as_utf8(); + for (int i = 0; i < ci_inline_records->length(); i++) { + ciInlineRecord* rec = ci_inline_records->at(i); + if ((rec->bci == bci) && + (rec->inline_depth == inline_depth) && + (strcmp(rec->klass, klass_name) == 0) && + (strcmp(rec->method, method_name) == 0) && + (strcmp(rec->signature, signature) == 0)) { + return rec; + } + } + } + return NULL; + } + + static ciInlineRecord* find_ciInlineRecord(GrowableArray* records, + Method* method, int bci, int inline_depth) { + if (records != NULL) { + const char* klass_name = method->method_holder()->name()->as_utf8(); + const char* method_name = method->name()->as_utf8(); + const char* signature = method->signature()->as_utf8(); + for (int i = 0; i < records->length(); i++) { + ciInlineRecord* rec = records->at(i); + if ((rec->bci == bci) && + (rec->inline_depth == inline_depth) && + (strcmp(rec->klass, klass_name) == 0) && + (strcmp(rec->method, method_name) == 0) && + (strcmp(rec->signature, signature) == 0)) { + return rec; + } + } + } + return NULL; + } + const char* error_message() { return _error_message; } @@ -845,11 +1015,42 @@ vm_exit(exit_code); } +void* ciReplay::load_inline_data(ciMethod* method, int entry_bci, int comp_level) { + if (FLAG_IS_DEFAULT(InlineDataFile)) { + tty->print_cr("ERROR: no inline replay data file specified (use -XX:InlineDataFile=inline_pid12345.txt)."); + return NULL; + } + + VM_ENTRY_MARK; + // Load and parse the replay data + CompileReplay rp(InlineDataFile, THREAD); + if (!rp.can_replay()) { + tty->print_cr("ciReplay: !rp.can_replay()"); + return NULL; + } + void* data = rp.process_inline(method, method->get_Method(), entry_bci, comp_level, THREAD); + if (HAS_PENDING_EXCEPTION) { + oop throwable = PENDING_EXCEPTION; + CLEAR_PENDING_EXCEPTION; + java_lang_Throwable::print(throwable, tty); + tty->cr(); + java_lang_Throwable::print_stack_trace(throwable, tty); + tty->cr(); + return NULL; + } + + if (rp.had_error()) { + tty->print_cr("ciReplay: Failed on %s", rp.error_message()); + return NULL; + } + return data; +} + int ciReplay::replay_impl(TRAPS) { HandleMark hm; ResourceMark rm; // Make sure we don't run with background compilation - BackgroundCompilation = false; + // BackgroundCompilation = false; if (ReplaySuppressInitializers > 2) { // ReplaySuppressInitializers > 2 means that we want to allow @@ -890,7 +1091,6 @@ return exit_code; } - void ciReplay::initialize(ciMethodData* m) { if (replay_state == NULL) { return; @@ -939,12 +1139,38 @@ if (replay_state == NULL) { return false; } - VM_ENTRY_MARK; // ciMethod without a record shouldn't be inlined. return replay_state->find_ciMethodRecord(method->get_Method()) == NULL; } +bool ciReplay::should_inline(void* data, ciMethod* method, int bci, int inline_depth) { + if (data != NULL) { + GrowableArray* records = (GrowableArray*)data; + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) != NULL; + } else if (replay_state != NULL) { + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) != NULL; + } + return false; +} + +bool ciReplay::should_not_inline(void* data, ciMethod* method, int bci, int inline_depth) { + if (data != NULL) { + GrowableArray* records = (GrowableArray*)data; + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return CompileReplay::find_ciInlineRecord(records, method->get_Method(), bci, inline_depth) == NULL; + } else if (replay_state != NULL) { + VM_ENTRY_MARK; + // Inline record are ordered by bci and depth. + return replay_state->find_ciInlineRecord(method->get_Method(), bci, inline_depth) == NULL; + } + return false; +} void ciReplay::initialize(ciMethod* m) { if (replay_state == NULL) {