Line data Source code
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 : namespace v8 {
34 : namespace base {
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 10 : static void TestAtomicIncrement() {
44 : // For now, we just test the single-threaded execution.
45 :
46 : // Use a guard value to make sure that Relaxed_AtomicIncrement doesn't
47 : // go outside the expected address bounds. This is to test that the
48 : // 32-bit Relaxed_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 10 : s.prev_word = prev_word_value;
61 10 : s.count = 0;
62 10 : s.next_word = next_word_value;
63 :
64 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, 1), 1);
65 10 : CHECK_EQU(s.count, 1);
66 10 : CHECK_EQU(s.prev_word, prev_word_value);
67 10 : CHECK_EQU(s.next_word, next_word_value);
68 :
69 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, 2), 3);
70 10 : CHECK_EQU(s.count, 3);
71 10 : CHECK_EQU(s.prev_word, prev_word_value);
72 10 : CHECK_EQU(s.next_word, next_word_value);
73 :
74 5 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, 3), 6);
75 10 : CHECK_EQU(s.count, 6);
76 10 : CHECK_EQU(s.prev_word, prev_word_value);
77 10 : CHECK_EQU(s.next_word, next_word_value);
78 :
79 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, -3), 3);
80 10 : CHECK_EQU(s.count, 3);
81 10 : CHECK_EQU(s.prev_word, prev_word_value);
82 10 : CHECK_EQU(s.next_word, next_word_value);
83 :
84 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, -2), 1);
85 10 : CHECK_EQU(s.count, 1);
86 10 : CHECK_EQU(s.prev_word, prev_word_value);
87 10 : CHECK_EQU(s.next_word, next_word_value);
88 :
89 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, -1), 0);
90 10 : CHECK_EQU(s.count, 0);
91 10 : CHECK_EQU(s.prev_word, prev_word_value);
92 10 : CHECK_EQU(s.next_word, next_word_value);
93 :
94 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, -1), -1);
95 10 : CHECK_EQU(s.count, -1);
96 10 : CHECK_EQU(s.prev_word, prev_word_value);
97 10 : CHECK_EQU(s.next_word, next_word_value);
98 :
99 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, -4), -5);
100 10 : CHECK_EQU(s.count, -5);
101 10 : CHECK_EQU(s.prev_word, prev_word_value);
102 10 : CHECK_EQU(s.next_word, next_word_value);
103 :
104 10 : CHECK_EQU(Relaxed_AtomicIncrement(&s.count, 5), 0);
105 10 : CHECK_EQU(s.count, 0);
106 10 : CHECK_EQU(s.prev_word, prev_word_value);
107 10 : CHECK_EQU(s.next_word, next_word_value);
108 10 : }
109 :
110 :
111 : template <class AtomicType>
112 10 : static void TestCompareAndSwap() {
113 10 : AtomicType value = 0;
114 : AtomicType prev = Relaxed_CompareAndSwap(&value, 0, 1);
115 10 : CHECK_EQU(1, value);
116 10 : 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 10 : value = k_test_val;
123 : prev = Relaxed_CompareAndSwap(&value, 0, 5);
124 10 : CHECK_EQU(k_test_val, value);
125 10 : CHECK_EQU(k_test_val, prev);
126 :
127 10 : value = k_test_val;
128 : prev = Relaxed_CompareAndSwap(&value, k_test_val, 5);
129 10 : CHECK_EQU(5, value);
130 10 : CHECK_EQU(k_test_val, prev);
131 10 : }
132 :
133 :
134 : template <class AtomicType>
135 10 : static void TestAtomicExchange() {
136 10 : AtomicType value = 0;
137 : AtomicType new_value = Relaxed_AtomicExchange(&value, 1);
138 10 : CHECK_EQU(1, value);
139 10 : 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 10 : value = k_test_val;
146 : new_value = Relaxed_AtomicExchange(&value, k_test_val);
147 5 : CHECK_EQU(k_test_val, value);
148 10 : CHECK_EQU(k_test_val, new_value);
149 :
150 10 : value = k_test_val;
151 : new_value = Relaxed_AtomicExchange(&value, 5);
152 10 : CHECK_EQU(5, value);
153 10 : CHECK_EQU(k_test_val, new_value);
154 10 : }
155 :
156 :
157 : template <class AtomicType>
158 10 : static void TestAtomicIncrementBounds() {
159 : // Test at 32-bit boundary for 64-bit atomic type.
160 : AtomicType test_val = static_cast<AtomicType>(1)
161 : << (NUM_BITS(AtomicType) / 2);
162 10 : AtomicType value = test_val - 1;
163 : AtomicType new_value = Relaxed_AtomicIncrement(&value, 1);
164 10 : CHECK_EQU(test_val, value);
165 10 : CHECK_EQU(value, new_value);
166 :
167 : Relaxed_AtomicIncrement(&value, -1);
168 10 : CHECK_EQU(test_val - 1, value);
169 10 : }
170 :
171 : // Return an AtomicType with the value 0xA5A5A5..
172 : template <class AtomicType>
173 : static AtomicType TestFillValue() {
174 : AtomicType val = 0;
175 : memset(&val, 0xA5, sizeof(AtomicType));
176 : return val;
177 : }
178 :
179 :
180 : // This is a simple sanity check to ensure that values are correct.
181 : // Not testing atomicity.
182 : template <class AtomicType>
183 10 : static void TestStore() {
184 : const AtomicType kVal1 = TestFillValue<AtomicType>();
185 : const AtomicType kVal2 = static_cast<AtomicType>(-1);
186 :
187 : AtomicType value;
188 :
189 : Relaxed_Store(&value, kVal1);
190 10 : CHECK_EQU(kVal1, value);
191 : Relaxed_Store(&value, kVal2);
192 10 : CHECK_EQU(kVal2, value);
193 :
194 : Release_Store(&value, kVal1);
195 10 : CHECK_EQU(kVal1, value);
196 : Release_Store(&value, kVal2);
197 10 : CHECK_EQU(kVal2, value);
198 10 : }
199 :
200 :
201 : // Merge this test with TestStore as soon as we have Atomic8 acquire
202 : // and release stores.
203 5 : static void TestStoreAtomic8() {
204 : const Atomic8 kVal1 = TestFillValue<Atomic8>();
205 : const Atomic8 kVal2 = static_cast<Atomic8>(-1);
206 :
207 : Atomic8 value;
208 :
209 : Relaxed_Store(&value, kVal1);
210 5 : CHECK_EQU(kVal1, value);
211 : Relaxed_Store(&value, kVal2);
212 5 : CHECK_EQU(kVal2, value);
213 5 : }
214 :
215 :
216 : // This is a simple sanity check to ensure that values are correct.
217 : // Not testing atomicity.
218 : template <class AtomicType>
219 10 : static void TestLoad() {
220 : const AtomicType kVal1 = TestFillValue<AtomicType>();
221 : const AtomicType kVal2 = static_cast<AtomicType>(-1);
222 :
223 : AtomicType value;
224 :
225 10 : value = kVal1;
226 10 : CHECK_EQU(kVal1, Relaxed_Load(&value));
227 10 : value = kVal2;
228 10 : CHECK_EQU(kVal2, Relaxed_Load(&value));
229 :
230 10 : value = kVal1;
231 10 : CHECK_EQU(kVal1, Acquire_Load(&value));
232 10 : value = kVal2;
233 10 : CHECK_EQU(kVal2, Acquire_Load(&value));
234 10 : }
235 :
236 :
237 : // Merge this test with TestLoad as soon as we have Atomic8 acquire
238 : // and release loads.
239 5 : static void TestLoadAtomic8() {
240 : const Atomic8 kVal1 = TestFillValue<Atomic8>();
241 : const Atomic8 kVal2 = static_cast<Atomic8>(-1);
242 :
243 : Atomic8 value;
244 :
245 5 : value = kVal1;
246 5 : CHECK_EQU(kVal1, Relaxed_Load(&value));
247 5 : value = kVal2;
248 5 : CHECK_EQU(kVal2, Relaxed_Load(&value));
249 5 : }
250 :
251 :
252 26644 : TEST(AtomicIncrement) {
253 5 : TestAtomicIncrement<Atomic32>();
254 5 : TestAtomicIncrement<AtomicWord>();
255 5 : }
256 :
257 :
258 26644 : TEST(CompareAndSwap) {
259 5 : TestCompareAndSwap<Atomic32>();
260 5 : TestCompareAndSwap<AtomicWord>();
261 5 : }
262 :
263 :
264 26644 : TEST(AtomicExchange) {
265 5 : TestAtomicExchange<Atomic32>();
266 5 : TestAtomicExchange<AtomicWord>();
267 5 : }
268 :
269 :
270 26644 : TEST(AtomicIncrementBounds) {
271 5 : TestAtomicIncrementBounds<Atomic32>();
272 5 : TestAtomicIncrementBounds<AtomicWord>();
273 5 : }
274 :
275 :
276 26644 : TEST(Store) {
277 5 : TestStoreAtomic8();
278 5 : TestStore<Atomic32>();
279 5 : TestStore<AtomicWord>();
280 5 : }
281 :
282 :
283 26644 : TEST(Load) {
284 5 : TestLoadAtomic8();
285 5 : TestLoad<Atomic32>();
286 5 : TestLoad<AtomicWord>();
287 5 : }
288 :
289 : } // namespace base
290 79917 : } // namespace v8
|