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 }