--- old/src/share/vm/classfile/javaClasses.cpp 2015-10-30 18:24:03.584615587 -0400 +++ new/src/share/vm/classfile/javaClasses.cpp 2015-10-30 18:24:03.156709904 -0400 @@ -24,6 +24,7 @@ #include "precompiled.hpp" #include "classfile/altHashing.hpp" +#include "classfile/backtrace.hpp" #include "classfile/javaClasses.inline.hpp" #include "classfile/stringTable.hpp" #include "classfile/vmSymbols.hpp" @@ -1330,12 +1331,7 @@ return extract_low_short_from_int(merged); } -static inline bool version_matches(Method* method, int version) { - assert(version < MAX_VERSION, "version is too big"); - return method != NULL && (method->constants()->version() == version); -} - -static inline int get_line_number(Method* method, int bci) { +static inline int get_line_number(const methodHandle& method, int bci) { int line_number = 0; if (method->is_native()) { // Negative value different from -1 below, enabling Java code in @@ -1352,6 +1348,28 @@ return line_number; } +// Mark all of the methods in this backtrace as on the stack during full GC +// so that they aren't deallocated if any of these methods are redefined. +void java_lang_Throwable::mark_on_stack(oop throwable) { + objArrayOop result = objArrayOop(backtrace(throwable)); + + while (result != NULL) { + typeArrayOop methods = typeArrayOop(result->obj_at(trace_methods_offset)); + + if (methods == NULL) { + return; + } + + int length = methods->length(); + for (int index = 0; index < length; index++) { + Method* method = ((Method*)methods->metadata_at(index)); + if (method == NULL) return; + method->set_on_stack(true); + } + result = objArrayOop(result->obj_at(trace_next_offset)); + } +} + // This class provides a simple wrapper over the internal structure of // exception backtrace to insulate users of the backtrace from needing // to know what it looks like. @@ -1362,17 +1380,51 @@ typeArrayOop _methods; typeArrayOop _bcis; objArrayOop _mirrors; - typeArrayOop _cprefs; // needed to insulate method name against redefinition int _index; No_Safepoint_Verifier _nsv; + void add_backtrace(Handle throwable) { + Pause_No_Safepoint_Verifier pnsv(&_nsv); + // RedefineClasses support + // Save this backtrace object to find methods used in Java heap + BacktraceList::add(throwable()); + } + + void expand(TRAPS) { + objArrayHandle old_head(THREAD, _head); + Pause_No_Safepoint_Verifier pnsv(&_nsv); + + objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK); + objArrayHandle new_head(THREAD, head); + + typeArrayOop methods = oopFactory::new_metadataArray(trace_chunk_size, CHECK); + typeArrayHandle new_methods(THREAD, methods); + + typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK); + typeArrayHandle new_bcis(THREAD, bcis); + + objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); + objArrayHandle new_mirrors(THREAD, mirrors); + + if (!old_head.is_null()) { + old_head->obj_at_put(trace_next_offset, new_head()); + } + new_head->obj_at_put(trace_methods_offset, new_methods()); + new_head->obj_at_put(trace_bcis_offset, new_bcis()); + new_head->obj_at_put(trace_mirrors_offset, new_mirrors()); + + _head = new_head(); + _methods = new_methods(); + _bcis = new_bcis(); + _mirrors = new_mirrors(); + _index = 0; + } public: enum { trace_methods_offset = java_lang_Throwable::trace_methods_offset, trace_bcis_offset = java_lang_Throwable::trace_bcis_offset, trace_mirrors_offset = java_lang_Throwable::trace_mirrors_offset, - trace_cprefs_offset = java_lang_Throwable::trace_cprefs_offset, trace_next_offset = java_lang_Throwable::trace_next_offset, trace_size = java_lang_Throwable::trace_size, trace_chunk_size = java_lang_Throwable::trace_chunk_size @@ -1394,24 +1446,19 @@ assert(mirrors != NULL, "mirror array should be initialized in backtrace"); return mirrors; } - static typeArrayOop get_cprefs(objArrayHandle chunk) { - typeArrayOop cprefs = typeArrayOop(chunk->obj_at(trace_cprefs_offset)); - assert(cprefs != NULL, "cprefs array should be initialized in backtrace"); - return cprefs; - } // constructor for new backtrace - BacktraceBuilder(TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL), _cprefs(NULL) { + BacktraceBuilder(Handle throwable, TRAPS): _methods(NULL), _bcis(NULL), _head(NULL), _mirrors(NULL) { expand(CHECK); _backtrace = _head; _index = 0; + add_backtrace(throwable); } BacktraceBuilder(objArrayHandle backtrace) { _methods = get_methods(backtrace); _bcis = get_bcis(backtrace); _mirrors = get_mirrors(backtrace); - _cprefs = get_cprefs(backtrace); assert(_methods->length() == _bcis->length() && _methods->length() == _mirrors->length(), "method and source information arrays should match"); @@ -1421,41 +1468,6 @@ _index = 0; } - void expand(TRAPS) { - objArrayHandle old_head(THREAD, _head); - Pause_No_Safepoint_Verifier pnsv(&_nsv); - - objArrayOop head = oopFactory::new_objectArray(trace_size, CHECK); - objArrayHandle new_head(THREAD, head); - - typeArrayOop methods = oopFactory::new_shortArray(trace_chunk_size, CHECK); - typeArrayHandle new_methods(THREAD, methods); - - typeArrayOop bcis = oopFactory::new_intArray(trace_chunk_size, CHECK); - typeArrayHandle new_bcis(THREAD, bcis); - - objArrayOop mirrors = oopFactory::new_objectArray(trace_chunk_size, CHECK); - objArrayHandle new_mirrors(THREAD, mirrors); - - typeArrayOop cprefs = oopFactory::new_shortArray(trace_chunk_size, CHECK); - typeArrayHandle new_cprefs(THREAD, cprefs); - - if (!old_head.is_null()) { - old_head->obj_at_put(trace_next_offset, new_head()); - } - new_head->obj_at_put(trace_methods_offset, new_methods()); - new_head->obj_at_put(trace_bcis_offset, new_bcis()); - new_head->obj_at_put(trace_mirrors_offset, new_mirrors()); - new_head->obj_at_put(trace_cprefs_offset, new_cprefs()); - - _head = new_head(); - _methods = new_methods(); - _bcis = new_bcis(); - _mirrors = new_mirrors(); - _cprefs = new_cprefs(); - _index = 0; - } - oop backtrace() { return _backtrace(); } @@ -1472,9 +1484,8 @@ method = mhandle(); } - _methods->short_at_put(_index, method->orig_method_idnum()); + _methods->metadata_at_put(_index, method); _bcis->int_at_put(_index, merge_bci_and_version(bci, method->constants()->version())); - _cprefs->short_at_put(_index, method->name_index()); // We need to save the mirrors in the backtrace to keep the class // from being unloaded while we still have this stack trace. @@ -1500,17 +1511,14 @@ // Print stack trace element to resource allocated buffer char* java_lang_Throwable::print_stack_element_to_buffer(Handle mirror, - int method_id, int version, int bci, int cpref) { + const methodHandle& method, int version, int bci) { // Get strings and string lengths InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(mirror())); const char* klass_name = holder->external_name(); int buf_len = (int)strlen(klass_name); - Method* method = holder->method_with_orig_idnum(method_id, version); - - // The method can be NULL if the requested class version is gone - Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); + Symbol* sym = method->name(); char* method_name = sym->as_C_string(); buf_len += (int)strlen(method_name); @@ -1527,27 +1535,23 @@ // Print stack trace line in buffer sprintf(buf, "\tat %s.%s", klass_name, method_name); - if (!version_matches(method, version)) { - strcat(buf, "(Redefined)"); + int line_number = get_line_number(method, bci); + if (line_number == -2) { + strcat(buf, "(Native Method)"); } else { - int line_number = get_line_number(method, bci); - if (line_number == -2) { - strcat(buf, "(Native Method)"); + if (source_file_name != NULL && (line_number != -1)) { + // Sourcename and linenumber + sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); + } else if (source_file_name != NULL) { + // Just sourcename + sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); } else { - if (source_file_name != NULL && (line_number != -1)) { - // Sourcename and linenumber - sprintf(buf + (int)strlen(buf), "(%s:%d)", source_file_name, line_number); - } else if (source_file_name != NULL) { - // Just sourcename - sprintf(buf + (int)strlen(buf), "(%s)", source_file_name); - } else { - // Neither sourcename nor linenumber - sprintf(buf + (int)strlen(buf), "(Unknown Source)"); - } - nmethod* nm = method->code(); - if (WizardMode && nm != NULL) { - sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); - } + // Neither sourcename nor linenumber + sprintf(buf + (int)strlen(buf), "(Unknown Source)"); + } + nmethod* nm = method->code(); + if (WizardMode && nm != NULL) { + sprintf(buf + (int)strlen(buf), "(nmethod " INTPTR_FORMAT ")", (intptr_t)nm); } } @@ -1555,18 +1559,16 @@ } void java_lang_Throwable::print_stack_element(outputStream *st, Handle mirror, - int method_id, int version, int bci, int cpref) { + const methodHandle& method, int version, int bci) { ResourceMark rm; - char* buf = print_stack_element_to_buffer(mirror, method_id, version, bci, cpref); + char* buf = print_stack_element_to_buffer(mirror, method, version, bci); st->print_cr("%s", buf); } void java_lang_Throwable::print_stack_element(outputStream *st, const methodHandle& method, int bci) { Handle mirror = method->method_holder()->java_mirror(); - int method_id = method->orig_method_idnum(); int version = method->constants()->version(); - int cpref = method->name_index(); - print_stack_element(st, mirror, method_id, version, bci, cpref); + print_stack_element(st, mirror, method, version, bci); } const char* java_lang_Throwable::no_stack_trace_message() { @@ -1591,18 +1593,16 @@ typeArrayHandle methods (THREAD, BacktraceBuilder::get_methods(result)); typeArrayHandle bcis (THREAD, BacktraceBuilder::get_bcis(result)); objArrayHandle mirrors (THREAD, BacktraceBuilder::get_mirrors(result)); - typeArrayHandle cprefs (THREAD, BacktraceBuilder::get_cprefs(result)); int length = methods()->length(); for (int index = 0; index < length; index++) { Handle mirror(THREAD, mirrors->obj_at(index)); // NULL mirror means end of stack trace if (mirror.is_null()) goto handle_cause; - int method = methods->short_at(index); + methodHandle method(THREAD, (Method*)methods->metadata_at(index)); int version = version_at(bcis->int_at(index)); int bci = bci_at(bcis->int_at(index)); - int cpref = cprefs->short_at(index); - print_stack_element(st, mirror, method, version, bci, cpref); + print_stack_element(st, mirror, method, version, bci); } result = objArrayHandle(THREAD, objArrayOop(result->obj_at(trace_next_offset))); } @@ -1645,7 +1645,7 @@ int max_depth = MaxJavaStackTraceDepth; JavaThread* thread = (JavaThread*)THREAD; - BacktraceBuilder bt(CHECK); + BacktraceBuilder bt(throwable, CHECK); // If there is no Java frame just return the method that was being called // with bci 0 @@ -1787,7 +1787,7 @@ // No-op if stack trace is disabled if (!StackTraceInThrowable) return; - BacktraceBuilder bt(CHECK); // creates a backtrace + BacktraceBuilder bt(throwable, CHECK); // creates a backtrace set_backtrace(throwable(), bt.backtrace()); } @@ -1878,30 +1878,28 @@ if (chunk == NULL) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - // Get method id, bci, version, mirror and cpref from chunk + // Get method id, bci, version, mirror from chunk typeArrayOop methods = BacktraceBuilder::get_methods(chunk); typeArrayOop bcis = BacktraceBuilder::get_bcis(chunk); objArrayOop mirrors = BacktraceBuilder::get_mirrors(chunk); - typeArrayOop cprefs = BacktraceBuilder::get_cprefs(chunk); assert(methods != NULL && bcis != NULL && mirrors != NULL, "sanity check"); - int method = methods->short_at(chunk_index); + methodHandle method(THREAD, (Method*)methods->metadata_at(chunk_index)); int version = version_at(bcis->int_at(chunk_index)); int bci = bci_at(bcis->int_at(chunk_index)); - int cpref = cprefs->short_at(chunk_index); Handle mirror(THREAD, mirrors->obj_at(chunk_index)); // Chunk can be partial full if (mirror.is_null()) { THROW_(vmSymbols::java_lang_IndexOutOfBoundsException(), NULL); } - oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, cpref, CHECK_0); + oop element = java_lang_StackTraceElement::create(mirror, method, version, bci, CHECK_0); return element; } -oop java_lang_StackTraceElement::create(Handle mirror, int method_id, - int version, int bci, int cpref, TRAPS) { +oop java_lang_StackTraceElement::create(Handle mirror, const methodHandle& method, + int version, int bci, TRAPS) { // Allocate java.lang.StackTraceElement instance Klass* k = SystemDictionary::StackTraceElement_klass(); assert(k != NULL, "must be loaded in 1.4+"); @@ -1918,38 +1916,25 @@ oop classname = StringTable::intern((char*) str, CHECK_0); java_lang_StackTraceElement::set_declaringClass(element(), classname); - Method* method = holder->method_with_orig_idnum(method_id, version); - - // The method can be NULL if the requested class version is gone - Symbol* sym = (method != NULL) ? method->name() : holder->constants()->symbol_at(cpref); - // Fill in method name - oop methodname = StringTable::intern(sym, CHECK_0); + oop methodname = StringTable::intern(method->name(), CHECK_0); java_lang_StackTraceElement::set_methodName(element(), methodname); - if (!version_matches(method, version)) { - // The method was redefined, accurate line number information isn't available - java_lang_StackTraceElement::set_fileName(element(), NULL); - java_lang_StackTraceElement::set_lineNumber(element(), -1); - } else { - // Fill in source file name and line number. - Symbol* source = get_source_file_name(holder, version); - if (ShowHiddenFrames && source == NULL) - source = vmSymbols::unknown_class_name(); - oop filename = StringTable::intern(source, CHECK_0); - java_lang_StackTraceElement::set_fileName(element(), filename); + // Fill in source file name and line number. + Symbol* source = get_source_file_name(holder, version); + if (ShowHiddenFrames && source == NULL) + source = vmSymbols::unknown_class_name(); + oop filename = StringTable::intern(source, CHECK_0); + java_lang_StackTraceElement::set_fileName(element(), filename); - int line_number = get_line_number(method, bci); - java_lang_StackTraceElement::set_lineNumber(element(), line_number); - } + int line_number = get_line_number(method, bci); + java_lang_StackTraceElement::set_lineNumber(element(), line_number); return element(); } oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) { Handle mirror (THREAD, method->method_holder()->java_mirror()); - int method_id = method->orig_method_idnum(); - int cpref = method->name_index(); - return create(mirror, method_id, method->constants()->version(), bci, cpref, THREAD); + return create(mirror, method, method->constants()->version(), bci, THREAD); } void java_lang_reflect_AccessibleObject::compute_offsets() {