1 /*
   2  * Copyright (c) 2017, 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 #include "precompiled.hpp"
  26 #include "runtime/atomic.hpp"
  27 #include "utilities/macros.hpp"
  28 #include "unittest.hpp"
  29 
  30 #include <limits.h>
  31 
  32 struct AtomicShortAddTest: public testing::Test {
  33   ATOMIC_SHORT_PAIR(
  34                     volatile int16_t _atomic,
  35                     int16_t _not_atomic
  36                     );
  37 
  38   void add_max() {
  39     Atomic::add(std::numeric_limits<int16_t>::max(), &_atomic);
  40   }
  41 
  42   void sub_max() {
  43     Atomic::add(std::numeric_limits<int16_t>::min(), &_atomic);
  44   }
  45 
  46   AtomicShortAddTest() : _atomic(0), _not_atomic(0) {}
  47 };
  48 
  49 // This test tests whether the neighbouring short will be
  50 // touched by an overflow.
  51 TEST_VM_F(AtomicShortAddTest, test_short_add_overflow) {
  52   EXPECT_EQ(_atomic, 0);
  53   EXPECT_EQ(_not_atomic, 0);
  54   add_max();
  55   EXPECT_EQ(_atomic, std::numeric_limits<int16_t>::max());
  56   EXPECT_EQ(_not_atomic, 0);
  57   add_max();
  58   EXPECT_EQ(_not_atomic, 0);
  59 }
  60 
  61 // This test tests whether the neighbouring short will be
  62 // touched by an underflow.
  63 TEST_VM_F(AtomicShortAddTest, test_short_add_underflow) {
  64   EXPECT_EQ(0, _atomic);
  65   EXPECT_EQ(_not_atomic, 0);
  66   sub_max();
  67   EXPECT_EQ(_atomic, std::numeric_limits<int16_t>::min());
  68   EXPECT_EQ(_not_atomic, 0);
  69   sub_max();
  70   EXPECT_EQ(_not_atomic, 0);
  71 }
  72 
  73 class AtomicIntegerTest: public testing::Test {
  74 public:
  75   template <typename T>
  76   void test_add() {
  77     volatile T value = 0;
  78     T result;
  79     const T zero = 0;
  80     const T one = 1;
  81     const T max = std::numeric_limits<T>::max();
  82     const T min = std::numeric_limits<T>::min();
  83 
  84     EXPECT_EQ(zero, value);
  85     result = Atomic::add(1, &value);
  86     EXPECT_EQ(one, value);
  87     EXPECT_EQ(result, value);
  88     result = Atomic::add(-1, &value);
  89     EXPECT_EQ(zero, value);
  90     EXPECT_EQ(result, value);
  91     result = Atomic::add(max, &value);
  92     EXPECT_EQ(max, value);
  93     EXPECT_EQ(result, value);
  94   }
  95 
  96   template <typename T>
  97   void test_inc_dec() {
  98     volatile T value = 0;
  99     const T zero = 0;
 100     const T one = 1;
 101     const T max = std::numeric_limits<T>::max();
 102     const T min = std::numeric_limits<T>::min();
 103 
 104     EXPECT_EQ(zero, value);
 105     Atomic::inc(&value);
 106     EXPECT_EQ(one, value);
 107     Atomic::dec(&value);
 108     EXPECT_EQ(zero, value);
 109     Atomic::add(max - 1, &value);
 110     EXPECT_EQ(max - 1, value);
 111     Atomic::inc(&value);
 112     EXPECT_EQ(max, value);
 113   }
 114 
 115   template <typename T>
 116   void test_cas() {
 117     const T max = std::numeric_limits<T>::max();
 118     const T min = std::numeric_limits<T>::min();
 119 
 120     volatile T value = min;
 121 
 122     // Successful cas
 123     T result = Atomic::cmpxchg(max, &value, min);
 124     EXPECT_EQ(max, value);
 125     EXPECT_EQ(min, result);
 126 
 127     // Unsuccessful cas
 128     result = Atomic::cmpxchg(max, &value, min);
 129     EXPECT_EQ(max, value);
 130     EXPECT_EQ(max, result);
 131 
 132     // Another successful cas
 133     result = Atomic::cmpxchg(min, &value, max);
 134     EXPECT_EQ(min, value);
 135     EXPECT_EQ(max, result);
 136   }
 137 
 138   template <typename T>
 139   void test_swap() {
 140     const T zero = 0;
 141     const T one = 1;
 142     const T max = std::numeric_limits<T>::max();
 143     const T min = std::numeric_limits<T>::min();
 144 
 145     volatile T value = zero;
 146 
 147     T result = Atomic::xchg(one, &value);
 148     EXPECT_EQ(one, value);
 149     EXPECT_EQ(zero, result);
 150 
 151     value = min;
 152     result = Atomic::xchg(max, &value);
 153     EXPECT_EQ(max, value);
 154     EXPECT_EQ(min, result);
 155 
 156     result = Atomic::xchg(min, &value);
 157     EXPECT_EQ(min, value);
 158     EXPECT_EQ(max, result);
 159   }
 160 };
 161 
 162 #define GENERATE_ATOMIC_INTEGER_TEST(T)               \
 163 TEST_VM_F(AtomicIntegerTest, atomic_add_##T) {        \
 164   test_add<T##_t>();                                  \
 165   test_inc_dec<T##_t>();                              \
 166   test_cas<T##_t>();                                  \
 167   test_swap<T##_t>();                                 \
 168 }
 169 
 170 GENERATE_ATOMIC_INTEGER_TEST(int32)
 171 GENERATE_ATOMIC_INTEGER_TEST(intptr)
 172 GENERATE_ATOMIC_INTEGER_TEST(uint32)
 173 GENERATE_ATOMIC_INTEGER_TEST(uintptr)
 174 
 175 #undef GENERATE_ATOMIC_INTEGER_TEST
 176 
 177 TEST(AtomicTest, pointer_arithmetic_byte) {
 178   const intptr_t max = std::numeric_limits<intptr_t>::max();
 179   const intptr_t min = std::numeric_limits<intptr_t>::min();
 180 
 181   int8_t *volatile byte_array = NULL;
 182 
 183   Atomic::inc(&byte_array);
 184   EXPECT_EQ(1, IntegerTypes::cast_to_signed(byte_array));
 185   int8_t* result = Atomic::add(5, &byte_array);
 186   EXPECT_EQ(6, IntegerTypes::cast_to_signed(byte_array));
 187   EXPECT_EQ(6, IntegerTypes::cast_to_signed(result));
 188   byte_array = NULL;
 189   result = Atomic::add(max, &byte_array);
 190   EXPECT_EQ(max, IntegerTypes::cast_to_signed(byte_array));
 191   EXPECT_EQ(max, IntegerTypes::cast_to_signed(result));
 192   Atomic::dec(&byte_array);
 193   EXPECT_EQ(max - 1, IntegerTypes::cast_to_signed(byte_array));
 194 }
 195 
 196 TEST(AtomicTest, pointer_arithmetic_pointer) {
 197   const intptr_t max = std::numeric_limits<intptr_t>::max() / sizeof(void*);
 198   const intptr_t min = std::numeric_limits<intptr_t>::min() / sizeof(void*);
 199 
 200   void **volatile pointer_array = NULL;
 201 
 202   Atomic::inc(&pointer_array);
 203   EXPECT_EQ(IntegerTypes::cast_to_signed(1 * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array));
 204   void** result = Atomic::add(5, &pointer_array);
 205   EXPECT_EQ(IntegerTypes::cast_to_signed(6 * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array));
 206   EXPECT_EQ(IntegerTypes::cast_to_signed(6 * sizeof(void*)), IntegerTypes::cast_to_signed(result));
 207   pointer_array = NULL;
 208   result = Atomic::add(max, &pointer_array);
 209   EXPECT_EQ(IntegerTypes::cast_to_signed(max * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array));
 210   EXPECT_EQ(IntegerTypes::cast_to_signed(max * sizeof(void*)), IntegerTypes::cast_to_signed(result));
 211   Atomic::dec(&pointer_array);
 212   EXPECT_EQ(IntegerTypes::cast_to_signed((max - 1) * sizeof(void*)), IntegerTypes::cast_to_signed(pointer_array));
 213 }