1 | /* |
2 | * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved. |
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | * |
5 | * This code is free software; you can redistribute it and/or modify it |
6 | * under the terms of the GNU General Public License version 2 only, as |
7 | * published by the Free Software Foundation. |
8 | * |
9 | * This code is distributed in the hope that it will be useful, but WITHOUT |
10 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
11 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
12 | * version 2 for more details (a copy is included in the LICENSE file that |
13 | * accompanied this code). |
14 | * |
15 | * You should have received a copy of the GNU General Public License version |
16 | * 2 along with this work; if not, write to the Free Software Foundation, |
17 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
18 | * |
19 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
20 | * or visit www.oracle.com if you need additional information or have any |
21 | * questions. |
22 | * |
23 | */ |
24 | |
25 | #include "precompiled.hpp" |
26 | #include "classfile/systemDictionary.hpp" |
27 | #include "classfile/vmSymbols.hpp" |
28 | #include "compiler/compileBroker.hpp" |
29 | #include "logging/log.hpp" |
30 | #include "logging/logStream.hpp" |
31 | #include "memory/resourceArea.hpp" |
32 | #include "memory/universe.hpp" |
33 | #include "oops/oop.inline.hpp" |
34 | #include "runtime/handles.inline.hpp" |
35 | #include "runtime/init.hpp" |
36 | #include "runtime/java.hpp" |
37 | #include "runtime/javaCalls.hpp" |
38 | #include "runtime/os.hpp" |
39 | #include "runtime/thread.inline.hpp" |
40 | #include "runtime/threadCritical.hpp" |
41 | #include "runtime/atomic.hpp" |
42 | #include "utilities/events.hpp" |
43 | #include "utilities/exceptions.hpp" |
44 | |
45 | // Implementation of ThreadShadow |
46 | void check_ThreadShadow() { |
47 | const ByteSize offset1 = byte_offset_of(ThreadShadow, _pending_exception); |
48 | const ByteSize offset2 = Thread::pending_exception_offset(); |
49 | if (offset1 != offset2) fatal("ThreadShadow::_pending_exception is not positioned correctly" ); |
50 | } |
51 | |
52 | |
53 | void ThreadShadow::set_pending_exception(oop exception, const char* file, int line) { |
54 | assert(exception != NULL && oopDesc::is_oop(exception), "invalid exception oop" ); |
55 | _pending_exception = exception; |
56 | _exception_file = file; |
57 | _exception_line = line; |
58 | } |
59 | |
60 | void ThreadShadow::clear_pending_exception() { |
61 | LogTarget(Debug, exceptions) lt; |
62 | if (_pending_exception != NULL && lt.is_enabled()) { |
63 | ResourceMark rm; |
64 | LogStream ls(lt); |
65 | ls.print("Thread::clear_pending_exception: cleared exception:" ); |
66 | _pending_exception->print_on(&ls); |
67 | } |
68 | _pending_exception = NULL; |
69 | _exception_file = NULL; |
70 | _exception_line = 0; |
71 | } |
72 | // Implementation of Exceptions |
73 | |
74 | bool Exceptions::special_exception(Thread* thread, const char* file, int line, Handle h_exception) { |
75 | // bootstrapping check |
76 | if (!Universe::is_fully_initialized()) { |
77 | vm_exit_during_initialization(h_exception); |
78 | ShouldNotReachHere(); |
79 | } |
80 | |
81 | #ifdef ASSERT |
82 | // Check for trying to throw stack overflow before initialization is complete |
83 | // to prevent infinite recursion trying to initialize stack overflow without |
84 | // adequate stack space. |
85 | // This can happen with stress testing a large value of StackShadowPages |
86 | if (h_exception()->klass() == SystemDictionary::StackOverflowError_klass()) { |
87 | InstanceKlass* ik = InstanceKlass::cast(h_exception->klass()); |
88 | assert(ik->is_initialized(), |
89 | "need to increase java_thread_min_stack_allowed calculation" ); |
90 | } |
91 | #endif // ASSERT |
92 | |
93 | if (thread->is_VM_thread() |
94 | || !thread->can_call_java()) { |
95 | // We do not care what kind of exception we get for the vm-thread or a thread which |
96 | // is compiling. We just install a dummy exception object |
97 | thread->set_pending_exception(Universe::vm_exception(), file, line); |
98 | return true; |
99 | } |
100 | |
101 | return false; |
102 | } |
103 | |
104 | bool Exceptions::special_exception(Thread* thread, const char* file, int line, Symbol* h_name, const char* message) { |
105 | // bootstrapping check |
106 | if (!Universe::is_fully_initialized()) { |
107 | if (h_name == NULL) { |
108 | // atleast an informative message. |
109 | vm_exit_during_initialization("Exception" , message); |
110 | } else { |
111 | vm_exit_during_initialization(h_name, message); |
112 | } |
113 | ShouldNotReachHere(); |
114 | } |
115 | |
116 | if (thread->is_VM_thread() |
117 | || !thread->can_call_java()) { |
118 | // We do not care what kind of exception we get for the vm-thread or a thread which |
119 | // is compiling. We just install a dummy exception object |
120 | thread->set_pending_exception(Universe::vm_exception(), file, line); |
121 | return true; |
122 | } |
123 | return false; |
124 | } |
125 | |
126 | // This method should only be called from generated code, |
127 | // therefore the exception oop should be in the oopmap. |
128 | void Exceptions::_throw_oop(Thread* thread, const char* file, int line, oop exception) { |
129 | assert(exception != NULL, "exception should not be NULL" ); |
130 | Handle h_exception(thread, exception); |
131 | _throw(thread, file, line, h_exception); |
132 | } |
133 | |
134 | void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exception, const char* message) { |
135 | ResourceMark rm(thread); |
136 | assert(h_exception() != NULL, "exception should not be NULL" ); |
137 | |
138 | // tracing (do this up front - so it works during boot strapping) |
139 | // Note, the print_value_string() argument is not called unless logging is enabled! |
140 | log_info(exceptions)("Exception <%s%s%s> (" INTPTR_FORMAT ") \n" |
141 | "thrown [%s, line %d]\nfor thread " INTPTR_FORMAT, |
142 | h_exception->print_value_string(), |
143 | message ? ": " : "" , message ? message : "" , |
144 | p2i(h_exception()), file, line, p2i(thread)); |
145 | |
146 | // for AbortVMOnException flag |
147 | Exceptions::debug_check_abort(h_exception, message); |
148 | |
149 | // Check for special boot-strapping/vm-thread handling |
150 | if (special_exception(thread, file, line, h_exception)) { |
151 | return; |
152 | } |
153 | |
154 | if (h_exception->is_a(SystemDictionary::OutOfMemoryError_klass())) { |
155 | count_out_of_memory_exceptions(h_exception); |
156 | } |
157 | |
158 | if (h_exception->is_a(SystemDictionary::LinkageError_klass())) { |
159 | Atomic::inc(&_linkage_errors); |
160 | } |
161 | |
162 | assert(h_exception->is_a(SystemDictionary::Throwable_klass()), "exception is not a subclass of java/lang/Throwable" ); |
163 | |
164 | // set the pending exception |
165 | thread->set_pending_exception(h_exception(), file, line); |
166 | |
167 | // vm log |
168 | Events::log_exception(thread, h_exception, message, file, line); |
169 | } |
170 | |
171 | |
172 | void Exceptions::_throw_msg(Thread* thread, const char* file, int line, Symbol* name, const char* message, |
173 | Handle h_loader, Handle h_protection_domain) { |
174 | // Check for special boot-strapping/vm-thread handling |
175 | if (special_exception(thread, file, line, name, message)) return; |
176 | // Create and throw exception |
177 | Handle h_cause(thread, NULL); |
178 | Handle h_exception = new_exception(thread, name, message, h_cause, h_loader, h_protection_domain); |
179 | _throw(thread, file, line, h_exception, message); |
180 | } |
181 | |
182 | void Exceptions::_throw_msg_cause(Thread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_cause, |
183 | Handle h_loader, Handle h_protection_domain) { |
184 | // Check for special boot-strapping/vm-thread handling |
185 | if (special_exception(thread, file, line, name, message)) return; |
186 | // Create and throw exception and init cause |
187 | Handle h_exception = new_exception(thread, name, message, h_cause, h_loader, h_protection_domain); |
188 | _throw(thread, file, line, h_exception, message); |
189 | } |
190 | |
191 | void Exceptions::_throw_cause(Thread* thread, const char* file, int line, Symbol* name, Handle h_cause, |
192 | Handle h_loader, Handle h_protection_domain) { |
193 | // Check for special boot-strapping/vm-thread handling |
194 | if (special_exception(thread, file, line, h_cause)) return; |
195 | // Create and throw exception |
196 | Handle h_exception = new_exception(thread, name, h_cause, h_loader, h_protection_domain); |
197 | _throw(thread, file, line, h_exception, NULL); |
198 | } |
199 | |
200 | void Exceptions::_throw_args(Thread* thread, const char* file, int line, Symbol* name, Symbol* signature, JavaCallArguments *args) { |
201 | // Check for special boot-strapping/vm-thread handling |
202 | if (special_exception(thread, file, line, name, NULL)) return; |
203 | // Create and throw exception |
204 | Handle h_loader(thread, NULL); |
205 | Handle h_prot(thread, NULL); |
206 | Handle exception = new_exception(thread, name, signature, args, h_loader, h_prot); |
207 | _throw(thread, file, line, exception); |
208 | } |
209 | |
210 | |
211 | // Methods for default parameters. |
212 | // NOTE: These must be here (and not in the header file) because of include circularities. |
213 | void Exceptions::_throw_msg_cause(Thread* thread, const char* file, int line, Symbol* name, const char* message, Handle h_cause) { |
214 | _throw_msg_cause(thread, file, line, name, message, h_cause, Handle(thread, NULL), Handle(thread, NULL)); |
215 | } |
216 | void Exceptions::_throw_msg(Thread* thread, const char* file, int line, Symbol* name, const char* message) { |
217 | _throw_msg(thread, file, line, name, message, Handle(thread, NULL), Handle(thread, NULL)); |
218 | } |
219 | void Exceptions::_throw_cause(Thread* thread, const char* file, int line, Symbol* name, Handle h_cause) { |
220 | _throw_cause(thread, file, line, name, h_cause, Handle(thread, NULL), Handle(thread, NULL)); |
221 | } |
222 | |
223 | |
224 | void Exceptions::throw_stack_overflow_exception(Thread* THREAD, const char* file, int line, const methodHandle& method) { |
225 | Handle exception; |
226 | if (!THREAD->has_pending_exception()) { |
227 | InstanceKlass* k = SystemDictionary::StackOverflowError_klass(); |
228 | oop e = k->allocate_instance(CHECK); |
229 | exception = Handle(THREAD, e); // fill_in_stack trace does gc |
230 | assert(k->is_initialized(), "need to increase java_thread_min_stack_allowed calculation" ); |
231 | if (StackTraceInThrowable) { |
232 | java_lang_Throwable::fill_in_stack_trace(exception, method()); |
233 | } |
234 | // Increment counter for hs_err file reporting |
235 | Atomic::inc(&Exceptions::_stack_overflow_errors); |
236 | } else { |
237 | // if prior exception, throw that one instead |
238 | exception = Handle(THREAD, THREAD->pending_exception()); |
239 | } |
240 | _throw(THREAD, file, line, exception); |
241 | } |
242 | |
243 | void Exceptions::fthrow(Thread* thread, const char* file, int line, Symbol* h_name, const char* format, ...) { |
244 | const int max_msg_size = 1024; |
245 | va_list ap; |
246 | va_start(ap, format); |
247 | char msg[max_msg_size]; |
248 | os::vsnprintf(msg, max_msg_size, format, ap); |
249 | va_end(ap); |
250 | _throw_msg(thread, file, line, h_name, msg); |
251 | } |
252 | |
253 | |
254 | // Creates an exception oop, calls the <init> method with the given signature. |
255 | // and returns a Handle |
256 | Handle Exceptions::new_exception(Thread *thread, Symbol* name, |
257 | Symbol* signature, JavaCallArguments *args, |
258 | Handle h_loader, Handle h_protection_domain) { |
259 | assert(Universe::is_fully_initialized(), |
260 | "cannot be called during initialization" ); |
261 | assert(thread->is_Java_thread(), "can only be called by a Java thread" ); |
262 | assert(!thread->has_pending_exception(), "already has exception" ); |
263 | |
264 | Handle h_exception; |
265 | |
266 | // Resolve exception klass, and check for pending exception below. |
267 | Klass* klass = SystemDictionary::resolve_or_fail(name, h_loader, h_protection_domain, true, thread); |
268 | |
269 | if (!thread->has_pending_exception()) { |
270 | assert(klass != NULL, "klass must exist" ); |
271 | h_exception = JavaCalls::construct_new_instance(InstanceKlass::cast(klass), |
272 | signature, |
273 | args, |
274 | thread); |
275 | } |
276 | |
277 | // Check if another exception was thrown in the process, if so rethrow that one |
278 | if (thread->has_pending_exception()) { |
279 | h_exception = Handle(thread, thread->pending_exception()); |
280 | thread->clear_pending_exception(); |
281 | } |
282 | return h_exception; |
283 | } |
284 | |
285 | // Creates an exception oop, calls the <init> method with the given signature. |
286 | // and returns a Handle |
287 | // Initializes the cause if cause non-null |
288 | Handle Exceptions::new_exception(Thread *thread, Symbol* name, |
289 | Symbol* signature, JavaCallArguments *args, |
290 | Handle h_cause, |
291 | Handle h_loader, Handle h_protection_domain) { |
292 | Handle h_exception = new_exception(thread, name, signature, args, h_loader, h_protection_domain); |
293 | |
294 | // Future: object initializer should take a cause argument |
295 | if (h_cause.not_null()) { |
296 | assert(h_cause->is_a(SystemDictionary::Throwable_klass()), |
297 | "exception cause is not a subclass of java/lang/Throwable" ); |
298 | JavaValue result1(T_OBJECT); |
299 | JavaCallArguments args1; |
300 | args1.set_receiver(h_exception); |
301 | args1.push_oop(h_cause); |
302 | JavaCalls::call_virtual(&result1, h_exception->klass(), |
303 | vmSymbols::initCause_name(), |
304 | vmSymbols::throwable_throwable_signature(), |
305 | &args1, |
306 | thread); |
307 | } |
308 | |
309 | // Check if another exception was thrown in the process, if so rethrow that one |
310 | if (thread->has_pending_exception()) { |
311 | h_exception = Handle(thread, thread->pending_exception()); |
312 | thread->clear_pending_exception(); |
313 | } |
314 | return h_exception; |
315 | } |
316 | |
317 | // Convenience method. Calls either the <init>() or <init>(Throwable) method when |
318 | // creating a new exception |
319 | Handle Exceptions::new_exception(Thread* thread, Symbol* name, |
320 | Handle h_cause, |
321 | Handle h_loader, Handle h_protection_domain, |
322 | ExceptionMsgToUtf8Mode to_utf8_safe) { |
323 | JavaCallArguments args; |
324 | Symbol* signature = NULL; |
325 | if (h_cause.is_null()) { |
326 | signature = vmSymbols::void_method_signature(); |
327 | } else { |
328 | signature = vmSymbols::throwable_void_signature(); |
329 | args.push_oop(h_cause); |
330 | } |
331 | return new_exception(thread, name, signature, &args, h_loader, h_protection_domain); |
332 | } |
333 | |
334 | // Convenience method. Calls either the <init>() or <init>(String) method when |
335 | // creating a new exception |
336 | Handle Exceptions::new_exception(Thread* thread, Symbol* name, |
337 | const char* message, Handle h_cause, |
338 | Handle h_loader, Handle h_protection_domain, |
339 | ExceptionMsgToUtf8Mode to_utf8_safe) { |
340 | JavaCallArguments args; |
341 | Symbol* signature = NULL; |
342 | if (message == NULL) { |
343 | signature = vmSymbols::void_method_signature(); |
344 | } else { |
345 | // We want to allocate storage, but we can't do that if there's |
346 | // a pending exception, so we preserve any pending exception |
347 | // around the allocation. |
348 | // If we get an exception from the allocation, prefer that to |
349 | // the exception we are trying to build, or the pending exception. |
350 | // This is sort of like what PRESERVE_EXCEPTION_MARK does, except |
351 | // for the preferencing and the early returns. |
352 | Handle incoming_exception(thread, NULL); |
353 | if (thread->has_pending_exception()) { |
354 | incoming_exception = Handle(thread, thread->pending_exception()); |
355 | thread->clear_pending_exception(); |
356 | } |
357 | Handle msg; |
358 | if (to_utf8_safe == safe_to_utf8) { |
359 | // Make a java UTF8 string. |
360 | msg = java_lang_String::create_from_str(message, thread); |
361 | } else { |
362 | // Make a java string keeping the encoding scheme of the original string. |
363 | msg = java_lang_String::create_from_platform_dependent_str(message, thread); |
364 | } |
365 | if (thread->has_pending_exception()) { |
366 | Handle exception(thread, thread->pending_exception()); |
367 | thread->clear_pending_exception(); |
368 | return exception; |
369 | } |
370 | if (incoming_exception.not_null()) { |
371 | return incoming_exception; |
372 | } |
373 | args.push_oop(msg); |
374 | signature = vmSymbols::string_void_signature(); |
375 | } |
376 | return new_exception(thread, name, signature, &args, h_cause, h_loader, h_protection_domain); |
377 | } |
378 | |
379 | // Another convenience method that creates handles for null class loaders and |
380 | // protection domains and null causes. |
381 | // If the last parameter 'to_utf8_mode' is safe_to_utf8, |
382 | // it means we can safely ignore the encoding scheme of the message string and |
383 | // convert it directly to a java UTF8 string. Otherwise, we need to take the |
384 | // encoding scheme of the string into account. One thing we should do at some |
385 | // point is to push this flag down to class java_lang_String since other |
386 | // classes may need similar functionalities. |
387 | Handle Exceptions::new_exception(Thread* thread, Symbol* name, |
388 | const char* message, |
389 | ExceptionMsgToUtf8Mode to_utf8_safe) { |
390 | |
391 | Handle h_loader(thread, NULL); |
392 | Handle h_prot(thread, NULL); |
393 | Handle h_cause(thread, NULL); |
394 | return Exceptions::new_exception(thread, name, message, h_cause, h_loader, |
395 | h_prot, to_utf8_safe); |
396 | } |
397 | |
398 | // invokedynamic uses wrap_dynamic_exception for: |
399 | // - bootstrap method resolution |
400 | // - post call to MethodHandleNatives::linkCallSite |
401 | // dynamically computed constant uses wrap_dynamic_exception for: |
402 | // - bootstrap method resolution |
403 | // - post call to MethodHandleNatives::linkDynamicConstant |
404 | void Exceptions::wrap_dynamic_exception(Thread* THREAD) { |
405 | if (THREAD->has_pending_exception()) { |
406 | oop exception = THREAD->pending_exception(); |
407 | // See the "Linking Exceptions" section for the invokedynamic instruction |
408 | // in JVMS 6.5. |
409 | if (exception->is_a(SystemDictionary::Error_klass())) { |
410 | // Pass through an Error, including BootstrapMethodError, any other form |
411 | // of linkage error, or say ThreadDeath/OutOfMemoryError |
412 | if (TraceMethodHandles) { |
413 | tty->print_cr("bootstrap method invocation wraps BSME around " INTPTR_FORMAT, p2i((void *)exception)); |
414 | exception->print(); |
415 | } |
416 | return; |
417 | } |
418 | |
419 | // Otherwise wrap the exception in a BootstrapMethodError |
420 | if (TraceMethodHandles) { |
421 | tty->print_cr("[constant/invoke]dynamic throws BSME for " INTPTR_FORMAT, p2i((void *)exception)); |
422 | exception->print(); |
423 | } |
424 | Handle nested_exception(THREAD, exception); |
425 | THREAD->clear_pending_exception(); |
426 | THROW_CAUSE(vmSymbols::java_lang_BootstrapMethodError(), nested_exception) |
427 | } |
428 | } |
429 | |
430 | // Exception counting for hs_err file |
431 | volatile int Exceptions::_stack_overflow_errors = 0; |
432 | volatile int Exceptions::_linkage_errors = 0; |
433 | volatile int Exceptions::_out_of_memory_error_java_heap_errors = 0; |
434 | volatile int Exceptions::_out_of_memory_error_metaspace_errors = 0; |
435 | volatile int Exceptions::_out_of_memory_error_class_metaspace_errors = 0; |
436 | |
437 | void Exceptions::count_out_of_memory_exceptions(Handle exception) { |
438 | if (oopDesc::equals(exception(), Universe::out_of_memory_error_metaspace())) { |
439 | Atomic::inc(&_out_of_memory_error_metaspace_errors); |
440 | } else if (oopDesc::equals(exception(), Universe::out_of_memory_error_class_metaspace())) { |
441 | Atomic::inc(&_out_of_memory_error_class_metaspace_errors); |
442 | } else { |
443 | // everything else reported as java heap OOM |
444 | Atomic::inc(&_out_of_memory_error_java_heap_errors); |
445 | } |
446 | } |
447 | |
448 | void print_oom_count(outputStream* st, const char *err, int count) { |
449 | if (count > 0) { |
450 | st->print_cr("OutOfMemoryError %s=%d" , err, count); |
451 | } |
452 | } |
453 | |
454 | bool Exceptions::has_exception_counts() { |
455 | return (_stack_overflow_errors + _out_of_memory_error_java_heap_errors + |
456 | _out_of_memory_error_metaspace_errors + _out_of_memory_error_class_metaspace_errors) > 0; |
457 | } |
458 | |
459 | void Exceptions::print_exception_counts_on_error(outputStream* st) { |
460 | print_oom_count(st, "java_heap_errors" , _out_of_memory_error_java_heap_errors); |
461 | print_oom_count(st, "metaspace_errors" , _out_of_memory_error_metaspace_errors); |
462 | print_oom_count(st, "class_metaspace_errors" , _out_of_memory_error_class_metaspace_errors); |
463 | if (_stack_overflow_errors > 0) { |
464 | st->print_cr("StackOverflowErrors=%d" , _stack_overflow_errors); |
465 | } |
466 | if (_linkage_errors > 0) { |
467 | st->print_cr("LinkageErrors=%d" , _linkage_errors); |
468 | } |
469 | } |
470 | |
471 | // Implementation of ExceptionMark |
472 | |
473 | ExceptionMark::ExceptionMark(Thread*& thread) { |
474 | thread = Thread::current(); |
475 | _thread = thread; |
476 | if (_thread->has_pending_exception()) { |
477 | oop exception = _thread->pending_exception(); |
478 | _thread->clear_pending_exception(); // Needed to avoid infinite recursion |
479 | exception->print(); |
480 | fatal("ExceptionMark constructor expects no pending exceptions" ); |
481 | } |
482 | } |
483 | |
484 | |
485 | ExceptionMark::~ExceptionMark() { |
486 | if (_thread->has_pending_exception()) { |
487 | Handle exception(_thread, _thread->pending_exception()); |
488 | _thread->clear_pending_exception(); // Needed to avoid infinite recursion |
489 | if (is_init_completed()) { |
490 | exception->print(); |
491 | fatal("ExceptionMark destructor expects no pending exceptions" ); |
492 | } else { |
493 | vm_exit_during_initialization(exception); |
494 | } |
495 | } |
496 | } |
497 | |
498 | // ---------------------------------------------------------------------------------------- |
499 | |
500 | // caller frees value_string if necessary |
501 | void Exceptions::debug_check_abort(const char *value_string, const char* message) { |
502 | if (AbortVMOnException != NULL && value_string != NULL && |
503 | strstr(value_string, AbortVMOnException)) { |
504 | if (AbortVMOnExceptionMessage == NULL || (message != NULL && |
505 | strstr(message, AbortVMOnExceptionMessage))) { |
506 | fatal("Saw %s, aborting" , value_string); |
507 | } |
508 | } |
509 | } |
510 | |
511 | void Exceptions::debug_check_abort(Handle exception, const char* message) { |
512 | if (AbortVMOnException != NULL) { |
513 | debug_check_abort_helper(exception, message); |
514 | } |
515 | } |
516 | |
517 | void Exceptions::debug_check_abort_helper(Handle exception, const char* message) { |
518 | ResourceMark rm; |
519 | if (message == NULL && exception->is_a(SystemDictionary::Throwable_klass())) { |
520 | oop msg = java_lang_Throwable::message(exception()); |
521 | if (msg != NULL) { |
522 | message = java_lang_String::as_utf8_string(msg); |
523 | } |
524 | } |
525 | debug_check_abort(exception()->klass()->external_name(), message); |
526 | } |
527 | |
528 | // for logging exceptions |
529 | void Exceptions::log_exception(Handle exception, const char* message) { |
530 | ResourceMark rm; |
531 | Symbol* detail_message = java_lang_Throwable::detail_message(exception()); |
532 | if (detail_message != NULL) { |
533 | log_info(exceptions)("Exception <%s: %s>\n thrown in %s" , |
534 | exception->print_value_string(), |
535 | detail_message->as_C_string(), |
536 | message); |
537 | } else { |
538 | log_info(exceptions)("Exception <%s>\n thrown in %s" , |
539 | exception->print_value_string(), |
540 | message); |
541 | } |
542 | } |
543 | |