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