289 |
289 |
290 inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { |
290 inline void* Atomic::xchg_ptr(void* exchange_value, volatile void* dest) { |
291 return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); |
291 return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest); |
292 } |
292 } |
293 |
293 |
|
294 #define VM_HAS_SPECIALIZED_CMPXCHG_BYTE |
|
295 inline jbyte Atomic::cmpxchg(jbyte exchange_value, volatile jbyte* dest, jbyte compare_value) { |
|
296 |
|
297 // Note that cmpxchg guarantees a two-way memory barrier across |
|
298 // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire' |
|
299 // (see atomic.hpp). |
|
300 |
|
301 // Using 32 bit internally. |
|
302 volatile int *dest_base = (volatile int*)((uintptr_t)dest & ~3); |
|
303 |
|
304 #ifdef VM_LITTLE_ENDIAN |
|
305 const unsigned int shift_amount = ((uintptr_t)dest & 3) * 8; |
|
306 #else |
|
307 const unsigned int shift_amount = ((~(uintptr_t)dest) & 3) * 8; |
|
308 #endif |
|
309 const unsigned int masked_compare_val = ((unsigned int)(unsigned char)compare_value), |
|
310 masked_exchange_val = ((unsigned int)(unsigned char)exchange_value), |
|
311 xor_value = (masked_compare_val ^ masked_exchange_val) << shift_amount; |
|
312 |
|
313 unsigned int old_value, value32; |
|
314 |
|
315 __asm__ __volatile__ ( |
|
316 /* fence */ |
|
317 strasm_sync |
|
318 /* simple guard */ |
|
319 " lbz %[old_value], 0(%[dest]) \n" |
|
320 " cmpw %[masked_compare_val], %[old_value] \n" |
|
321 " bne- 2f \n" |
|
322 /* atomic loop */ |
|
323 "1: \n" |
|
324 " lwarx %[value32], 0, %[dest_base] \n" |
|
325 /* extract byte and compare */ |
|
326 " srd %[old_value], %[value32], %[shift_amount] \n" |
|
327 " clrldi %[old_value], %[old_value], 56 \n" |
|
328 " cmpw %[masked_compare_val], %[old_value] \n" |
|
329 " bne- 2f \n" |
|
330 /* replace byte and try to store */ |
|
331 " xor %[value32], %[xor_value], %[value32] \n" |
|
332 " stwcx. %[value32], 0, %[dest_base] \n" |
|
333 " bne- 1b \n" |
|
334 /* acquire */ |
|
335 strasm_sync |
|
336 /* exit */ |
|
337 "2: \n" |
|
338 /* out */ |
|
339 : [old_value] "=&r" (old_value), |
|
340 [value32] "=&r" (value32), |
|
341 "=m" (*dest), |
|
342 "=m" (*dest_base) |
|
343 /* in */ |
|
344 : [dest] "b" (dest), |
|
345 [dest_base] "b" (dest_base), |
|
346 [shift_amount] "r" (shift_amount), |
|
347 [masked_compare_val] "r" (masked_compare_val), |
|
348 [xor_value] "r" (xor_value), |
|
349 "m" (*dest), |
|
350 "m" (*dest_base) |
|
351 /* clobber */ |
|
352 : "cc", |
|
353 "memory" |
|
354 ); |
|
355 |
|
356 return (jbyte)(unsigned char)old_value; |
|
357 } |
|
358 |
294 inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) { |
359 inline jint Atomic::cmpxchg(jint exchange_value, volatile jint* dest, jint compare_value) { |
295 |
360 |
296 // Note that cmpxchg guarantees a two-way memory barrier across |
361 // Note that cmpxchg guarantees a two-way memory barrier across |
297 // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire' |
362 // the cmpxchg, so it's really a a 'fence_cmpxchg_acquire' |
298 // (see atomic.hpp). |
363 // (see atomic.hpp). |