< prev index next >
src/hotspot/share/classfile/javaClasses.cpp
Print this page
rev 56353 : 8218628: Add detailed message to NullPointerException describing what is null.
Summary: This is the implementation of JEP 358: Helpful NullPointerExceptions.
Reviewed-by: coleenp, clanger, rschmelter, rriggs, forax
*** 1539,1549 ****
bool java_lang_Class::offsets_computed = false;
int java_lang_Class::classRedefinedCount_offset = -1;
#define CLASS_FIELDS_DO(macro) \
! macro(classRedefinedCount_offset, k, "classRedefinedCount", int_signature, false) ; \
macro(_class_loader_offset, k, "classLoader", classloader_signature, false); \
macro(_component_mirror_offset, k, "componentType", class_signature, false); \
macro(_module_offset, k, "module", module_signature, false); \
macro(_name_offset, k, "name", string_signature, false); \
--- 1539,1549 ----
bool java_lang_Class::offsets_computed = false;
int java_lang_Class::classRedefinedCount_offset = -1;
#define CLASS_FIELDS_DO(macro) \
! macro(classRedefinedCount_offset, k, "classRedefinedCount", int_signature, false); \
macro(_class_loader_offset, k, "classLoader", classloader_signature, false); \
macro(_component_mirror_offset, k, "componentType", class_signature, false); \
macro(_module_offset, k, "module", module_signature, false); \
macro(_name_offset, k, "name", string_signature, false); \
*** 1932,1942 ****
static inline bool version_matches(Method* method, int version) {
assert(version < MAX_VERSION, "version is too big");
return method != NULL && (method->constants()->version() == version);
}
-
// 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.
class BacktraceBuilder: public StackObj {
friend class BacktraceIterator;
--- 1932,1941 ----
*** 1944,1963 ****
Handle _backtrace;
objArrayOop _head;
typeArrayOop _methods;
typeArrayOop _bcis;
objArrayOop _mirrors;
! typeArrayOop _names; // needed to insulate method name against redefinition
int _index;
NoSafepointVerifier _nsv;
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_names_offset = java_lang_Throwable::trace_names_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
};
// get info out of chunks
--- 1943,1967 ----
Handle _backtrace;
objArrayOop _head;
typeArrayOop _methods;
typeArrayOop _bcis;
objArrayOop _mirrors;
! typeArrayOop _names; // Needed to insulate method name against redefinition.
! // This is set to a java.lang.Boolean(true) if the top frame
! // of the backtrace is omitted because it shall be hidden.
! // Else it is null.
! oop _has_hidden_top_frame;
int _index;
NoSafepointVerifier _nsv;
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_names_offset = java_lang_Throwable::trace_names_offset,
trace_next_offset = java_lang_Throwable::trace_next_offset,
+ trace_hidden_offset = java_lang_Throwable::trace_hidden_offset,
trace_size = java_lang_Throwable::trace_size,
trace_chunk_size = java_lang_Throwable::trace_chunk_size
};
// get info out of chunks
*** 1979,2003 ****
static typeArrayOop get_names(objArrayHandle chunk) {
typeArrayOop names = typeArrayOop(chunk->obj_at(trace_names_offset));
assert(names != NULL, "names array should be initialized in backtrace");
return names;
}
public:
// constructor for new backtrace
! BacktraceBuilder(TRAPS): _head(NULL), _methods(NULL), _bcis(NULL), _mirrors(NULL), _names(NULL) {
expand(CHECK);
_backtrace = Handle(THREAD, _head);
_index = 0;
}
BacktraceBuilder(Thread* thread, objArrayHandle backtrace) {
_methods = get_methods(backtrace);
_bcis = get_bcis(backtrace);
_mirrors = get_mirrors(backtrace);
_names = get_names(backtrace);
assert(_methods->length() == _bcis->length() &&
_methods->length() == _mirrors->length() &&
_mirrors->length() == _names->length(),
"method and source information arrays should match");
--- 1983,2012 ----
static typeArrayOop get_names(objArrayHandle chunk) {
typeArrayOop names = typeArrayOop(chunk->obj_at(trace_names_offset));
assert(names != NULL, "names array should be initialized in backtrace");
return names;
}
+ static oop get_has_hidden_top_frame(objArrayHandle chunk) {
+ oop hidden = chunk->obj_at(trace_hidden_offset);
+ return hidden;
+ }
public:
// constructor for new backtrace
! BacktraceBuilder(TRAPS): _head(NULL), _methods(NULL), _bcis(NULL), _mirrors(NULL), _names(NULL), _has_hidden_top_frame(NULL) {
expand(CHECK);
_backtrace = Handle(THREAD, _head);
_index = 0;
}
BacktraceBuilder(Thread* thread, objArrayHandle backtrace) {
_methods = get_methods(backtrace);
_bcis = get_bcis(backtrace);
_mirrors = get_mirrors(backtrace);
_names = get_names(backtrace);
+ _has_hidden_top_frame = get_has_hidden_top_frame(backtrace);
assert(_methods->length() == _bcis->length() &&
_methods->length() == _mirrors->length() &&
_mirrors->length() == _names->length(),
"method and source information arrays should match");
*** 2031,2040 ****
--- 2040,2050 ----
}
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_names_offset, new_names());
+ new_head->obj_at_put(trace_hidden_offset, NULL);
_head = new_head();
_methods = new_methods();
_bcis = new_bcis();
_mirrors = new_mirrors();
*** 2071,2080 ****
--- 2081,2100 ----
assert(method->method_holder()->java_mirror() != NULL, "never push null for mirror");
_mirrors->obj_at_put(_index, method->method_holder()->java_mirror());
_index++;
}
+ void set_has_hidden_top_frame(TRAPS) {
+ if (_has_hidden_top_frame == NULL) {
+ jvalue prim;
+ prim.z = 1;
+ PauseNoSafepointVerifier pnsv(&_nsv);
+ _has_hidden_top_frame = java_lang_boxing_object::create(T_BOOLEAN, &prim, CHECK);
+ _head->obj_at_put(trace_hidden_offset, _has_hidden_top_frame);
+ }
+ }
+
};
struct BacktraceElement : public StackObj {
int _method_id;
int _bci;
*** 2400,2410 ****
// there are none or we've seen them all - either way stop checking
skip_throwableInit_check = true;
}
}
if (method->is_hidden()) {
! if (skip_hidden) continue;
}
bt.push(method, bci, CHECK);
total_count++;
}
--- 2420,2436 ----
// there are none or we've seen them all - either way stop checking
skip_throwableInit_check = true;
}
}
if (method->is_hidden()) {
! if (skip_hidden) {
! if (total_count == 0) {
! // The top frame will be hidden from the stack trace.
! bt.set_has_hidden_top_frame(CHECK);
! }
! continue;
! }
}
bt.push(method, bci, CHECK);
total_count++;
}
*** 2517,2526 ****
--- 2543,2583 ----
bte._bci,
bte._name, CHECK);
}
}
+ bool java_lang_Throwable::get_top_method_and_bci(oop throwable, Method** method, int* bci) {
+ Thread* THREAD = Thread::current();
+ objArrayHandle result(THREAD, objArrayOop(backtrace(throwable)));
+ BacktraceIterator iter(result, THREAD);
+ // No backtrace available.
+ if (!iter.repeat()) return false;
+
+ // If the exception happened in a frame that has been hidden, i.e.,
+ // omitted from the back trace, we can not compute the message.
+ oop hidden = ((objArrayOop)backtrace(throwable))->obj_at(trace_hidden_offset);
+ if (hidden != NULL) {
+ return false;
+ }
+
+ // Get first backtrace element.
+ BacktraceElement bte = iter.next(THREAD);
+
+ InstanceKlass* holder = InstanceKlass::cast(java_lang_Class::as_Klass(bte._mirror()));
+ assert(holder != NULL, "first element should be non-null");
+ Method* m = holder->method_with_orig_idnum(bte._method_id, bte._version);
+
+ // Original version is no longer available.
+ if (m == NULL || !version_matches(m, bte._version)) {
+ return false;
+ }
+
+ *method = m;
+ *bci = bte._bci;
+ return true;
+ }
+
oop java_lang_StackTraceElement::create(const methodHandle& method, int bci, TRAPS) {
// Allocate java.lang.StackTraceElement instance
InstanceKlass* k = SystemDictionary::StackTraceElement_klass();
assert(k != NULL, "must be loaded in 1.4+");
if (k->should_be_initialized()) {
< prev index next >