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