< prev index next >

src/hotspot/share/interpreter/bytecodeUtils.cpp

Print this page
rev 56281 : 8218628: Add detailed message to NullPointerException describing what is null.
Summary: This is the implementation of JEP 358: Helpful NullPointerExceptions.
Reviewed-by: coleenp
rev 56283 : [mq]: fixes_review_of_16.patch


  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #include "precompiled.hpp"
  27 #include "classfile/systemDictionary.hpp"
  28 #include "gc/shared/gcLocker.hpp"
  29 #include "interpreter/bytecodeUtils.hpp"
  30 #include "memory/resourceArea.hpp"
  31 #include "runtime/signature.hpp"
  32 #include "runtime/safepointVerifiers.hpp"
  33 #include "utilities/events.hpp"

  34 
  35 class SimulatedOperandStack;
  36 class ExceptionMessageBuilder;
  37 
  38 // The entries of a SimulatedOperandStack. They carry the analysis
  39 // information gathered for the slot.
  40 class StackSlotAnalysisData {
  41  private:
  42 
  43   friend class SimulatedOperandStack;
  44   friend class ExceptionMessageBuilder;
  45 
  46   unsigned int _bci:17;    // The bci of the bytecode that pushed the current value on the operand stack.
  47                            // INVALID if ambiguous, e.g. after a control flow merge.
  48                            // 16 bits for bci (max bytecode size) and one for INVALID.
  49   unsigned int _type:15;   // The BasicType of the value on the operand stack.
  50 
  51   // Merges this slot data with the given one and returns the result. If
  52   // the bcis of the two merged objects are different, the bci of the result
  53   // will be undefined. If the types are different, the result type is T_CONFLICT.


 194   int get_NPE_null_slot(int bci);
 195 
 196   // Prints a java-like expression for the bytecode that pushed
 197   // the value to the given slot being live at the given bci.
 198   // It constructs the expression by recursing backwards over the
 199   // bytecode using the results of the analysis done in the
 200   // constructor of ExceptionMessageBuilder.
 201   //  os:   The stream to print the message to.
 202   //  bci:  The index of the bytecode that caused the NPE.
 203   //  slot: The slot on the operand stack that contains null.
 204   //        The slots are numbered from TOS downwards, i.e.,
 205   //        TOS has the slot number 0, that below 1 and so on.
 206   //
 207   // Returns false if nothing was printed, else true.
 208   bool print_NPE_cause(outputStream *os, int bci, int slot);
 209 
 210   // Prints a string describing the failed action.
 211   void print_NPE_failed_action(outputStream *os, int bci);
 212 };
 213 
 214 
 215 /*
 216  * Prints the name of the method that is described at constant pool
 217  * index cp_index in the constant pool of method 'method'.
 218  */
 219 static void print_method_name(outputStream *os, Method* method, int cp_index) {
 220   ConstantPool* cp  = method->constants();
 221   Symbol* klass     = cp->klass_ref_at_noresolve(cp_index);
 222   Symbol* name      = cp->name_ref_at(cp_index);
 223   Symbol* signature = cp->signature_ref_at(cp_index);
 224 
 225   os->print("%s.%s(", klass->as_klass_external_name(), name->as_C_string());
 226   signature->print_as_signature_external_parameters(os);
 227   os->print(")");
 228 }
 229 
 230 /*
 231  * Prints the name of the field that is described at constant pool
 232  * index cp_index in the constant pool of method 'method'.
 233  */
 234 static void print_field_and_class(outputStream *os, Method* method, int cp_index) {
 235   ConstantPool* cp = method->constants();
 236   Symbol* klass    = cp->klass_ref_at_noresolve(cp_index);
 237   Symbol *name     = cp->name_ref_at(cp_index);
 238   os->print("%s.%s", klass->as_klass_external_name(), name->as_C_string());
 239 }
 240 
 241 /*
 242  * Returns the name of the field that is described at constant pool
 243  * index cp_index in the constant pool of method 'method'.
 244  */
 245 static char const* get_field_name(Method* method, int cp_index) {
 246   Symbol* name = method->constants()->name_ref_at(cp_index);
 247   return name->as_C_string();
 248 }
 249 
 250 static void print_local_var(outputStream *os, unsigned int bci, Method* method, int slot) {
 251   if (method->has_localvariable_table()) {
 252     for (int i = 0; i < method->localvariable_table_length(); i++) {
 253       LocalVariableTableElement* elem = method->localvariable_table_start() + i;
 254       unsigned int start = elem->start_bci;
 255       unsigned int end = start + elem->length;
 256 
 257       if ((bci >= start) && (bci < end) && (elem->slot == slot)) {
 258         ConstantPool* cp = method->constants();
 259         char *var =  cp->symbol_at(elem->name_cp_index)->as_C_string();
 260         os->print("%s", var);
 261 
 262         return;
 263       }
 264     }


 371 
 372   for (int i = get_size() - 1; i >= 0; --i) {
 373     _stack.at_put(i, _stack.at(i).merge(other._stack.at(i)));
 374   }
 375 }
 376 
 377 int SimulatedOperandStack::get_size() const {
 378   return _stack.length();
 379 }
 380 
 381 StackSlotAnalysisData SimulatedOperandStack::get_slotData(int slot) {
 382   assert(slot >= 0, "Slot < 0");
 383   assert(slot < get_size(), "Slot >= size");
 384 
 385   return _stack.at(get_size() - slot - 1);
 386 }
 387 
 388 ExceptionMessageBuilder::ExceptionMessageBuilder(Method* method, int bci) :
 389                     _method(method), _nr_of_entries(0),
 390                     _added_one(true), _all_processed(false) {
 391   ConstMethod* const_method = method->constMethod();

 392 

 393   const int len = const_method->code_size();
 394 
 395   _stacks = new GrowableArray<SimulatedOperandStack*> (len+1);
 396 
 397   for (int i = 0; i <= len; ++i) {
 398     _stacks->push(NULL);
 399   }
 400 
 401   // Initialize stack a bci 0.
 402   _stacks->at_put(0, new SimulatedOperandStack());
 403 
 404   // And initialize the start of all exception handlers.
 405   if (const_method->has_exception_handler()) {
 406     ExceptionTableElement *et = const_method->exception_table_start();
 407     for (int i = 0; i < const_method->exception_table_length(); ++i) {
 408       u2 index = et[i].handler_pc;
 409 
 410       if (_stacks->at(index) == NULL) {
 411         _stacks->at_put(index, new SimulatedOperandStack());
 412         _stacks->at(index)->push(index, T_OBJECT);


1341       } break;
1342 
1343     default:
1344       assert(0, "We should have checked this bytecode in get_NPE_null_slot().");
1345       break;
1346   }
1347 }
1348 
1349 // Main API
1350 bool BytecodeUtils::get_NPE_message_at(outputStream* ss, Method* method, int bci) {
1351 
1352   NoSafepointVerifier _nsv;   // Cannot use this object over a safepoint.
1353 
1354   // If this NPE was created via reflection, we have no real NPE.
1355   if (method->method_holder() ==
1356       SystemDictionary::reflect_NativeConstructorAccessorImpl_klass()) {
1357     return false;
1358   }
1359 
1360   // Analyse the bytecodes.

1361   ExceptionMessageBuilder emb(method, bci);
1362 
1363   // The slot of the operand stack that contains the null reference.
1364   // Also checks for NPE explicitly constructed and returns -2.
1365   int slot = emb.get_NPE_null_slot(bci);
1366 
1367   // Build the message.
1368   if (slot == -2) {
1369     // We don't want to print a message.
1370     return false;
1371   } else if (slot == -1) {
1372     // We encountered a bytecode that does not dereference a reference.
1373     DEBUG_ONLY(ss->print("There cannot be a NullPointerException at bci %d of method %s",
1374                          bci, method->external_name()));
1375     NOT_DEBUG(return false);
1376   } else {
1377     // Print string describing which action (bytecode) could not be
1378     // performed because of the null reference.
1379     emb.print_NPE_failed_action(ss, bci);
1380     // Print a description of what is null.


  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #include "precompiled.hpp"
  27 #include "classfile/systemDictionary.hpp"
  28 #include "gc/shared/gcLocker.hpp"
  29 #include "interpreter/bytecodeUtils.hpp"
  30 #include "memory/resourceArea.hpp"
  31 #include "runtime/signature.hpp"
  32 #include "runtime/safepointVerifiers.hpp"
  33 #include "utilities/events.hpp"
  34 #include "utilities/ostream.hpp"
  35 
  36 class SimulatedOperandStack;
  37 class ExceptionMessageBuilder;
  38 
  39 // The entries of a SimulatedOperandStack. They carry the analysis
  40 // information gathered for the slot.
  41 class StackSlotAnalysisData {
  42  private:
  43 
  44   friend class SimulatedOperandStack;
  45   friend class ExceptionMessageBuilder;
  46 
  47   unsigned int _bci:17;    // The bci of the bytecode that pushed the current value on the operand stack.
  48                            // INVALID if ambiguous, e.g. after a control flow merge.
  49                            // 16 bits for bci (max bytecode size) and one for INVALID.
  50   unsigned int _type:15;   // The BasicType of the value on the operand stack.
  51 
  52   // Merges this slot data with the given one and returns the result. If
  53   // the bcis of the two merged objects are different, the bci of the result
  54   // will be undefined. If the types are different, the result type is T_CONFLICT.


 195   int get_NPE_null_slot(int bci);
 196 
 197   // Prints a java-like expression for the bytecode that pushed
 198   // the value to the given slot being live at the given bci.
 199   // It constructs the expression by recursing backwards over the
 200   // bytecode using the results of the analysis done in the
 201   // constructor of ExceptionMessageBuilder.
 202   //  os:   The stream to print the message to.
 203   //  bci:  The index of the bytecode that caused the NPE.
 204   //  slot: The slot on the operand stack that contains null.
 205   //        The slots are numbered from TOS downwards, i.e.,
 206   //        TOS has the slot number 0, that below 1 and so on.
 207   //
 208   // Returns false if nothing was printed, else true.
 209   bool print_NPE_cause(outputStream *os, int bci, int slot);
 210 
 211   // Prints a string describing the failed action.
 212   void print_NPE_failed_action(outputStream *os, int bci);
 213 };
 214 
 215 // Prints the name of the method that is described at constant pool
 216 // index cp_index in the constant pool of method 'method'.



 217 static void print_method_name(outputStream *os, Method* method, int cp_index) {
 218   ConstantPool* cp  = method->constants();
 219   Symbol* klass     = cp->klass_ref_at_noresolve(cp_index);
 220   Symbol* name      = cp->name_ref_at(cp_index);
 221   Symbol* signature = cp->signature_ref_at(cp_index);
 222 
 223   os->print("%s.%s(", klass->as_klass_external_name(), name->as_C_string());
 224   signature->print_as_signature_external_parameters(os);
 225   os->print(")");
 226 }
 227 
 228 // Prints the name of the field that is described at constant pool
 229 // index cp_index in the constant pool of method 'method'.


 230 static void print_field_and_class(outputStream *os, Method* method, int cp_index) {
 231   ConstantPool* cp = method->constants();
 232   Symbol* klass    = cp->klass_ref_at_noresolve(cp_index);
 233   Symbol *name     = cp->name_ref_at(cp_index);
 234   os->print("%s.%s", klass->as_klass_external_name(), name->as_C_string());
 235 }
 236 
 237 // Returns the name of the field that is described at constant pool
 238 // index cp_index in the constant pool of method 'method'.


 239 static char const* get_field_name(Method* method, int cp_index) {
 240   Symbol* name = method->constants()->name_ref_at(cp_index);
 241   return name->as_C_string();
 242 }
 243 
 244 static void print_local_var(outputStream *os, unsigned int bci, Method* method, int slot) {
 245   if (method->has_localvariable_table()) {
 246     for (int i = 0; i < method->localvariable_table_length(); i++) {
 247       LocalVariableTableElement* elem = method->localvariable_table_start() + i;
 248       unsigned int start = elem->start_bci;
 249       unsigned int end = start + elem->length;
 250 
 251       if ((bci >= start) && (bci < end) && (elem->slot == slot)) {
 252         ConstantPool* cp = method->constants();
 253         char *var =  cp->symbol_at(elem->name_cp_index)->as_C_string();
 254         os->print("%s", var);
 255 
 256         return;
 257       }
 258     }


 365 
 366   for (int i = get_size() - 1; i >= 0; --i) {
 367     _stack.at_put(i, _stack.at(i).merge(other._stack.at(i)));
 368   }
 369 }
 370 
 371 int SimulatedOperandStack::get_size() const {
 372   return _stack.length();
 373 }
 374 
 375 StackSlotAnalysisData SimulatedOperandStack::get_slotData(int slot) {
 376   assert(slot >= 0, "Slot < 0");
 377   assert(slot < get_size(), "Slot >= size");
 378 
 379   return _stack.at(get_size() - slot - 1);
 380 }
 381 
 382 ExceptionMessageBuilder::ExceptionMessageBuilder(Method* method, int bci) :
 383                     _method(method), _nr_of_entries(0),
 384                     _added_one(true), _all_processed(false) {
 385   assert(bci >= 0, "BCI too low");
 386   assert(bci < get_size(), "BCI too large");
 387 
 388   ConstMethod* const_method = method->constMethod();
 389   const int len = const_method->code_size();
 390 
 391   _stacks = new GrowableArray<SimulatedOperandStack*> (len+1);
 392 
 393   for (int i = 0; i <= len; ++i) {
 394     _stacks->push(NULL);
 395   }
 396 
 397   // Initialize stack a bci 0.
 398   _stacks->at_put(0, new SimulatedOperandStack());
 399 
 400   // And initialize the start of all exception handlers.
 401   if (const_method->has_exception_handler()) {
 402     ExceptionTableElement *et = const_method->exception_table_start();
 403     for (int i = 0; i < const_method->exception_table_length(); ++i) {
 404       u2 index = et[i].handler_pc;
 405 
 406       if (_stacks->at(index) == NULL) {
 407         _stacks->at_put(index, new SimulatedOperandStack());
 408         _stacks->at(index)->push(index, T_OBJECT);


1337       } break;
1338 
1339     default:
1340       assert(0, "We should have checked this bytecode in get_NPE_null_slot().");
1341       break;
1342   }
1343 }
1344 
1345 // Main API
1346 bool BytecodeUtils::get_NPE_message_at(outputStream* ss, Method* method, int bci) {
1347 
1348   NoSafepointVerifier _nsv;   // Cannot use this object over a safepoint.
1349 
1350   // If this NPE was created via reflection, we have no real NPE.
1351   if (method->method_holder() ==
1352       SystemDictionary::reflect_NativeConstructorAccessorImpl_klass()) {
1353     return false;
1354   }
1355 
1356   // Analyse the bytecodes.
1357   ResourceMark rm;
1358   ExceptionMessageBuilder emb(method, bci);
1359 
1360   // The slot of the operand stack that contains the null reference.
1361   // Also checks for NPE explicitly constructed and returns -2.
1362   int slot = emb.get_NPE_null_slot(bci);
1363 
1364   // Build the message.
1365   if (slot == -2) {
1366     // We don't want to print a message.
1367     return false;
1368   } else if (slot == -1) {
1369     // We encountered a bytecode that does not dereference a reference.
1370     DEBUG_ONLY(ss->print("There cannot be a NullPointerException at bci %d of method %s",
1371                          bci, method->external_name()));
1372     NOT_DEBUG(return false);
1373   } else {
1374     // Print string describing which action (bytecode) could not be
1375     // performed because of the null reference.
1376     emb.print_NPE_failed_action(ss, bci);
1377     // Print a description of what is null.
< prev index next >