Thu, 20 Nov 2008 16:56:09 -0800
6684579: SoftReference processing can be made more efficient
Summary: For current soft-ref clearing policies, we can decide at marking time if a soft-reference will definitely not be cleared, postponing the decision of whether it will definitely be cleared to the final reference processing phase. This can be especially beneficial in the case of concurrent collectors where the marking is usually concurrent but reference processing is usually not.
Reviewed-by: jmasa
1 /*
2 * Copyright 1998-2007 Sun Microsystems, Inc. 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 Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
20 * CA 95054 USA or visit www.sun.com if you need additional information or
21 * have any questions.
22 *
23 */
25 #include "incls/_precompiled.incl"
26 #include "incls/_exceptions.cpp.incl"
29 // Implementation of ThreadShadow
30 void check_ThreadShadow() {
31 const ByteSize offset1 = byte_offset_of(ThreadShadow, _pending_exception);
32 const ByteSize offset2 = Thread::pending_exception_offset();
33 if (offset1 != offset2) fatal("ThreadShadow::_pending_exception is not positioned correctly");
34 }
37 void ThreadShadow::set_pending_exception(oop exception, const char* file, int line) {
38 assert(exception != NULL && exception->is_oop(), "invalid exception oop");
39 _pending_exception = exception;
40 _exception_file = file;
41 _exception_line = line;
42 }
44 void ThreadShadow::clear_pending_exception() {
45 if (TraceClearedExceptions) {
46 if (_pending_exception != NULL) {
47 tty->print_cr("Thread::clear_pending_exception: cleared exception:");
48 _pending_exception->print();
49 }
50 }
51 _pending_exception = NULL;
52 _exception_file = NULL;
53 _exception_line = 0;
54 }
55 // Implementation of Exceptions
57 bool Exceptions::special_exception(Thread* thread, const char* file, int line, Handle h_exception) {
58 // bootstrapping check
59 if (!Universe::is_fully_initialized()) {
60 vm_exit_during_initialization(h_exception);
61 ShouldNotReachHere();
62 }
64 if (thread->is_VM_thread()
65 || thread->is_Compiler_thread() ) {
66 // We do not care what kind of exception we get for the vm-thread or a thread which
67 // is compiling. We just install a dummy exception object
68 thread->set_pending_exception(Universe::vm_exception(), file, line);
69 return true;
70 }
72 return false;
73 }
75 bool Exceptions::special_exception(Thread* thread, const char* file, int line, symbolHandle h_name, const char* message) {
76 // bootstrapping check
77 if (!Universe::is_fully_initialized()) {
78 if (h_name.is_null()) {
79 // atleast an informative message.
80 vm_exit_during_initialization("Exception", message);
81 } else {
82 vm_exit_during_initialization(h_name, message);
83 }
84 ShouldNotReachHere();
85 }
87 if (thread->is_VM_thread()
88 || thread->is_Compiler_thread() ) {
89 // We do not care what kind of exception we get for the vm-thread or a thread which
90 // is compiling. We just install a dummy exception object
91 thread->set_pending_exception(Universe::vm_exception(), file, line);
92 return true;
93 }
95 return false;
96 }
98 // This method should only be called from generated code,
99 // therefore the exception oop should be in the oopmap.
100 void Exceptions::_throw_oop(Thread* thread, const char* file, int line, oop exception) {
101 assert(exception != NULL, "exception should not be NULL");
102 Handle h_exception = Handle(thread, exception);
103 _throw(thread, file, line, h_exception);
104 }
106 void Exceptions::_throw(Thread* thread, const char* file, int line, Handle h_exception) {
107 assert(h_exception() != NULL, "exception should not be NULL");
109 // tracing (do this up front - so it works during boot strapping)
110 if (TraceExceptions) {
111 ttyLocker ttyl;
112 ResourceMark rm;
113 tty->print_cr("Exception <%s> (" INTPTR_FORMAT " ) \nthrown [%s, line %d]\nfor thread " INTPTR_FORMAT,
114 h_exception->print_value_string(), (address)h_exception(), file, line, thread);
115 }
116 // for AbortVMOnException flag
117 NOT_PRODUCT(Exceptions::debug_check_abort(h_exception));
119 // Check for special boot-strapping/vm-thread handling
120 if (special_exception(thread, file, line, h_exception)) return;
122 assert(h_exception->is_a(SystemDictionary::throwable_klass()), "exception is not a subclass of java/lang/Throwable");
124 // set the pending exception
125 thread->set_pending_exception(h_exception(), file, line);
127 // vm log
128 Events::log("throw_exception " INTPTR_FORMAT, (address)h_exception());
129 }
132 void Exceptions::_throw_msg(Thread* thread, const char* file, int line, symbolHandle h_name, const char* message, Handle h_loader, Handle h_protection_domain) {
133 // Check for special boot-strapping/vm-thread handling
134 if (special_exception(thread, file, line, h_name, message)) return;
135 // Create and throw exception
136 Handle h_cause(thread, NULL);
137 Handle h_exception = new_exception(thread, h_name, message, h_cause, h_loader, h_protection_domain);
138 _throw(thread, file, line, h_exception);
139 }
141 // Throw an exception with a message and a cause
142 void Exceptions::_throw_msg_cause(Thread* thread, const char* file, int line, symbolHandle h_name, const char* message, Handle h_cause, Handle h_loader, Handle h_protection_domain) {
143 // Check for special boot-strapping/vm-thread handling
144 if (special_exception(thread, file, line, h_name, message)) return;
145 // Create and throw exception and init cause
146 Handle h_exception = new_exception(thread, h_name, message, h_cause, h_loader, h_protection_domain);
147 _throw(thread, file, line, h_exception);
148 }
150 // This version creates handles and calls the other version
151 void Exceptions::_throw_msg(Thread* thread, const char* file, int line,
152 symbolOop name, const char* message) {
153 symbolHandle h_name(thread, name);
154 Handle h_loader(thread, NULL);
155 Handle h_protection_domain(thread, NULL);
156 Exceptions::_throw_msg(thread, file, line, h_name, message, h_loader, h_protection_domain);
157 }
159 // This version already has a handle for name
160 void Exceptions::_throw_msg(Thread* thread, const char* file, int line,
161 symbolHandle name, const char* message) {
162 Handle h_loader(thread, NULL);
163 Handle h_protection_domain(thread, NULL);
164 Exceptions::_throw_msg(thread, file, line, name, message, h_loader, h_protection_domain);
165 }
167 // This version already has a handle for name
168 void Exceptions::_throw_msg_cause(Thread* thread, const char* file, int line,
169 symbolHandle name, const char* message, Handle cause) {
170 Handle h_loader(thread, NULL);
171 Handle h_protection_domain(thread, NULL);
172 Exceptions::_throw_msg_cause(thread, file, line, name, message, cause, h_loader, h_protection_domain);
173 }
175 void Exceptions::_throw_args(Thread* thread, const char* file, int line, symbolHandle h_name, symbolHandle h_signature, JavaCallArguments *args) {
176 // Check for special boot-strapping/vm-thread handling
177 if (special_exception(thread, file, line, h_name, NULL)) return;
178 // Create and throw exception
179 Handle h_loader(thread, NULL);
180 Handle h_prot(thread, NULL);
181 Handle h_cause(thread, NULL);
182 Handle exception = new_exception(thread, h_name, h_signature, args, h_cause, h_loader, h_prot);
183 _throw(thread, file, line, exception);
184 }
187 void Exceptions::throw_stack_overflow_exception(Thread* THREAD, const char* file, int line) {
188 Handle exception;
189 if (!THREAD->has_pending_exception()) {
190 klassOop k = SystemDictionary::StackOverflowError_klass();
191 oop e = instanceKlass::cast(k)->allocate_instance(CHECK);
192 exception = Handle(THREAD, e); // fill_in_stack trace does gc
193 if (StackTraceInThrowable) {
194 java_lang_Throwable::fill_in_stack_trace(exception);
195 }
196 } else {
197 // if prior exception, throw that one instead
198 exception = Handle(THREAD, THREAD->pending_exception());
199 }
200 _throw_oop(THREAD, file, line, exception());
201 }
203 void Exceptions::fthrow(Thread* thread, const char* file, int line, symbolHandle h_name, const char* format, ...) {
204 const int max_msg_size = 1024;
205 va_list ap;
206 va_start(ap, format);
207 char msg[max_msg_size];
208 vsnprintf(msg, max_msg_size, format, ap);
209 msg[max_msg_size-1] = '\0';
210 va_end(ap);
211 _throw_msg(thread, file, line, h_name, msg);
212 }
214 // Creates an exception oop, calls the <init> method with the given signature.
215 // and returns a Handle
216 // Initializes the cause if cause non-null
217 Handle Exceptions::new_exception(Thread *thread, symbolHandle h_name,
218 symbolHandle signature,
219 JavaCallArguments *args,
220 Handle h_cause, Handle h_loader,
221 Handle h_protection_domain) {
222 assert(Universe::is_fully_initialized(),
223 "cannot be called during initialization");
224 assert(thread->is_Java_thread(), "can only be called by a Java thread");
225 assert(!thread->has_pending_exception(), "already has exception");
227 Handle h_exception;
229 // Resolve exception klass
230 klassOop ik = SystemDictionary::resolve_or_fail(h_name, h_loader, h_protection_domain, true, thread);
231 instanceKlassHandle klass (thread, ik);
233 if (!thread->has_pending_exception()) {
234 assert(klass.not_null(), "klass must exist");
235 // We are about to create an instance - so make sure that klass is initialized
236 klass->initialize(thread);
237 if (!thread->has_pending_exception()) {
238 // Allocate new exception
239 h_exception = klass->allocate_instance_handle(thread);
240 if (!thread->has_pending_exception()) {
241 JavaValue result(T_VOID);
242 args->set_receiver(h_exception);
243 // Call constructor
244 JavaCalls::call_special(&result, klass,
245 vmSymbolHandles::object_initializer_name(),
246 signature,
247 args,
248 thread);
250 }
251 }
253 // Future: object initializer should take a cause argument
254 if (h_cause() != NULL) {
255 assert(h_cause->is_a(SystemDictionary::throwable_klass()),
256 "exception cause is not a subclass of java/lang/Throwable");
257 JavaValue result1(T_OBJECT);
258 JavaCallArguments args1;
259 args1.set_receiver(h_exception);
260 args1.push_oop(h_cause);
261 JavaCalls::call_virtual(&result1, klass,
262 vmSymbolHandles::initCause_name(),
263 vmSymbolHandles::throwable_throwable_signature(),
264 &args1,
265 thread);
266 }
267 }
269 // Check if another exception was thrown in the process, if so rethrow that one
270 if (thread->has_pending_exception()) {
271 h_exception = Handle(thread, thread->pending_exception());
272 thread->clear_pending_exception();
273 }
274 return h_exception;
275 }
277 // Convenience method. Calls either the <init>() or <init>(String) method when
278 // creating a new exception
279 Handle Exceptions::new_exception(Thread* thread, symbolHandle h_name,
280 const char* message, Handle h_cause,
281 Handle h_loader,
282 Handle h_protection_domain,
283 ExceptionMsgToUtf8Mode to_utf8_safe) {
284 JavaCallArguments args;
285 symbolHandle signature;
286 if (message == NULL) {
287 signature = vmSymbolHandles::void_method_signature();
288 } else {
289 // We want to allocate storage, but we can't do that if there's
290 // a pending exception, so we preserve any pending exception
291 // around the allocation.
292 // If we get an exception from the allocation, prefer that to
293 // the exception we are trying to build, or the pending exception.
294 // This is sort of like what PRESERVE_EXCEPTION_MARK does, except
295 // for the preferencing and the early returns.
296 Handle incoming_exception (thread, NULL);
297 if (thread->has_pending_exception()) {
298 incoming_exception = Handle(thread, thread->pending_exception());
299 thread->clear_pending_exception();
300 }
301 Handle msg;
302 if (to_utf8_safe == safe_to_utf8) {
303 // Make a java UTF8 string.
304 msg = java_lang_String::create_from_str(message, thread);
305 } else {
306 // Make a java string keeping the encoding scheme of the original string.
307 msg = java_lang_String::create_from_platform_dependent_str(message, thread);
308 }
309 if (thread->has_pending_exception()) {
310 Handle exception(thread, thread->pending_exception());
311 thread->clear_pending_exception();
312 return exception;
313 }
314 if (incoming_exception.not_null()) {
315 return incoming_exception;
316 }
317 args.push_oop(msg);
318 signature = vmSymbolHandles::string_void_signature();
319 }
320 return new_exception(thread, h_name, signature, &args, h_cause, h_loader, h_protection_domain);
321 }
323 // Another convenience method that creates handles for null class loaders and
324 // protection domains and null causes.
325 // If the last parameter 'to_utf8_mode' is safe_to_utf8,
326 // it means we can safely ignore the encoding scheme of the message string and
327 // convert it directly to a java UTF8 string. Otherwise, we need to take the
328 // encoding scheme of the string into account. One thing we should do at some
329 // point is to push this flag down to class java_lang_String since other
330 // classes may need similar functionalities.
331 Handle Exceptions::new_exception(Thread* thread,
332 symbolOop name,
333 const char* message,
334 ExceptionMsgToUtf8Mode to_utf8_safe) {
336 symbolHandle h_name(thread, name);
337 Handle h_loader(thread, NULL);
338 Handle h_prot(thread, NULL);
339 Handle h_cause(thread, NULL);
340 return Exceptions::new_exception(thread, h_name, message, h_cause, h_loader,
341 h_prot, to_utf8_safe);
342 }
344 // Implementation of ExceptionMark
346 ExceptionMark::ExceptionMark(Thread*& thread) {
347 thread = Thread::current();
348 _thread = thread;
349 if (_thread->has_pending_exception()) {
350 oop exception = _thread->pending_exception();
351 _thread->clear_pending_exception(); // Needed to avoid infinite recursion
352 exception->print();
353 fatal("ExceptionMark constructor expects no pending exceptions");
354 }
355 }
358 ExceptionMark::~ExceptionMark() {
359 if (_thread->has_pending_exception()) {
360 Handle exception(_thread, _thread->pending_exception());
361 _thread->clear_pending_exception(); // Needed to avoid infinite recursion
362 if (is_init_completed()) {
363 exception->print();
364 fatal("ExceptionMark destructor expects no pending exceptions");
365 } else {
366 vm_exit_during_initialization(exception);
367 }
368 }
369 }
371 // ----------------------------------------------------------------------------------------
373 #ifndef PRODUCT
374 // caller frees value_string if necessary
375 void Exceptions::debug_check_abort(const char *value_string) {
376 if (AbortVMOnException != NULL && value_string != NULL &&
377 strstr(value_string, AbortVMOnException)) {
378 fatal1("Saw %s, aborting", value_string);
379 }
380 }
382 void Exceptions::debug_check_abort(Handle exception) {
383 if (AbortVMOnException != NULL) {
384 ResourceMark rm;
385 debug_check_abort(instanceKlass::cast(exception()->klass())->external_name());
386 }
387 }
388 #endif