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.
|