21 * questions. |
21 * questions. |
22 * |
22 * |
23 */ |
23 */ |
24 |
24 |
25 #include "precompiled.hpp" |
25 #include "precompiled.hpp" |
26 #include "classfile/systemDictionary.hpp" |
26 #include "gc/shared/oopStorage.hpp" |
27 #include "logging/log.hpp" |
27 #include "logging/log.hpp" |
28 #include "memory/iterator.hpp" |
28 #include "memory/iterator.hpp" |
29 #include "oops/oop.inline.hpp" |
29 #include "oops/oop.inline.hpp" |
30 #include "runtime/jniHandles.hpp" |
30 #include "runtime/jniHandles.hpp" |
31 #include "runtime/mutexLocker.hpp" |
31 #include "runtime/mutexLocker.hpp" |
32 #include "runtime/thread.inline.hpp" |
32 #include "runtime/thread.inline.hpp" |
33 #include "trace/traceMacros.hpp" |
33 #include "trace/traceMacros.hpp" |
34 #include "utilities/align.hpp" |
34 #include "utilities/align.hpp" |
|
35 #include "utilities/debug.hpp" |
35 #if INCLUDE_ALL_GCS |
36 #if INCLUDE_ALL_GCS |
36 #include "gc/g1/g1SATBCardTableModRefBS.hpp" |
37 #include "gc/g1/g1SATBCardTableModRefBS.hpp" |
37 #endif |
38 #endif |
38 |
39 |
39 JNIHandleBlock* JNIHandles::_global_handles = NULL; |
40 OopStorage* JNIHandles::_global_handles = NULL; |
40 JNIHandleBlock* JNIHandles::_weak_global_handles = NULL; |
41 OopStorage* JNIHandles::_weak_global_handles = NULL; |
41 oop JNIHandles::_deleted_handle = NULL; |
|
42 |
42 |
43 |
43 |
44 jobject JNIHandles::make_local(oop obj) { |
44 jobject JNIHandles::make_local(oop obj) { |
45 if (obj == NULL) { |
45 if (obj == NULL) { |
46 return NULL; // ignore null handles |
46 return NULL; // ignore null handles |
47 } else { |
47 } else { |
48 Thread* thread = Thread::current(); |
48 Thread* thread = Thread::current(); |
49 assert(Universe::heap()->is_in_reserved(obj), "sanity check"); |
49 assert(oopDesc::is_oop(obj), "not an oop"); |
50 assert(!current_thread_in_native(), "must not be in native"); |
50 assert(!current_thread_in_native(), "must not be in native"); |
51 return thread->active_handles()->allocate_handle(obj); |
51 return thread->active_handles()->allocate_handle(obj); |
52 } |
52 } |
53 } |
53 } |
54 |
54 |
70 jobject JNIHandles::make_local(JNIEnv* env, oop obj) { |
70 jobject JNIHandles::make_local(JNIEnv* env, oop obj) { |
71 if (obj == NULL) { |
71 if (obj == NULL) { |
72 return NULL; // ignore null handles |
72 return NULL; // ignore null handles |
73 } else { |
73 } else { |
74 JavaThread* thread = JavaThread::thread_from_jni_environment(env); |
74 JavaThread* thread = JavaThread::thread_from_jni_environment(env); |
75 assert(Universe::heap()->is_in_reserved(obj), "sanity check"); |
75 assert(oopDesc::is_oop(obj), "not an oop"); |
76 assert(!current_thread_in_native(), "must not be in native"); |
76 assert(!current_thread_in_native(), "must not be in native"); |
77 return thread->active_handles()->allocate_handle(obj); |
77 return thread->active_handles()->allocate_handle(obj); |
78 } |
78 } |
79 } |
79 } |
80 |
80 |
81 |
81 |
82 jobject JNIHandles::make_global(Handle obj) { |
82 static void report_handle_allocation_failure(AllocFailType alloc_failmode, |
|
83 const char* handle_kind) { |
|
84 if (alloc_failmode == AllocFailStrategy::EXIT_OOM) { |
|
85 // Fake size value, since we don't know the min allocation size here. |
|
86 vm_exit_out_of_memory(sizeof(oop), OOM_MALLOC_ERROR, |
|
87 "Cannot create %s JNI handle", handle_kind); |
|
88 } else { |
|
89 assert(alloc_failmode == AllocFailStrategy::RETURN_NULL, "invariant"); |
|
90 } |
|
91 } |
|
92 |
|
93 jobject JNIHandles::make_global(Handle obj, AllocFailType alloc_failmode) { |
83 assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); |
94 assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); |
84 assert(!current_thread_in_native(), "must not be in native"); |
95 assert(!current_thread_in_native(), "must not be in native"); |
85 jobject res = NULL; |
96 jobject res = NULL; |
86 if (!obj.is_null()) { |
97 if (!obj.is_null()) { |
87 // ignore null handles |
98 // ignore null handles |
88 MutexLocker ml(JNIGlobalHandle_lock); |
99 assert(oopDesc::is_oop(obj()), "not an oop"); |
89 assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); |
100 oop* ptr = _global_handles->allocate(); |
90 res = _global_handles->allocate_handle(obj()); |
101 // Return NULL on allocation failure. |
|
102 if (ptr != NULL) { |
|
103 *ptr = obj(); |
|
104 res = reinterpret_cast<jobject>(ptr); |
|
105 } else { |
|
106 report_handle_allocation_failure(alloc_failmode, "global"); |
|
107 } |
91 } else { |
108 } else { |
92 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); |
109 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); |
93 } |
110 } |
94 |
111 |
95 return res; |
112 return res; |
96 } |
113 } |
97 |
114 |
98 |
115 |
99 jobject JNIHandles::make_weak_global(Handle obj) { |
116 jobject JNIHandles::make_weak_global(Handle obj, AllocFailType alloc_failmode) { |
100 assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); |
117 assert(!Universe::heap()->is_gc_active(), "can't extend the root set during GC"); |
101 assert(!current_thread_in_native(), "must not be in native"); |
118 assert(!current_thread_in_native(), "must not be in native"); |
102 jobject res = NULL; |
119 jobject res = NULL; |
103 if (!obj.is_null()) { |
120 if (!obj.is_null()) { |
104 // ignore null handles |
121 // ignore null handles |
105 { |
122 assert(oopDesc::is_oop(obj()), "not an oop"); |
106 MutexLocker ml(JNIGlobalHandle_lock); |
123 oop* ptr = _weak_global_handles->allocate(); |
107 assert(Universe::heap()->is_in_reserved(obj()), "sanity check"); |
124 // Return NULL on allocation failure. |
108 res = _weak_global_handles->allocate_handle(obj()); |
125 if (ptr != NULL) { |
109 } |
126 *ptr = obj(); |
110 // Add weak tag. |
127 char* tptr = reinterpret_cast<char*>(ptr) + weak_tag_value; |
111 assert(is_aligned(res, weak_tag_alignment), "invariant"); |
128 res = reinterpret_cast<jobject>(tptr); |
112 char* tptr = reinterpret_cast<char*>(res) + weak_tag_value; |
129 } else { |
113 res = reinterpret_cast<jobject>(tptr); |
130 report_handle_allocation_failure(alloc_failmode, "weak global"); |
|
131 } |
114 } else { |
132 } else { |
115 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); |
133 CHECK_UNHANDLED_OOPS_ONLY(Thread::current()->clear_unhandled_oops()); |
116 } |
134 } |
117 return res; |
135 return res; |
118 } |
136 } |
119 |
137 |
120 template<bool external_guard> |
|
121 oop JNIHandles::resolve_jweak(jweak handle) { |
138 oop JNIHandles::resolve_jweak(jweak handle) { |
122 assert(is_jweak(handle), "precondition"); |
139 assert(is_jweak(handle), "precondition"); |
123 oop result = jweak_ref(handle); |
140 oop result = jweak_ref(handle); |
124 result = guard_value<external_guard>(result); |
|
125 #if INCLUDE_ALL_GCS |
141 #if INCLUDE_ALL_GCS |
126 if (result != NULL && UseG1GC) { |
142 if (result != NULL && UseG1GC) { |
127 G1SATBCardTableModRefBS::enqueue(result); |
143 G1SATBCardTableModRefBS::enqueue(result); |
128 } |
144 } |
129 #endif // INCLUDE_ALL_GCS |
145 #endif // INCLUDE_ALL_GCS |
130 return result; |
146 return result; |
131 } |
147 } |
132 |
148 |
133 template oop JNIHandles::resolve_jweak<true>(jweak); |
|
134 template oop JNIHandles::resolve_jweak<false>(jweak); |
|
135 |
|
136 bool JNIHandles::is_global_weak_cleared(jweak handle) { |
149 bool JNIHandles::is_global_weak_cleared(jweak handle) { |
137 assert(is_jweak(handle), "not a weak handle"); |
150 assert(is_jweak(handle), "not a weak handle"); |
138 return guard_value<false>(jweak_ref(handle)) == NULL; |
151 return jweak_ref(handle) == NULL; |
139 } |
152 } |
140 |
153 |
141 void JNIHandles::destroy_global(jobject handle) { |
154 void JNIHandles::destroy_global(jobject handle) { |
142 if (handle != NULL) { |
155 if (handle != NULL) { |
143 assert(is_global_handle(handle), "Invalid delete of global JNI handle"); |
156 assert(!is_jweak(handle), "wrong method for detroying jweak"); |
144 jobject_ref(handle) = deleted_handle(); |
157 jobject_ref(handle) = NULL; |
|
158 _global_handles->release(&jobject_ref(handle)); |
145 } |
159 } |
146 } |
160 } |
147 |
161 |
148 |
162 |
149 void JNIHandles::destroy_weak_global(jobject handle) { |
163 void JNIHandles::destroy_weak_global(jobject handle) { |
150 if (handle != NULL) { |
164 if (handle != NULL) { |
151 jweak_ref(handle) = deleted_handle(); |
165 assert(is_jweak(handle), "JNI handle not jweak"); |
|
166 jweak_ref(handle) = NULL; |
|
167 _weak_global_handles->release(&jweak_ref(handle)); |
152 } |
168 } |
153 } |
169 } |
154 |
170 |
155 |
171 |
156 void JNIHandles::oops_do(OopClosure* f) { |
172 void JNIHandles::oops_do(OopClosure* f) { |
157 f->do_oop(&_deleted_handle); |
|
158 _global_handles->oops_do(f); |
173 _global_handles->oops_do(f); |
159 } |
174 } |
160 |
175 |
161 |
176 |
162 void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { |
177 void JNIHandles::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* f) { |
163 _weak_global_handles->weak_oops_do(is_alive, f); |
178 _weak_global_handles->weak_oops_do(is_alive, f); |
164 } |
179 } |
165 |
180 |
166 |
181 |
167 void JNIHandles::weak_oops_do(OopClosure* f) { |
182 void JNIHandles::weak_oops_do(OopClosure* f) { |
168 AlwaysTrueClosure always_true; |
183 _weak_global_handles->weak_oops_do(f); |
169 weak_oops_do(&always_true, f); |
|
170 } |
184 } |
171 |
185 |
172 |
186 |
173 void JNIHandles::initialize() { |
187 void JNIHandles::initialize() { |
174 _global_handles = JNIHandleBlock::allocate_block(); |
188 _global_handles = new OopStorage("JNI Global", |
175 _weak_global_handles = JNIHandleBlock::allocate_block(); |
189 JNIGlobalAlloc_lock, |
176 EXCEPTION_MARK; |
190 JNIGlobalActive_lock); |
177 // We will never reach the CATCH below since Exceptions::_throw will cause |
191 _weak_global_handles = new OopStorage("JNI Weak", |
178 // the VM to exit if an exception is thrown during initialization |
192 JNIWeakAlloc_lock, |
179 Klass* k = SystemDictionary::Object_klass(); |
193 JNIWeakActive_lock); |
180 _deleted_handle = InstanceKlass::cast(k)->allocate_instance(CATCH); |
194 } |
|
195 |
|
196 |
|
197 inline bool is_storage_handle(const OopStorage* storage, const oop* ptr) { |
|
198 return storage->allocation_status(ptr) == OopStorage::ALLOCATED_ENTRY; |
|
199 } |
|
200 |
|
201 |
|
202 jobjectRefType JNIHandles::handle_type(Thread* thread, jobject handle) { |
|
203 jobjectRefType result = JNIInvalidRefType; |
|
204 if (is_jweak(handle)) { |
|
205 if (is_storage_handle(_weak_global_handles, &jweak_ref(handle))) { |
|
206 result = JNIWeakGlobalRefType; |
|
207 } |
|
208 } else { |
|
209 switch (_global_handles->allocation_status(&jobject_ref(handle))) { |
|
210 case OopStorage::ALLOCATED_ENTRY: |
|
211 result = JNIGlobalRefType; |
|
212 break; |
|
213 |
|
214 case OopStorage::UNALLOCATED_ENTRY: |
|
215 break; // Invalid global handle |
|
216 |
|
217 case OopStorage::INVALID_ENTRY: |
|
218 // Not in global storage. Might be a local handle. |
|
219 if (is_local_handle(thread, handle) || |
|
220 (thread->is_Java_thread() && |
|
221 is_frame_handle((JavaThread*)thread, handle))) { |
|
222 result = JNILocalRefType; |
|
223 } |
|
224 break; |
|
225 |
|
226 default: |
|
227 ShouldNotReachHere(); |
|
228 } |
|
229 } |
|
230 return result; |
181 } |
231 } |
182 |
232 |
183 |
233 |
184 bool JNIHandles::is_local_handle(Thread* thread, jobject handle) { |
234 bool JNIHandles::is_local_handle(Thread* thread, jobject handle) { |
185 JNIHandleBlock* block = thread->active_handles(); |
235 JNIHandleBlock* block = thread->active_handles(); |
208 (void*)obj >= (void*)thr->last_Java_sp()); |
258 (void*)obj >= (void*)thr->last_Java_sp()); |
209 } |
259 } |
210 |
260 |
211 |
261 |
212 bool JNIHandles::is_global_handle(jobject handle) { |
262 bool JNIHandles::is_global_handle(jobject handle) { |
213 return _global_handles->chain_contains(handle); |
263 return !is_jweak(handle) && is_storage_handle(_global_handles, &jobject_ref(handle)); |
214 } |
264 } |
215 |
265 |
216 |
266 |
217 bool JNIHandles::is_weak_global_handle(jobject handle) { |
267 bool JNIHandles::is_weak_global_handle(jobject handle) { |
218 return _weak_global_handles->chain_contains(handle); |
268 return is_jweak(handle) && is_storage_handle(_weak_global_handles, &jweak_ref(handle)); |
219 } |
269 } |
220 |
270 |
221 long JNIHandles::global_handle_memory_usage() { |
271 size_t JNIHandles::global_handle_memory_usage() { |
222 return _global_handles->memory_usage(); |
272 return _global_handles->total_memory_usage(); |
223 } |
273 } |
224 |
274 |
225 long JNIHandles::weak_global_handle_memory_usage() { |
275 size_t JNIHandles::weak_global_handle_memory_usage() { |
226 return _weak_global_handles->memory_usage(); |
276 return _weak_global_handles->total_memory_usage(); |
227 } |
277 } |
228 |
278 |
229 |
|
230 class CountHandleClosure: public OopClosure { |
|
231 private: |
|
232 int _count; |
|
233 public: |
|
234 CountHandleClosure(): _count(0) {} |
|
235 virtual void do_oop(oop* ooph) { |
|
236 if (*ooph != JNIHandles::deleted_handle()) { |
|
237 _count++; |
|
238 } |
|
239 } |
|
240 virtual void do_oop(narrowOop* unused) { ShouldNotReachHere(); } |
|
241 int count() { return _count; } |
|
242 }; |
|
243 |
279 |
244 // We assume this is called at a safepoint: no lock is needed. |
280 // We assume this is called at a safepoint: no lock is needed. |
245 void JNIHandles::print_on(outputStream* st) { |
281 void JNIHandles::print_on(outputStream* st) { |
246 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
282 assert(SafepointSynchronize::is_at_safepoint(), "must be at safepoint"); |
247 assert(_global_handles != NULL && _weak_global_handles != NULL, |
283 assert(_global_handles != NULL && _weak_global_handles != NULL, |
248 "JNIHandles not initialized"); |
284 "JNIHandles not initialized"); |
249 |
285 |
250 CountHandleClosure global_handle_count; |
286 st->print_cr("JNI global refs: " SIZE_FORMAT ", weak refs: " SIZE_FORMAT, |
251 oops_do(&global_handle_count); |
287 _global_handles->allocation_count(), |
252 weak_oops_do(&global_handle_count); |
288 _weak_global_handles->allocation_count()); |
253 |
|
254 st->print_cr("JNI global references: %d", global_handle_count.count()); |
|
255 st->cr(); |
289 st->cr(); |
256 st->flush(); |
290 st->flush(); |
257 } |
291 } |
258 |
292 |
259 class VerifyHandleClosure: public OopClosure { |
293 class VerifyJNIHandles: public OopClosure { |
260 public: |
294 public: |
261 virtual void do_oop(oop* root) { |
295 virtual void do_oop(oop* root) { |
262 (*root)->verify(); |
296 (*root)->verify(); |
263 } |
297 } |
264 virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); } |
298 virtual void do_oop(narrowOop* root) { ShouldNotReachHere(); } |
265 }; |
299 }; |
266 |
300 |
267 void JNIHandles::verify() { |
301 void JNIHandles::verify() { |
268 VerifyHandleClosure verify_handle; |
302 VerifyJNIHandles verify_handle; |
269 |
303 |
270 oops_do(&verify_handle); |
304 oops_do(&verify_handle); |
271 weak_oops_do(&verify_handle); |
305 weak_oops_do(&verify_handle); |
272 } |
306 } |
273 |
307 |