OLD | NEW |
(Empty) | |
| 1 // Copyright 2014 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are |
| 4 // met: |
| 5 // |
| 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. |
| 12 // * Neither the name of Google Inc. nor the names of its |
| 13 // contributors may be used to endorse or promote products derived |
| 14 // from this software without specific prior written permission. |
| 15 // |
| 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
| 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
| 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR |
| 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
| 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, |
| 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT |
| 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, |
| 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY |
| 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT |
| 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE |
| 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| 27 |
| 28 #include "v8.h" |
| 29 |
| 30 #include "cctest.h" |
| 31 #include "atomicops.h" |
| 32 |
| 33 using namespace v8::internal; |
| 34 |
| 35 |
| 36 #define CHECK_EQU(v1, v2) \ |
| 37 CHECK_EQ(static_cast<int64_t>(v1), static_cast<int64_t>(v2)) |
| 38 |
| 39 #define NUM_BITS(T) (sizeof(T) * 8) |
| 40 |
| 41 |
| 42 template <class AtomicType> |
| 43 static void TestAtomicIncrement() { |
| 44 // For now, we just test the single-threaded execution. |
| 45 |
| 46 // Use a guard value to make sure that NoBarrier_AtomicIncrement doesn't |
| 47 // go outside the expected address bounds. This is to test that the |
| 48 // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit |
| 49 // machines. |
| 50 struct { |
| 51 AtomicType prev_word; |
| 52 AtomicType count; |
| 53 AtomicType next_word; |
| 54 } s; |
| 55 |
| 56 AtomicType prev_word_value, next_word_value; |
| 57 memset(&prev_word_value, 0xFF, sizeof(AtomicType)); |
| 58 memset(&next_word_value, 0xEE, sizeof(AtomicType)); |
| 59 |
| 60 s.prev_word = prev_word_value; |
| 61 s.count = 0; |
| 62 s.next_word = next_word_value; |
| 63 |
| 64 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 1), 1); |
| 65 CHECK_EQU(s.count, 1); |
| 66 CHECK_EQU(s.prev_word, prev_word_value); |
| 67 CHECK_EQU(s.next_word, next_word_value); |
| 68 |
| 69 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 2), 3); |
| 70 CHECK_EQU(s.count, 3); |
| 71 CHECK_EQU(s.prev_word, prev_word_value); |
| 72 CHECK_EQU(s.next_word, next_word_value); |
| 73 |
| 74 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 3), 6); |
| 75 CHECK_EQU(s.count, 6); |
| 76 CHECK_EQU(s.prev_word, prev_word_value); |
| 77 CHECK_EQU(s.next_word, next_word_value); |
| 78 |
| 79 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -3), 3); |
| 80 CHECK_EQU(s.count, 3); |
| 81 CHECK_EQU(s.prev_word, prev_word_value); |
| 82 CHECK_EQU(s.next_word, next_word_value); |
| 83 |
| 84 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -2), 1); |
| 85 CHECK_EQU(s.count, 1); |
| 86 CHECK_EQU(s.prev_word, prev_word_value); |
| 87 CHECK_EQU(s.next_word, next_word_value); |
| 88 |
| 89 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -1), 0); |
| 90 CHECK_EQU(s.count, 0); |
| 91 CHECK_EQU(s.prev_word, prev_word_value); |
| 92 CHECK_EQU(s.next_word, next_word_value); |
| 93 |
| 94 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -1), -1); |
| 95 CHECK_EQU(s.count, -1); |
| 96 CHECK_EQU(s.prev_word, prev_word_value); |
| 97 CHECK_EQU(s.next_word, next_word_value); |
| 98 |
| 99 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -4), -5); |
| 100 CHECK_EQU(s.count, -5); |
| 101 CHECK_EQU(s.prev_word, prev_word_value); |
| 102 CHECK_EQU(s.next_word, next_word_value); |
| 103 |
| 104 CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 5), 0); |
| 105 CHECK_EQU(s.count, 0); |
| 106 CHECK_EQU(s.prev_word, prev_word_value); |
| 107 CHECK_EQU(s.next_word, next_word_value); |
| 108 } |
| 109 |
| 110 |
| 111 template <class AtomicType> |
| 112 static void TestCompareAndSwap() { |
| 113 AtomicType value = 0; |
| 114 AtomicType prev = NoBarrier_CompareAndSwap(&value, 0, 1); |
| 115 CHECK_EQU(1, value); |
| 116 CHECK_EQU(0, prev); |
| 117 |
| 118 // Use a test value that has non-zero bits in both halves, for testing |
| 119 // the 64-bit implementation on 32-bit platforms. |
| 120 const AtomicType k_test_val = |
| 121 (static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) - 2)) + 11; |
| 122 value = k_test_val; |
| 123 prev = NoBarrier_CompareAndSwap(&value, 0, 5); |
| 124 CHECK_EQU(k_test_val, value); |
| 125 CHECK_EQU(k_test_val, prev); |
| 126 |
| 127 value = k_test_val; |
| 128 prev = NoBarrier_CompareAndSwap(&value, k_test_val, 5); |
| 129 CHECK_EQU(5, value); |
| 130 CHECK_EQU(k_test_val, prev); |
| 131 } |
| 132 |
| 133 |
| 134 template <class AtomicType> |
| 135 static void TestAtomicExchange() { |
| 136 AtomicType value = 0; |
| 137 AtomicType new_value = NoBarrier_AtomicExchange(&value, 1); |
| 138 CHECK_EQU(1, value); |
| 139 CHECK_EQU(0, new_value); |
| 140 |
| 141 // Use a test value that has non-zero bits in both halves, for testing |
| 142 // the 64-bit implementation on 32-bit platforms. |
| 143 const AtomicType k_test_val = |
| 144 (static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) - 2)) + 11; |
| 145 value = k_test_val; |
| 146 new_value = NoBarrier_AtomicExchange(&value, k_test_val); |
| 147 CHECK_EQU(k_test_val, value); |
| 148 CHECK_EQU(k_test_val, new_value); |
| 149 |
| 150 value = k_test_val; |
| 151 new_value = NoBarrier_AtomicExchange(&value, 5); |
| 152 CHECK_EQU(5, value); |
| 153 CHECK_EQU(k_test_val, new_value); |
| 154 } |
| 155 |
| 156 |
| 157 template <class AtomicType> |
| 158 static void TestAtomicIncrementBounds() { |
| 159 // Test at rollover boundary between int_max and int_min. |
| 160 AtomicType test_val = |
| 161 static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) - 1); |
| 162 AtomicType value = -1 ^ test_val; |
| 163 AtomicType new_value = NoBarrier_AtomicIncrement(&value, 1); |
| 164 CHECK_EQU(test_val, value); |
| 165 CHECK_EQU(value, new_value); |
| 166 |
| 167 NoBarrier_AtomicIncrement(&value, -1); |
| 168 CHECK_EQU(-1 ^ test_val, value); |
| 169 |
| 170 // Test at 32-bit boundary for 64-bit atomic type. |
| 171 test_val = static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) / 2); |
| 172 value = test_val - 1; |
| 173 new_value = NoBarrier_AtomicIncrement(&value, 1); |
| 174 CHECK_EQU(test_val, value); |
| 175 CHECK_EQU(value, new_value); |
| 176 |
| 177 NoBarrier_AtomicIncrement(&value, -1); |
| 178 CHECK_EQU(test_val - 1, value); |
| 179 } |
| 180 |
| 181 |
| 182 // Return an AtomicType with the value 0xa5a5a5.. |
| 183 template <class AtomicType> |
| 184 static AtomicType TestFillValue() { |
| 185 AtomicType val = 0; |
| 186 memset(&val, 0xa5, sizeof(AtomicType)); |
| 187 return val; |
| 188 } |
| 189 |
| 190 |
| 191 // This is a simple sanity check to ensure that values are correct. |
| 192 // Not testing atomicity. |
| 193 template <class AtomicType> |
| 194 static void TestStore() { |
| 195 const AtomicType kVal1 = TestFillValue<AtomicType>(); |
| 196 const AtomicType kVal2 = static_cast<AtomicType>(-1); |
| 197 |
| 198 AtomicType value; |
| 199 |
| 200 NoBarrier_Store(&value, kVal1); |
| 201 CHECK_EQU(kVal1, value); |
| 202 NoBarrier_Store(&value, kVal2); |
| 203 CHECK_EQU(kVal2, value); |
| 204 |
| 205 Acquire_Store(&value, kVal1); |
| 206 CHECK_EQU(kVal1, value); |
| 207 Acquire_Store(&value, kVal2); |
| 208 CHECK_EQU(kVal2, value); |
| 209 |
| 210 Release_Store(&value, kVal1); |
| 211 CHECK_EQU(kVal1, value); |
| 212 Release_Store(&value, kVal2); |
| 213 CHECK_EQU(kVal2, value); |
| 214 } |
| 215 |
| 216 |
| 217 // This is a simple sanity check to ensure that values are correct. |
| 218 // Not testing atomicity. |
| 219 template <class AtomicType> |
| 220 static void TestLoad() { |
| 221 const AtomicType kVal1 = TestFillValue<AtomicType>(); |
| 222 const AtomicType kVal2 = static_cast<AtomicType>(-1); |
| 223 |
| 224 AtomicType value; |
| 225 |
| 226 value = kVal1; |
| 227 CHECK_EQU(kVal1, NoBarrier_Load(&value)); |
| 228 value = kVal2; |
| 229 CHECK_EQU(kVal2, NoBarrier_Load(&value)); |
| 230 |
| 231 value = kVal1; |
| 232 CHECK_EQU(kVal1, Acquire_Load(&value)); |
| 233 value = kVal2; |
| 234 CHECK_EQU(kVal2, Acquire_Load(&value)); |
| 235 |
| 236 value = kVal1; |
| 237 CHECK_EQU(kVal1, Release_Load(&value)); |
| 238 value = kVal2; |
| 239 CHECK_EQU(kVal2, Release_Load(&value)); |
| 240 } |
| 241 |
| 242 |
| 243 TEST(AtomicIncrement) { |
| 244 TestAtomicIncrement<Atomic32>(); |
| 245 TestAtomicIncrement<AtomicWord>(); |
| 246 } |
| 247 |
| 248 |
| 249 TEST(CompareAndSwap) { |
| 250 TestCompareAndSwap<Atomic32>(); |
| 251 TestCompareAndSwap<AtomicWord>(); |
| 252 } |
| 253 |
| 254 |
| 255 TEST(AtomicExchange) { |
| 256 TestAtomicExchange<Atomic32>(); |
| 257 TestAtomicExchange<AtomicWord>(); |
| 258 } |
| 259 |
| 260 |
| 261 TEST(AtomicIncrementBounds) { |
| 262 TestAtomicIncrementBounds<Atomic32>(); |
| 263 TestAtomicIncrementBounds<AtomicWord>(); |
| 264 } |
| 265 |
| 266 |
| 267 TEST(Store) { |
| 268 TestStore<Atomic32>(); |
| 269 TestStore<AtomicWord>(); |
| 270 } |
| 271 |
| 272 |
| 273 TEST(Load) { |
| 274 TestLoad<Atomic32>(); |
| 275 TestLoad<AtomicWord>(); |
| 276 } |
OLD | NEW |