1 /*
2  * Copyright (c) 1999, 2013, 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 #ifndef OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_INLINE_HPP
26 #define OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_INLINE_HPP
27 
28 #include "runtime/atomic.hpp"
29 #include "runtime/os.hpp"
30 #include "vm_version_sparc.hpp"
31 
32 // Implementation of class atomic
33 
store(jbyte store_value,jbyte * dest)34 inline void Atomic::store    (jbyte    store_value, jbyte*    dest) { *dest = store_value; }
store(jshort store_value,jshort * dest)35 inline void Atomic::store    (jshort   store_value, jshort*   dest) { *dest = store_value; }
store(jint store_value,jint * dest)36 inline void Atomic::store    (jint     store_value, jint*     dest) { *dest = store_value; }
store_ptr(intptr_t store_value,intptr_t * dest)37 inline void Atomic::store_ptr(intptr_t store_value, intptr_t* dest) { *dest = store_value; }
store_ptr(void * store_value,void * dest)38 inline void Atomic::store_ptr(void*    store_value, void*     dest) { *(void**)dest = store_value; }
39 
store(jbyte store_value,volatile jbyte * dest)40 inline void Atomic::store    (jbyte    store_value, volatile jbyte*    dest) { *dest = store_value; }
store(jshort store_value,volatile jshort * dest)41 inline void Atomic::store    (jshort   store_value, volatile jshort*   dest) { *dest = store_value; }
store(jint store_value,volatile jint * dest)42 inline void Atomic::store    (jint     store_value, volatile jint*     dest) { *dest = store_value; }
store_ptr(intptr_t store_value,volatile intptr_t * dest)43 inline void Atomic::store_ptr(intptr_t store_value, volatile intptr_t* dest) { *dest = store_value; }
store_ptr(void * store_value,volatile void * dest)44 inline void Atomic::store_ptr(void*    store_value, volatile void*     dest) { *(void* volatile *)dest = store_value; }
45 
inc(volatile jint * dest)46 inline void Atomic::inc    (volatile jint*     dest) { (void)add    (1, dest); }
inc_ptr(volatile intptr_t * dest)47 inline void Atomic::inc_ptr(volatile intptr_t* dest) { (void)add_ptr(1, dest); }
inc_ptr(volatile void * dest)48 inline void Atomic::inc_ptr(volatile void*     dest) { (void)add_ptr(1, dest); }
49 
dec(volatile jint * dest)50 inline void Atomic::dec    (volatile jint*     dest) { (void)add    (-1, dest); }
dec_ptr(volatile intptr_t * dest)51 inline void Atomic::dec_ptr(volatile intptr_t* dest) { (void)add_ptr(-1, dest); }
dec_ptr(volatile void * dest)52 inline void Atomic::dec_ptr(volatile void*     dest) { (void)add_ptr(-1, dest); }
53 
54 
55 #ifdef _LP64
56 
store(jlong store_value,jlong * dest)57 inline void Atomic::store(jlong store_value, jlong* dest) { *dest = store_value; }
store(jlong store_value,volatile jlong * dest)58 inline void Atomic::store(jlong store_value, volatile jlong* dest) { *dest = store_value; }
load(volatile jlong * src)59 inline jlong Atomic::load(volatile jlong* src) { return *src; }
60 
61 #else
62 
63 extern "C" void _Atomic_move_long_v9(volatile jlong* src, volatile jlong* dst);
64 
Atomic_move_long(volatile jlong * src,volatile jlong * dst)65 inline void Atomic_move_long(volatile jlong* src, volatile jlong* dst) {
66   _Atomic_move_long_v9(src, dst);
67 }
68 
load(volatile jlong * src)69 inline jlong Atomic::load(volatile jlong* src) {
70   volatile jlong dest;
71   Atomic_move_long(src, &dest);
72   return dest;
73 }
74 
store(jlong store_value,jlong * dest)75 inline void Atomic::store(jlong store_value, jlong* dest) {
76   Atomic_move_long((volatile jlong*)&store_value, (volatile jlong*)dest);
77 }
78 
store(jlong store_value,volatile jlong * dest)79 inline void Atomic::store(jlong store_value, volatile jlong* dest) {
80   Atomic_move_long((volatile jlong*)&store_value, dest);
81 }
82 
83 #endif
84 
85 #ifdef _GNU_SOURCE
86 
add(jint add_value,volatile jint * dest)87 inline jint     Atomic::add    (jint     add_value, volatile jint*     dest) {
88   intptr_t rv;
89   __asm__ volatile(
90     "1: \n\t"
91     " ld     [%2], %%o2\n\t"
92     " add    %1, %%o2, %%o3\n\t"
93     " cas    [%2], %%o2, %%o3\n\t"
94     " cmp    %%o2, %%o3\n\t"
95     " bne    1b\n\t"
96     "  nop\n\t"
97     " add    %1, %%o2, %0\n\t"
98     : "=r" (rv)
99     : "r" (add_value), "r" (dest)
100     : "memory", "o2", "o3");
101   return rv;
102 }
103 
add_ptr(intptr_t add_value,volatile intptr_t * dest)104 inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) {
105   intptr_t rv;
106 #ifdef _LP64
107   __asm__ volatile(
108     "1: \n\t"
109     " ldx    [%2], %%o2\n\t"
110     " add    %0, %%o2, %%o3\n\t"
111     " casx   [%2], %%o2, %%o3\n\t"
112     " cmp    %%o2, %%o3\n\t"
113     " bne    %%xcc, 1b\n\t"
114     "  nop\n\t"
115     " add    %0, %%o2, %0\n\t"
116     : "=r" (rv)
117     : "r" (add_value), "r" (dest)
118     : "memory", "o2", "o3");
119 #else //_LP64
120   __asm__ volatile(
121     "1: \n\t"
122     " ld     [%2], %%o2\n\t"
123     " add    %1, %%o2, %%o3\n\t"
124     " cas    [%2], %%o2, %%o3\n\t"
125     " cmp    %%o2, %%o3\n\t"
126     " bne    1b\n\t"
127     "  nop\n\t"
128     " add    %1, %%o2, %0\n\t"
129     : "=r" (rv)
130     : "r" (add_value), "r" (dest)
131     : "memory", "o2", "o3");
132 #endif // _LP64
133   return rv;
134 }
135 
add_ptr(intptr_t add_value,volatile void * dest)136 inline void*    Atomic::add_ptr(intptr_t add_value, volatile void*     dest) {
137   return (void*)add_ptr((intptr_t)add_value, (volatile intptr_t*)dest);
138 }
139 
140 
xchg(jint exchange_value,volatile jint * dest)141 inline jint     Atomic::xchg    (jint     exchange_value, volatile jint*     dest) {
142   intptr_t rv = exchange_value;
143   __asm__ volatile(
144     " swap   [%2],%1\n\t"
145     : "=r" (rv)
146     : "0" (exchange_value) /* we use same register as for return value */, "r" (dest)
147     : "memory");
148   return rv;
149 }
150 
xchg_ptr(intptr_t exchange_value,volatile intptr_t * dest)151 inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
152   intptr_t rv = exchange_value;
153 #ifdef _LP64
154   __asm__ volatile(
155     "1:\n\t"
156     " mov    %1, %%o3\n\t"
157     " ldx    [%2], %%o2\n\t"
158     " casx   [%2], %%o2, %%o3\n\t"
159     " cmp    %%o2, %%o3\n\t"
160     " bne    %%xcc, 1b\n\t"
161     "  nop\n\t"
162     " mov    %%o2, %0\n\t"
163     : "=r" (rv)
164     : "r" (exchange_value), "r" (dest)
165     : "memory", "o2", "o3");
166 #else  //_LP64
167   __asm__ volatile(
168     "swap    [%2],%1\n\t"
169     : "=r" (rv)
170     : "0" (exchange_value) /* we use same register as for return value */, "r" (dest)
171     : "memory");
172 #endif // _LP64
173   return rv;
174 }
175 
xchg_ptr(void * exchange_value,volatile void * dest)176 inline void*    Atomic::xchg_ptr(void*    exchange_value, volatile void*     dest) {
177   return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
178 }
179 
180 
cmpxchg(jint exchange_value,volatile jint * dest,jint compare_value)181 inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
182   jint rv;
183   __asm__ volatile(
184     " cas    [%2], %3, %0"
185     : "=r" (rv)
186     : "0" (exchange_value), "r" (dest), "r" (compare_value)
187     : "memory");
188   return rv;
189 }
190 
cmpxchg(jlong exchange_value,volatile jlong * dest,jlong compare_value)191 inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
192 #ifdef _LP64
193   jlong rv;
194   __asm__ volatile(
195     " casx   [%2], %3, %0"
196     : "=r" (rv)
197     : "0" (exchange_value), "r" (dest), "r" (compare_value)
198     : "memory");
199   return rv;
200 #else  //_LP64
201   volatile jlong_accessor evl, cvl, rv;
202   evl.long_value = exchange_value;
203   cvl.long_value = compare_value;
204 
205   __asm__ volatile(
206     " sllx   %2, 32, %2\n\t"
207     " srl    %3, 0,  %3\n\t"
208     " or     %2, %3, %2\n\t"
209     " sllx   %5, 32, %5\n\t"
210     " srl    %6, 0,  %6\n\t"
211     " or     %5, %6, %5\n\t"
212     " casx   [%4], %5, %2\n\t"
213     " srl    %2, 0, %1\n\t"
214     " srlx   %2, 32, %0\n\t"
215     : "=r" (rv.words[0]), "=r" (rv.words[1])
216     : "r"  (evl.words[0]), "r" (evl.words[1]), "r" (dest), "r" (cvl.words[0]), "r" (cvl.words[1])
217     : "memory");
218 
219   return rv.long_value;
220 #endif  //_LP64
221 }
222 
cmpxchg_ptr(intptr_t exchange_value,volatile intptr_t * dest,intptr_t compare_value)223 inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value) {
224   intptr_t rv;
225 #ifdef _LP64
226   __asm__ volatile(
227     " casx    [%2], %3, %0"
228     : "=r" (rv)
229     : "0" (exchange_value), "r" (dest), "r" (compare_value)
230     : "memory");
231 #else  //_LP64
232   __asm__ volatile(
233     " cas     [%2], %3, %0"
234     : "=r" (rv)
235     : "0" (exchange_value), "r" (dest), "r" (compare_value)
236     : "memory");
237 #endif // _LP64
238   return rv;
239 }
240 
cmpxchg_ptr(void * exchange_value,volatile void * dest,void * compare_value)241 inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value) {
242   return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value);
243 }
244 
245 #else // _GNU_SOURCE
246 
247 #if defined(COMPILER2) || defined(_LP64)
248 
249 // This is the interface to the atomic instructions in solaris_sparc.il.
250 // It's very messy because we need to support v8 and these instructions
251 // are illegal there.  When sparc v8 is dropped, we can drop out lots of
252 // this code.  Also compiler2 does not support v8 so the conditional code
253 // omits the instruction set check.
254 
255 extern "C" jint     _Atomic_swap32(jint     exchange_value, volatile jint*     dest);
256 extern "C" intptr_t _Atomic_swap64(intptr_t exchange_value, volatile intptr_t* dest);
257 
258 extern "C" jint     _Atomic_cas32(jint     exchange_value, volatile jint*     dest, jint     compare_value);
259 extern "C" intptr_t _Atomic_cas64(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value);
260 extern "C" jlong    _Atomic_casl (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value);
261 
262 extern "C" jint     _Atomic_add32(jint     inc,       volatile jint*     dest);
263 extern "C" intptr_t _Atomic_add64(intptr_t add_value, volatile intptr_t* dest);
264 
265 
add(jint add_value,volatile jint * dest)266 inline jint     Atomic::add     (jint    add_value, volatile jint*     dest) {
267   return _Atomic_add32(add_value, dest);
268 }
269 
add_ptr(intptr_t add_value,volatile intptr_t * dest)270 inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) {
271 #ifdef _LP64
272   return _Atomic_add64(add_value, dest);
273 #else  //_LP64
274   return _Atomic_add32(add_value, dest);
275 #endif // _LP64
276 }
277 
add_ptr(intptr_t add_value,volatile void * dest)278 inline void*    Atomic::add_ptr(intptr_t add_value, volatile void*     dest) {
279   return (void*)add_ptr((intptr_t)add_value, (volatile intptr_t*)dest);
280 }
281 
282 
xchg(jint exchange_value,volatile jint * dest)283 inline jint     Atomic::xchg    (jint     exchange_value, volatile jint*     dest) {
284   return _Atomic_swap32(exchange_value, dest);
285 }
286 
xchg_ptr(intptr_t exchange_value,volatile intptr_t * dest)287 inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
288 #ifdef _LP64
289   return _Atomic_swap64(exchange_value, dest);
290 #else  // _LP64
291   return _Atomic_swap32(exchange_value, dest);
292 #endif // _LP64
293 }
294 
xchg_ptr(void * exchange_value,volatile void * dest)295 inline void*    Atomic::xchg_ptr(void*    exchange_value, volatile void*     dest) {
296   return (void*)xchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest);
297 }
298 
299 
cmpxchg(jint exchange_value,volatile jint * dest,jint compare_value)300 inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
301   return _Atomic_cas32(exchange_value, dest, compare_value);
302 }
303 
cmpxchg(jlong exchange_value,volatile jlong * dest,jlong compare_value)304 inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
305 #ifdef _LP64
306   // Return 64 bit value in %o0
307   return _Atomic_cas64((intptr_t)exchange_value, (intptr_t *)dest, (intptr_t)compare_value);
308 #else  // _LP64
309   // Return 64 bit value in %o0,%o1 by hand
310   return _Atomic_casl(exchange_value, dest, compare_value);
311 #endif // _LP64
312 }
313 
cmpxchg_ptr(intptr_t exchange_value,volatile intptr_t * dest,intptr_t compare_value)314 inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value) {
315 #ifdef _LP64
316   return _Atomic_cas64(exchange_value, dest, compare_value);
317 #else  // _LP64
318   return _Atomic_cas32(exchange_value, dest, compare_value);
319 #endif // _LP64
320 }
321 
cmpxchg_ptr(void * exchange_value,volatile void * dest,void * compare_value)322 inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value) {
323   return (void*)cmpxchg_ptr((intptr_t)exchange_value, (volatile intptr_t*)dest, (intptr_t)compare_value);
324 }
325 
326 
327 #else // _LP64 || COMPILER2
328 
329 
330 // 32-bit compiler1 only
331 
add(jint add_value,volatile jint * dest)332 inline jint     Atomic::add    (jint     add_value, volatile jint*     dest) {
333   return (*os::atomic_add_func)(add_value, dest);
334 }
335 
add_ptr(intptr_t add_value,volatile intptr_t * dest)336 inline intptr_t Atomic::add_ptr(intptr_t add_value, volatile intptr_t* dest) {
337   return (intptr_t)add((jint)add_value, (volatile jint*)dest);
338 }
339 
add_ptr(intptr_t add_value,volatile void * dest)340 inline void*    Atomic::add_ptr(intptr_t add_value, volatile void*     dest) {
341   return (void*)add((jint)add_value, (volatile jint*)dest);
342 }
343 
344 
xchg(jint exchange_value,volatile jint * dest)345 inline jint     Atomic::xchg    (jint     exchange_value, volatile jint*     dest) {
346   return (*os::atomic_xchg_func)(exchange_value, dest);
347 }
348 
xchg_ptr(intptr_t exchange_value,volatile intptr_t * dest)349 inline intptr_t Atomic::xchg_ptr(intptr_t exchange_value, volatile intptr_t* dest) {
350   return (intptr_t)xchg((jint)exchange_value, (volatile jint*)dest);
351 }
352 
xchg_ptr(void * exchange_value,volatile void * dest)353 inline void*    Atomic::xchg_ptr(void*    exchange_value, volatile void*     dest) {
354   return (void*)xchg((jint)exchange_value, (volatile jint*)dest);
355 }
356 
357 
cmpxchg(jint exchange_value,volatile jint * dest,jint compare_value)358 inline jint     Atomic::cmpxchg    (jint     exchange_value, volatile jint*     dest, jint     compare_value) {
359   return (*os::atomic_cmpxchg_func)(exchange_value, dest, compare_value);
360 }
361 
cmpxchg(jlong exchange_value,volatile jlong * dest,jlong compare_value)362 inline jlong    Atomic::cmpxchg    (jlong    exchange_value, volatile jlong*    dest, jlong    compare_value) {
363   return (*os::atomic_cmpxchg_long_func)(exchange_value, dest, compare_value);
364 }
365 
cmpxchg_ptr(intptr_t exchange_value,volatile intptr_t * dest,intptr_t compare_value)366 inline intptr_t Atomic::cmpxchg_ptr(intptr_t exchange_value, volatile intptr_t* dest, intptr_t compare_value) {
367   return (intptr_t)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value);
368 }
369 
cmpxchg_ptr(void * exchange_value,volatile void * dest,void * compare_value)370 inline void*    Atomic::cmpxchg_ptr(void*    exchange_value, volatile void*     dest, void*    compare_value) {
371   return (void*)cmpxchg((jint)exchange_value, (volatile jint*)dest, (jint)compare_value);
372 }
373 
374 #endif // _LP64 || COMPILER2
375 
376 #endif // _GNU_SOURCE
377 
378 #endif // OS_CPU_SOLARIS_SPARC_VM_ATOMIC_SOLARIS_SPARC_INLINE_HPP
379