The compiler in the server VM now provides correct stack backtraces for all “cold” built-in exceptions. For performance purposes, when such an exception is thrown a few times, the method may be recompiled. After recompilation, the compiler may choose a faster tactic using preallocated exceptions that do not provide a stack trace. To disable completely the use of preallocated exceptions, use this new flag: -XX:-OmitStackTraceInFastThrow.
if (JvmtiExport::can_post_exceptions()) { // Do not try anything fancy if we're notifying the VM on every throw. // Cf. case Bytecodes::_athrow in parse2.cpp. uncommon_trap(reason, Deoptimization::Action_none, (ciKlass*)NULL, (char*)NULL, must_throw); return; }
// If this particular condition has not yet happened at this // bytecode, then use the uncommon trap mechanism, and allow for // a future recompilation if several traps occur here. // If the throw is hot, try to use a more complicated inline mechanism // which keeps execution inside the compiled code. bool treat_throw_as_hot = false; ciMethodData* md = method()->method_data();
if (ProfileTraps) { if (too_many_traps(reason)) { treat_throw_as_hot = true; } // (If there is no MDO at all, assume it is early in // execution, and that any deopts are part of the // startup transient, and don't need to be remembered.)
// Also, if there is a local exception handler, treat all throws // as hot if there has been at least one in this method. if (C->trap_count(reason) != 0 && method()->method_data()->trap_count(reason) != 0 && has_ex_handler()) { treat_throw_as_hot = true; } }
// If this throw happens frequently, an uncommon trap might cause // a performance pothole. If there is a local exception handler, // and if this particular bytecode appears to be deoptimizing often, // let us handle the throw inline, with a preconstructed instance. // Note: If the deopt count has blown up, the uncommon trap // runtime is going to flush this nmethod, not matter what. if (treat_throw_as_hot && (!StackTraceInThrowable || OmitStackTraceInFastThrow)) { // If the throw is local, we use a pre-existing instance and // punt on the backtrace. This would lead to a missing backtrace // (a repeat of 4292742) if the backtrace object is ever asked // for its backtrace. // Fixing this remaining case of 4292742 requires some flavor of // escape analysis. Leave that for the future. ciInstance* ex_obj = NULL; switch (reason) { case Deoptimization::Reason_null_check: ex_obj = env()->NullPointerException_instance(); break; case Deoptimization::Reason_div0_check: ex_obj = env()->ArithmeticException_instance(); break; case Deoptimization::Reason_range_check: ex_obj = env()->ArrayIndexOutOfBoundsException_instance(); break; case Deoptimization::Reason_class_check: if (java_bc() == Bytecodes::_aastore) { ex_obj = env()->ArrayStoreException_instance(); } else { ex_obj = env()->ClassCastException_instance(); } break; } if (failing()) { stop(); return; } // exception allocation might fail if (ex_obj != NULL) { // Cheat with a preallocated exception object. if (C->log() != NULL) C->log()->elem("hot_throw preallocated='1' reason='%s'", Deoptimization::trap_reason_name(reason)); const TypeInstPtr* ex_con = TypeInstPtr::make(ex_obj); Node* ex_node = _gvn.transform(new (C, 1) ConPNode(ex_con));
// Clear the detail message of the preallocated exception object. // Weblogic sometimes mutates the detail message of exceptions // using reflection. int offset = java_lang_Throwable::get_detailMessage_offset(); const TypePtr* adr_typ = ex_con->add_offset(offset);
publicclassTestOmitStackTraceInFastThrow { publicstaticvoidmain(String[] args) { intcounter=0; int c=0; while(true) { try { Objectobj=null; /* * If we cause the exception every time(= without this "if" statement), * the optimization does not happen somehow. * So, cause it conditionally. */ if(counter % 2 == 0) { obj = newObject(); } // Cause NullpointerException obj.getClass(); }catch(NullPointerException e) { e.printStackTrace(); if(e.getStackTrace() == null || e.getStackTrace().length==0 ){ c++; if(c>2){ break; } } } counter++; } } }