144 * Helper class for accessing memory. |
144 * Helper class for accessing memory. |
145 * |
145 * |
146 * Normalizes values and wraps accesses in |
146 * Normalizes values and wraps accesses in |
147 * JavaThread::doing_unsafe_access() if needed. |
147 * JavaThread::doing_unsafe_access() if needed. |
148 */ |
148 */ |
|
149 template <typename T> |
149 class MemoryAccess : StackObj { |
150 class MemoryAccess : StackObj { |
150 JavaThread* _thread; |
151 JavaThread* _thread; |
151 oop _obj; |
152 oop _obj; |
152 ptrdiff_t _offset; |
153 ptrdiff_t _offset; |
153 |
154 |
154 // Resolves and returns the address of the memory access |
155 // Resolves and returns the address of the memory access. |
155 void* addr() { |
156 // This raw memory access may fault, so we make sure it happens within the |
156 return index_oop_from_field_offset_long(_obj, _offset); |
157 // guarded scope by making the access volatile at least. Since the store |
157 } |
158 // of Thread::set_doing_unsafe_access() is also volatile, these accesses |
158 |
159 // can not be reordered by the compiler. Therefore, if the access triggers |
159 template <typename T> |
160 // a fault, we will know that Thread::doing_unsafe_access() returns true. |
160 T normalize_for_write(T x) { |
161 volatile T* addr() { |
|
162 void* addr = index_oop_from_field_offset_long(_obj, _offset); |
|
163 return static_cast<volatile T*>(addr); |
|
164 } |
|
165 |
|
166 template <typename U> |
|
167 U normalize_for_write(U x) { |
161 return x; |
168 return x; |
162 } |
169 } |
163 |
170 |
164 jboolean normalize_for_write(jboolean x) { |
171 jboolean normalize_for_write(jboolean x) { |
165 return x & 1; |
172 return x & 1; |
166 } |
173 } |
167 |
174 |
168 template <typename T> |
175 template <typename U> |
169 T normalize_for_read(T x) { |
176 U normalize_for_read(U x) { |
170 return x; |
177 return x; |
171 } |
178 } |
172 |
179 |
173 jboolean normalize_for_read(jboolean x) { |
180 jboolean normalize_for_read(jboolean x) { |
174 return x != 0; |
181 return x != 0; |
197 MemoryAccess(JavaThread* thread, jobject obj, jlong offset) |
204 MemoryAccess(JavaThread* thread, jobject obj, jlong offset) |
198 : _thread(thread), _obj(JNIHandles::resolve(obj)), _offset((ptrdiff_t)offset) { |
205 : _thread(thread), _obj(JNIHandles::resolve(obj)), _offset((ptrdiff_t)offset) { |
199 assert_field_offset_sane(_obj, offset); |
206 assert_field_offset_sane(_obj, offset); |
200 } |
207 } |
201 |
208 |
202 template <typename T> |
|
203 T get() { |
209 T get() { |
204 if (oopDesc::is_null(_obj)) { |
210 if (oopDesc::is_null(_obj)) { |
205 GuardUnsafeAccess guard(_thread); |
211 GuardUnsafeAccess guard(_thread); |
206 T ret = RawAccess<>::load((T*)addr()); |
212 T ret = RawAccess<>::load(addr()); |
207 return normalize_for_read(ret); |
213 return normalize_for_read(ret); |
208 } else { |
214 } else { |
209 T ret = HeapAccess<>::load_at(_obj, _offset); |
215 T ret = HeapAccess<>::load_at(_obj, _offset); |
210 return normalize_for_read(ret); |
216 return normalize_for_read(ret); |
211 } |
217 } |
212 } |
218 } |
213 |
219 |
214 template <typename T> |
|
215 void put(T x) { |
220 void put(T x) { |
216 if (oopDesc::is_null(_obj)) { |
221 if (oopDesc::is_null(_obj)) { |
217 GuardUnsafeAccess guard(_thread); |
222 GuardUnsafeAccess guard(_thread); |
218 RawAccess<>::store((T*)addr(), normalize_for_write(x)); |
223 RawAccess<>::store(addr(), normalize_for_write(x)); |
219 } else { |
224 } else { |
220 HeapAccess<>::store_at(_obj, _offset, normalize_for_write(x)); |
225 HeapAccess<>::store_at(_obj, _offset, normalize_for_write(x)); |
221 } |
226 } |
222 } |
227 } |
223 |
228 |
224 |
229 |
225 template <typename T> |
|
226 T get_volatile() { |
230 T get_volatile() { |
227 if (oopDesc::is_null(_obj)) { |
231 if (oopDesc::is_null(_obj)) { |
228 GuardUnsafeAccess guard(_thread); |
232 GuardUnsafeAccess guard(_thread); |
229 volatile T ret = RawAccess<MO_SEQ_CST>::load((volatile T*)addr()); |
233 volatile T ret = RawAccess<MO_SEQ_CST>::load(addr()); |
230 return normalize_for_read(ret); |
234 return normalize_for_read(ret); |
231 } else { |
235 } else { |
232 T ret = HeapAccess<MO_SEQ_CST>::load_at(_obj, _offset); |
236 T ret = HeapAccess<MO_SEQ_CST>::load_at(_obj, _offset); |
233 return normalize_for_read(ret); |
237 return normalize_for_read(ret); |
234 } |
238 } |
235 } |
239 } |
236 |
240 |
237 template <typename T> |
|
238 void put_volatile(T x) { |
241 void put_volatile(T x) { |
239 if (oopDesc::is_null(_obj)) { |
242 if (oopDesc::is_null(_obj)) { |
240 GuardUnsafeAccess guard(_thread); |
243 GuardUnsafeAccess guard(_thread); |
241 RawAccess<MO_SEQ_CST>::store((volatile T*)addr(), normalize_for_write(x)); |
244 RawAccess<MO_SEQ_CST>::store(addr(), normalize_for_write(x)); |
242 } else { |
245 } else { |
243 HeapAccess<MO_SEQ_CST>::store_at(_obj, _offset, normalize_for_write(x)); |
246 HeapAccess<MO_SEQ_CST>::store_at(_obj, _offset, normalize_for_write(x)); |
244 } |
247 } |
245 } |
248 } |
246 }; |
249 }; |
294 } UNSAFE_END |
297 } UNSAFE_END |
295 |
298 |
296 #define DEFINE_GETSETOOP(java_type, Type) \ |
299 #define DEFINE_GETSETOOP(java_type, Type) \ |
297 \ |
300 \ |
298 UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ |
301 UNSAFE_ENTRY(java_type, Unsafe_Get##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ |
299 return MemoryAccess(thread, obj, offset).get<java_type>(); \ |
302 return MemoryAccess<java_type>(thread, obj, offset).get(); \ |
300 } UNSAFE_END \ |
303 } UNSAFE_END \ |
301 \ |
304 \ |
302 UNSAFE_ENTRY(void, Unsafe_Put##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ |
305 UNSAFE_ENTRY(void, Unsafe_Put##Type(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ |
303 MemoryAccess(thread, obj, offset).put<java_type>(x); \ |
306 MemoryAccess<java_type>(thread, obj, offset).put(x); \ |
304 } UNSAFE_END \ |
307 } UNSAFE_END \ |
305 \ |
308 \ |
306 // END DEFINE_GETSETOOP. |
309 // END DEFINE_GETSETOOP. |
307 |
310 |
308 DEFINE_GETSETOOP(jboolean, Boolean) |
311 DEFINE_GETSETOOP(jboolean, Boolean) |
317 #undef DEFINE_GETSETOOP |
320 #undef DEFINE_GETSETOOP |
318 |
321 |
319 #define DEFINE_GETSETOOP_VOLATILE(java_type, Type) \ |
322 #define DEFINE_GETSETOOP_VOLATILE(java_type, Type) \ |
320 \ |
323 \ |
321 UNSAFE_ENTRY(java_type, Unsafe_Get##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ |
324 UNSAFE_ENTRY(java_type, Unsafe_Get##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset)) { \ |
322 return MemoryAccess(thread, obj, offset).get_volatile<java_type>(); \ |
325 return MemoryAccess<java_type>(thread, obj, offset).get_volatile(); \ |
323 } UNSAFE_END \ |
326 } UNSAFE_END \ |
324 \ |
327 \ |
325 UNSAFE_ENTRY(void, Unsafe_Put##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ |
328 UNSAFE_ENTRY(void, Unsafe_Put##Type##Volatile(JNIEnv *env, jobject unsafe, jobject obj, jlong offset, java_type x)) { \ |
326 MemoryAccess(thread, obj, offset).put_volatile<java_type>(x); \ |
329 MemoryAccess<java_type>(thread, obj, offset).put_volatile(x); \ |
327 } UNSAFE_END \ |
330 } UNSAFE_END \ |
328 \ |
331 \ |
329 // END DEFINE_GETSETOOP_VOLATILE. |
332 // END DEFINE_GETSETOOP_VOLATILE. |
330 |
333 |
331 DEFINE_GETSETOOP_VOLATILE(jboolean, Boolean) |
334 DEFINE_GETSETOOP_VOLATILE(jboolean, Boolean) |