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