Home | History | Annotate | Download | only in cctest
      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 "src/v8.h"
     29 
     30 #include "src/base/atomicops.h"
     31 #include "test/cctest/cctest.h"
     32 
     33 using namespace v8::base;
     34 using namespace v8::internal;
     35 
     36 
     37 #define CHECK_EQU(v1, v2) \
     38   CHECK_EQ(static_cast<int64_t>(v1), static_cast<int64_t>(v2))
     39 
     40 #define NUM_BITS(T) (sizeof(T) * 8)
     41 
     42 
     43 template <class AtomicType>
     44 static void TestAtomicIncrement() {
     45   // For now, we just test the single-threaded execution.
     46 
     47   // Use a guard value to make sure that NoBarrier_AtomicIncrement doesn't
     48   // go outside the expected address bounds.  This is to test that the
     49   // 32-bit NoBarrier_AtomicIncrement doesn't do the wrong thing on 64-bit
     50   // machines.
     51   struct {
     52     AtomicType prev_word;
     53     AtomicType count;
     54     AtomicType next_word;
     55   } s;
     56 
     57   AtomicType prev_word_value, next_word_value;
     58   memset(&prev_word_value, 0xFF, sizeof(AtomicType));
     59   memset(&next_word_value, 0xEE, sizeof(AtomicType));
     60 
     61   s.prev_word = prev_word_value;
     62   s.count = 0;
     63   s.next_word = next_word_value;
     64 
     65   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 1), 1);
     66   CHECK_EQU(s.count, 1);
     67   CHECK_EQU(s.prev_word, prev_word_value);
     68   CHECK_EQU(s.next_word, next_word_value);
     69 
     70   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 2), 3);
     71   CHECK_EQU(s.count, 3);
     72   CHECK_EQU(s.prev_word, prev_word_value);
     73   CHECK_EQU(s.next_word, next_word_value);
     74 
     75   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 3), 6);
     76   CHECK_EQU(s.count, 6);
     77   CHECK_EQU(s.prev_word, prev_word_value);
     78   CHECK_EQU(s.next_word, next_word_value);
     79 
     80   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -3), 3);
     81   CHECK_EQU(s.count, 3);
     82   CHECK_EQU(s.prev_word, prev_word_value);
     83   CHECK_EQU(s.next_word, next_word_value);
     84 
     85   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -2), 1);
     86   CHECK_EQU(s.count, 1);
     87   CHECK_EQU(s.prev_word, prev_word_value);
     88   CHECK_EQU(s.next_word, next_word_value);
     89 
     90   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -1), 0);
     91   CHECK_EQU(s.count, 0);
     92   CHECK_EQU(s.prev_word, prev_word_value);
     93   CHECK_EQU(s.next_word, next_word_value);
     94 
     95   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -1), -1);
     96   CHECK_EQU(s.count, -1);
     97   CHECK_EQU(s.prev_word, prev_word_value);
     98   CHECK_EQU(s.next_word, next_word_value);
     99 
    100   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, -4), -5);
    101   CHECK_EQU(s.count, -5);
    102   CHECK_EQU(s.prev_word, prev_word_value);
    103   CHECK_EQU(s.next_word, next_word_value);
    104 
    105   CHECK_EQU(NoBarrier_AtomicIncrement(&s.count, 5), 0);
    106   CHECK_EQU(s.count, 0);
    107   CHECK_EQU(s.prev_word, prev_word_value);
    108   CHECK_EQU(s.next_word, next_word_value);
    109 }
    110 
    111 
    112 template <class AtomicType>
    113 static void TestCompareAndSwap() {
    114   AtomicType value = 0;
    115   AtomicType prev = NoBarrier_CompareAndSwap(&value, 0, 1);
    116   CHECK_EQU(1, value);
    117   CHECK_EQU(0, prev);
    118 
    119   // Use a test value that has non-zero bits in both halves, for testing
    120   // the 64-bit implementation on 32-bit platforms.
    121   const AtomicType k_test_val =
    122       (static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) - 2)) + 11;
    123   value = k_test_val;
    124   prev = NoBarrier_CompareAndSwap(&value, 0, 5);
    125   CHECK_EQU(k_test_val, value);
    126   CHECK_EQU(k_test_val, prev);
    127 
    128   value = k_test_val;
    129   prev = NoBarrier_CompareAndSwap(&value, k_test_val, 5);
    130   CHECK_EQU(5, value);
    131   CHECK_EQU(k_test_val, prev);
    132 }
    133 
    134 
    135 template <class AtomicType>
    136 static void TestAtomicExchange() {
    137   AtomicType value = 0;
    138   AtomicType new_value = NoBarrier_AtomicExchange(&value, 1);
    139   CHECK_EQU(1, value);
    140   CHECK_EQU(0, new_value);
    141 
    142   // Use a test value that has non-zero bits in both halves, for testing
    143   // the 64-bit implementation on 32-bit platforms.
    144   const AtomicType k_test_val =
    145       (static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) - 2)) + 11;
    146   value = k_test_val;
    147   new_value = NoBarrier_AtomicExchange(&value, k_test_val);
    148   CHECK_EQU(k_test_val, value);
    149   CHECK_EQU(k_test_val, new_value);
    150 
    151   value = k_test_val;
    152   new_value = NoBarrier_AtomicExchange(&value, 5);
    153   CHECK_EQU(5, value);
    154   CHECK_EQU(k_test_val, new_value);
    155 }
    156 
    157 
    158 template <class AtomicType>
    159 static void TestAtomicIncrementBounds() {
    160   // Test at rollover boundary between int_max and int_min.
    161   AtomicType test_val =
    162       static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) - 1);
    163   AtomicType value = -1 ^ test_val;
    164   AtomicType new_value = NoBarrier_AtomicIncrement(&value, 1);
    165   CHECK_EQU(test_val, value);
    166   CHECK_EQU(value, new_value);
    167 
    168   NoBarrier_AtomicIncrement(&value, -1);
    169   CHECK_EQU(-1 ^ test_val, value);
    170 
    171   // Test at 32-bit boundary for 64-bit atomic type.
    172   test_val = static_cast<AtomicType>(1) << (NUM_BITS(AtomicType) / 2);
    173   value = test_val - 1;
    174   new_value = NoBarrier_AtomicIncrement(&value, 1);
    175   CHECK_EQU(test_val, value);
    176   CHECK_EQU(value, new_value);
    177 
    178   NoBarrier_AtomicIncrement(&value, -1);
    179   CHECK_EQU(test_val - 1, value);
    180 }
    181 
    182 
    183 // Return an AtomicType with the value 0xa5a5a5..
    184 template <class AtomicType>
    185 static AtomicType TestFillValue() {
    186   AtomicType val = 0;
    187   memset(&val, 0xa5, sizeof(AtomicType));
    188   return val;
    189 }
    190 
    191 
    192 // This is a simple sanity check to ensure that values are correct.
    193 // Not testing atomicity.
    194 template <class AtomicType>
    195 static void TestStore() {
    196   const AtomicType kVal1 = TestFillValue<AtomicType>();
    197   const AtomicType kVal2 = static_cast<AtomicType>(-1);
    198 
    199   AtomicType value;
    200 
    201   NoBarrier_Store(&value, kVal1);
    202   CHECK_EQU(kVal1, value);
    203   NoBarrier_Store(&value, kVal2);
    204   CHECK_EQU(kVal2, value);
    205 
    206   Acquire_Store(&value, kVal1);
    207   CHECK_EQU(kVal1, value);
    208   Acquire_Store(&value, kVal2);
    209   CHECK_EQU(kVal2, value);
    210 
    211   Release_Store(&value, kVal1);
    212   CHECK_EQU(kVal1, value);
    213   Release_Store(&value, kVal2);
    214   CHECK_EQU(kVal2, value);
    215 }
    216 
    217 
    218 // Merge this test with TestStore as soon as we have Atomic8 acquire
    219 // and release stores.
    220 static void TestStoreAtomic8() {
    221   const Atomic8 kVal1 = TestFillValue<Atomic8>();
    222   const Atomic8 kVal2 = static_cast<Atomic8>(-1);
    223 
    224   Atomic8 value;
    225 
    226   NoBarrier_Store(&value, kVal1);
    227   CHECK_EQU(kVal1, value);
    228   NoBarrier_Store(&value, kVal2);
    229   CHECK_EQU(kVal2, value);
    230 }
    231 
    232 
    233 // This is a simple sanity check to ensure that values are correct.
    234 // Not testing atomicity.
    235 template <class AtomicType>
    236 static void TestLoad() {
    237   const AtomicType kVal1 = TestFillValue<AtomicType>();
    238   const AtomicType kVal2 = static_cast<AtomicType>(-1);
    239 
    240   AtomicType value;
    241 
    242   value = kVal1;
    243   CHECK_EQU(kVal1, NoBarrier_Load(&value));
    244   value = kVal2;
    245   CHECK_EQU(kVal2, NoBarrier_Load(&value));
    246 
    247   value = kVal1;
    248   CHECK_EQU(kVal1, Acquire_Load(&value));
    249   value = kVal2;
    250   CHECK_EQU(kVal2, Acquire_Load(&value));
    251 
    252   value = kVal1;
    253   CHECK_EQU(kVal1, Release_Load(&value));
    254   value = kVal2;
    255   CHECK_EQU(kVal2, Release_Load(&value));
    256 }
    257 
    258 
    259 // Merge this test with TestLoad as soon as we have Atomic8 acquire
    260 // and release loads.
    261 static void TestLoadAtomic8() {
    262   const Atomic8 kVal1 = TestFillValue<Atomic8>();
    263   const Atomic8 kVal2 = static_cast<Atomic8>(-1);
    264 
    265   Atomic8 value;
    266 
    267   value = kVal1;
    268   CHECK_EQU(kVal1, NoBarrier_Load(&value));
    269   value = kVal2;
    270   CHECK_EQU(kVal2, NoBarrier_Load(&value));
    271 }
    272 
    273 
    274 TEST(AtomicIncrement) {
    275   TestAtomicIncrement<Atomic32>();
    276   TestAtomicIncrement<AtomicWord>();
    277 }
    278 
    279 
    280 TEST(CompareAndSwap) {
    281   TestCompareAndSwap<Atomic32>();
    282   TestCompareAndSwap<AtomicWord>();
    283 }
    284 
    285 
    286 TEST(AtomicExchange) {
    287   TestAtomicExchange<Atomic32>();
    288   TestAtomicExchange<AtomicWord>();
    289 }
    290 
    291 
    292 TEST(AtomicIncrementBounds) {
    293   TestAtomicIncrementBounds<Atomic32>();
    294   TestAtomicIncrementBounds<AtomicWord>();
    295 }
    296 
    297 
    298 TEST(Store) {
    299   TestStoreAtomic8();
    300   TestStore<Atomic32>();
    301   TestStore<AtomicWord>();
    302 }
    303 
    304 
    305 TEST(Load) {
    306   TestLoadAtomic8();
    307   TestLoad<Atomic32>();
    308   TestLoad<AtomicWord>();
    309 }
    310