Line data Source code
1 : // Copyright 2016 the V8 project authors. All rights reserved. Use of this
2 : // source code is governed by a BSD-style license that can be found in the
3 : // LICENSE file.
4 :
5 : #include <cmath>
6 : #include <functional>
7 : #include <limits>
8 :
9 : #include "src/base/bits.h"
10 : #include "src/base/utils/random-number-generator.h"
11 : #include "src/codegen.h"
12 : #include "src/objects-inl.h"
13 : #include "test/cctest/cctest.h"
14 : #include "test/cctest/compiler/codegen-tester.h"
15 : #include "test/cctest/compiler/graph-builder-tester.h"
16 : #include "test/cctest/compiler/value-helper.h"
17 :
18 :
19 : namespace {
20 : template <typename Type>
21 : void CheckOobValue(Type val) {
22 : UNREACHABLE();
23 : }
24 :
25 : template <>
26 7656 : void CheckOobValue(int32_t val) {
27 7656 : CHECK_EQ(0, val);
28 7656 : }
29 :
30 : template <>
31 6 : void CheckOobValue(int64_t val) {
32 6 : CHECK_EQ(0, val);
33 6 : }
34 :
35 : template <>
36 3588 : void CheckOobValue(float val) {
37 3588 : CHECK(std::isnan(val));
38 3588 : }
39 :
40 : template <>
41 3588 : void CheckOobValue(double val) {
42 3588 : CHECK(std::isnan(val));
43 3588 : }
44 : } // namespace
45 :
46 : namespace v8 {
47 : namespace internal {
48 : namespace compiler {
49 :
50 : enum TestAlignment {
51 : kAligned,
52 : kUnaligned,
53 : };
54 :
55 : // This is a America!
56 : #define A_BILLION 1000000000ULL
57 : #define A_GIG (1024ULL * 1024ULL * 1024ULL)
58 :
59 : namespace {
60 12 : void RunLoadInt32(const TestAlignment t) {
61 12 : RawMachineAssemblerTester<int32_t> m;
62 :
63 12 : int32_t p1 = 0; // loads directly from this location.
64 :
65 12 : if (t == TestAlignment::kAligned) {
66 6 : m.Return(m.LoadFromPointer(&p1, MachineType::Int32()));
67 6 : } else if (t == TestAlignment::kUnaligned) {
68 6 : m.Return(m.UnalignedLoadFromPointer(&p1, MachineType::Int32()));
69 : } else {
70 0 : UNREACHABLE();
71 : }
72 :
73 708 : FOR_INT32_INPUTS(i) {
74 696 : p1 = *i;
75 696 : CHECK_EQ(p1, m.Call());
76 : }
77 12 : }
78 :
79 12 : void RunLoadInt32Offset(TestAlignment t) {
80 12 : int32_t p1 = 0; // loads directly from this location.
81 :
82 : int32_t offsets[] = {-2000000, -100, -101, 1, 3,
83 12 : 7, 120, 2000, 2000000000, 0xff};
84 :
85 132 : for (size_t i = 0; i < arraysize(offsets); i++) {
86 120 : RawMachineAssemblerTester<int32_t> m;
87 120 : int32_t offset = offsets[i];
88 120 : byte* pointer = reinterpret_cast<byte*>(&p1) - offset;
89 :
90 : // generate load [#base + #index]
91 120 : if (t == TestAlignment::kAligned) {
92 60 : m.Return(m.LoadFromPointer(pointer, MachineType::Int32(), offset));
93 60 : } else if (t == TestAlignment::kUnaligned) {
94 : m.Return(
95 60 : m.UnalignedLoadFromPointer(pointer, MachineType::Int32(), offset));
96 : } else {
97 0 : UNREACHABLE();
98 : }
99 :
100 7080 : FOR_INT32_INPUTS(j) {
101 6960 : p1 = *j;
102 6960 : CHECK_EQ(p1, m.Call());
103 : }
104 : }
105 12 : }
106 :
107 12 : void RunLoadStoreFloat32Offset(TestAlignment t) {
108 12 : float p1 = 0.0f; // loads directly from this location.
109 12 : float p2 = 0.0f; // and stores directly into this location.
110 :
111 708 : FOR_INT32_INPUTS(i) {
112 696 : int32_t magic = 0x2342aabb + *i * 3;
113 696 : RawMachineAssemblerTester<int32_t> m;
114 696 : int32_t offset = *i;
115 696 : byte* from = reinterpret_cast<byte*>(&p1) - offset;
116 696 : byte* to = reinterpret_cast<byte*>(&p2) - offset;
117 : // generate load [#base + #index]
118 696 : if (t == TestAlignment::kAligned) {
119 : Node* load = m.Load(MachineType::Float32(), m.PointerConstant(from),
120 696 : m.IntPtrConstant(offset));
121 : m.Store(MachineRepresentation::kFloat32, m.PointerConstant(to),
122 348 : m.IntPtrConstant(offset), load, kNoWriteBarrier);
123 348 : } else if (t == TestAlignment::kUnaligned) {
124 : Node* load =
125 : m.UnalignedLoad(MachineType::Float32(), m.PointerConstant(from),
126 696 : m.IntPtrConstant(offset));
127 : m.UnalignedStore(MachineRepresentation::kFloat32, m.PointerConstant(to),
128 348 : m.IntPtrConstant(offset), load);
129 :
130 : } else {
131 0 : UNREACHABLE();
132 : }
133 696 : m.Return(m.Int32Constant(magic));
134 :
135 80736 : FOR_FLOAT32_INPUTS(j) {
136 80040 : p1 = *j;
137 80040 : p2 = *j - 5;
138 80040 : CHECK_EQ(magic, m.Call());
139 80040 : CheckDoubleEq(p1, p2);
140 : }
141 : }
142 12 : }
143 :
144 12 : void RunLoadStoreFloat64Offset(TestAlignment t) {
145 12 : double p1 = 0; // loads directly from this location.
146 12 : double p2 = 0; // and stores directly into this location.
147 :
148 708 : FOR_INT32_INPUTS(i) {
149 696 : int32_t magic = 0x2342aabb + *i * 3;
150 696 : RawMachineAssemblerTester<int32_t> m;
151 696 : int32_t offset = *i;
152 696 : byte* from = reinterpret_cast<byte*>(&p1) - offset;
153 696 : byte* to = reinterpret_cast<byte*>(&p2) - offset;
154 : // generate load [#base + #index]
155 696 : if (t == TestAlignment::kAligned) {
156 : Node* load = m.Load(MachineType::Float64(), m.PointerConstant(from),
157 696 : m.IntPtrConstant(offset));
158 : m.Store(MachineRepresentation::kFloat64, m.PointerConstant(to),
159 348 : m.IntPtrConstant(offset), load, kNoWriteBarrier);
160 348 : } else if (t == TestAlignment::kUnaligned) {
161 : Node* load =
162 : m.UnalignedLoad(MachineType::Float64(), m.PointerConstant(from),
163 696 : m.IntPtrConstant(offset));
164 : m.UnalignedStore(MachineRepresentation::kFloat64, m.PointerConstant(to),
165 348 : m.IntPtrConstant(offset), load);
166 : } else {
167 0 : UNREACHABLE();
168 : }
169 696 : m.Return(m.Int32Constant(magic));
170 :
171 34800 : FOR_FLOAT64_INPUTS(j) {
172 34104 : p1 = *j;
173 34104 : p2 = *j - 5;
174 34104 : CHECK_EQ(magic, m.Call());
175 34104 : CheckDoubleEq(p1, p2);
176 : }
177 : }
178 12 : }
179 : } // namespace
180 :
181 23724 : TEST(RunLoadInt32) { RunLoadInt32(TestAlignment::kAligned); }
182 :
183 23724 : TEST(RunUnalignedLoadInt32) { RunLoadInt32(TestAlignment::kUnaligned); }
184 :
185 23724 : TEST(RunLoadInt32Offset) { RunLoadInt32Offset(TestAlignment::kAligned); }
186 :
187 23724 : TEST(RunUnalignedLoadInt32Offset) {
188 6 : RunLoadInt32Offset(TestAlignment::kUnaligned);
189 6 : }
190 :
191 23724 : TEST(RunLoadStoreFloat32Offset) {
192 6 : RunLoadStoreFloat32Offset(TestAlignment::kAligned);
193 6 : }
194 :
195 23724 : TEST(RunUnalignedLoadStoreFloat32Offset) {
196 6 : RunLoadStoreFloat32Offset(TestAlignment::kUnaligned);
197 6 : }
198 :
199 23724 : TEST(RunLoadStoreFloat64Offset) {
200 6 : RunLoadStoreFloat64Offset(TestAlignment::kAligned);
201 6 : }
202 :
203 23724 : TEST(RunUnalignedLoadStoreFloat64Offset) {
204 6 : RunLoadStoreFloat64Offset(TestAlignment::kUnaligned);
205 6 : }
206 :
207 : namespace {
208 : template <typename Type>
209 108 : void RunLoadImmIndex(MachineType rep, TestAlignment t) {
210 : const int kNumElems = 3;
211 : Type buffer[kNumElems];
212 :
213 : // initialize the buffer with some raw data.
214 : byte* raw = reinterpret_cast<byte*>(buffer);
215 1584 : for (size_t i = 0; i < sizeof(buffer); i++) {
216 1476 : raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
217 : }
218 :
219 : // Test with various large and small offsets.
220 972 : for (int offset = -1; offset <= 200000; offset *= -5) {
221 2916 : for (int i = 0; i < kNumElems; i++) {
222 2916 : BufferedRawMachineAssemblerTester<Type> m;
223 2916 : Node* base = m.PointerConstant(buffer - offset);
224 2916 : Node* index = m.Int32Constant((offset + i) * sizeof(buffer[0]));
225 2916 : if (t == TestAlignment::kAligned) {
226 1620 : m.Return(m.Load(rep, base, index));
227 1296 : } else if (t == TestAlignment::kUnaligned) {
228 1296 : m.Return(m.UnalignedLoad(rep, base, index));
229 : } else {
230 0 : UNREACHABLE();
231 : }
232 :
233 2916 : volatile Type expected = buffer[i];
234 2916 : volatile Type actual = m.Call();
235 2916 : CHECK_EQ(expected, actual);
236 : }
237 : }
238 108 : }
239 :
240 : template <typename CType>
241 108 : void RunLoadStore(MachineType rep, TestAlignment t) {
242 : const int kNumElems = 4;
243 : CType buffer[kNumElems];
244 :
245 540 : for (int32_t x = 0; x < kNumElems; x++) {
246 432 : int32_t y = kNumElems - x - 1;
247 : // initialize the buffer with raw data.
248 : byte* raw = reinterpret_cast<byte*>(buffer);
249 8304 : for (size_t i = 0; i < sizeof(buffer); i++) {
250 7872 : raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
251 : }
252 :
253 432 : RawMachineAssemblerTester<int32_t> m;
254 432 : int32_t OK = 0x29000 + x;
255 : Node* base = m.PointerConstant(buffer);
256 432 : Node* index0 = m.IntPtrConstant(x * sizeof(buffer[0]));
257 432 : Node* index1 = m.IntPtrConstant(y * sizeof(buffer[0]));
258 432 : if (t == TestAlignment::kAligned) {
259 240 : Node* load = m.Load(rep, base, index0);
260 240 : m.Store(rep.representation(), base, index1, load, kNoWriteBarrier);
261 192 : } else if (t == TestAlignment::kUnaligned) {
262 192 : Node* load = m.UnalignedLoad(rep, base, index0);
263 192 : m.UnalignedStore(rep.representation(), base, index1, load);
264 : }
265 :
266 432 : m.Return(m.Int32Constant(OK));
267 :
268 432 : CHECK(buffer[x] != buffer[y]);
269 432 : CHECK_EQ(OK, m.Call());
270 432 : CHECK(buffer[x] == buffer[y]);
271 : }
272 108 : }
273 :
274 : template <typename CType>
275 48 : void RunUnalignedLoadStoreUnalignedAccess(MachineType rep) {
276 : CType in, out;
277 : CType in_buffer[2];
278 : CType out_buffer[2];
279 : byte* raw;
280 :
281 288 : for (int x = 0; x < static_cast<int>(sizeof(CType)); x++) {
282 240 : int y = sizeof(CType) - x;
283 :
284 : raw = reinterpret_cast<byte*>(&in);
285 1728 : for (size_t i = 0; i < sizeof(CType); i++) {
286 1488 : raw[i] = static_cast<byte>((i + sizeof(CType)) ^ 0xAA);
287 : }
288 :
289 : raw = reinterpret_cast<byte*>(in_buffer);
290 240 : MemCopy(raw + x, &in, sizeof(CType));
291 :
292 240 : RawMachineAssemblerTester<int32_t> m;
293 240 : int32_t OK = 0x29000 + x;
294 :
295 : Node* base0 = m.PointerConstant(in_buffer);
296 : Node* base1 = m.PointerConstant(out_buffer);
297 240 : Node* index0 = m.IntPtrConstant(x);
298 240 : Node* index1 = m.IntPtrConstant(y);
299 240 : Node* load = m.UnalignedLoad(rep, base0, index0);
300 240 : m.UnalignedStore(rep.representation(), base1, index1, load);
301 :
302 240 : m.Return(m.Int32Constant(OK));
303 :
304 240 : CHECK_EQ(OK, m.Call());
305 :
306 : raw = reinterpret_cast<byte*>(&out_buffer);
307 240 : MemCopy(&out, raw + y, sizeof(CType));
308 240 : CHECK(in == out);
309 : }
310 48 : }
311 : } // namespace
312 :
313 23724 : TEST(RunLoadImmIndex) {
314 6 : RunLoadImmIndex<int8_t>(MachineType::Int8(), TestAlignment::kAligned);
315 6 : RunLoadImmIndex<uint8_t>(MachineType::Uint8(), TestAlignment::kAligned);
316 6 : RunLoadImmIndex<int16_t>(MachineType::Int16(), TestAlignment::kAligned);
317 6 : RunLoadImmIndex<uint16_t>(MachineType::Uint16(), TestAlignment::kAligned);
318 6 : RunLoadImmIndex<int32_t>(MachineType::Int32(), TestAlignment::kAligned);
319 6 : RunLoadImmIndex<uint32_t>(MachineType::Uint32(), TestAlignment::kAligned);
320 6 : RunLoadImmIndex<int32_t*>(MachineType::AnyTagged(), TestAlignment::kAligned);
321 6 : RunLoadImmIndex<float>(MachineType::Float32(), TestAlignment::kAligned);
322 6 : RunLoadImmIndex<double>(MachineType::Float64(), TestAlignment::kAligned);
323 : #if V8_TARGET_ARCH_64_BIT
324 6 : RunLoadImmIndex<int64_t>(MachineType::Int64(), TestAlignment::kAligned);
325 : #endif
326 : // TODO(titzer): test various indexing modes.
327 6 : }
328 :
329 23724 : TEST(RunUnalignedLoadImmIndex) {
330 6 : RunLoadImmIndex<int16_t>(MachineType::Int16(), TestAlignment::kUnaligned);
331 6 : RunLoadImmIndex<uint16_t>(MachineType::Uint16(), TestAlignment::kUnaligned);
332 6 : RunLoadImmIndex<int32_t>(MachineType::Int32(), TestAlignment::kUnaligned);
333 6 : RunLoadImmIndex<uint32_t>(MachineType::Uint32(), TestAlignment::kUnaligned);
334 : RunLoadImmIndex<int32_t*>(MachineType::AnyTagged(),
335 6 : TestAlignment::kUnaligned);
336 6 : RunLoadImmIndex<float>(MachineType::Float32(), TestAlignment::kUnaligned);
337 6 : RunLoadImmIndex<double>(MachineType::Float64(), TestAlignment::kUnaligned);
338 : #if V8_TARGET_ARCH_64_BIT
339 6 : RunLoadImmIndex<int64_t>(MachineType::Int64(), TestAlignment::kUnaligned);
340 : #endif
341 : // TODO(titzer): test various indexing modes.
342 6 : }
343 :
344 23724 : TEST(RunLoadStore) {
345 6 : RunLoadStore<int8_t>(MachineType::Int8(), TestAlignment::kAligned);
346 6 : RunLoadStore<uint8_t>(MachineType::Uint8(), TestAlignment::kAligned);
347 6 : RunLoadStore<int16_t>(MachineType::Int16(), TestAlignment::kAligned);
348 6 : RunLoadStore<uint16_t>(MachineType::Uint16(), TestAlignment::kAligned);
349 6 : RunLoadStore<int32_t>(MachineType::Int32(), TestAlignment::kAligned);
350 6 : RunLoadStore<uint32_t>(MachineType::Uint32(), TestAlignment::kAligned);
351 6 : RunLoadStore<void*>(MachineType::AnyTagged(), TestAlignment::kAligned);
352 6 : RunLoadStore<float>(MachineType::Float32(), TestAlignment::kAligned);
353 6 : RunLoadStore<double>(MachineType::Float64(), TestAlignment::kAligned);
354 : #if V8_TARGET_ARCH_64_BIT
355 6 : RunLoadStore<int64_t>(MachineType::Int64(), TestAlignment::kAligned);
356 : #endif
357 6 : }
358 :
359 23724 : TEST(RunUnalignedLoadStore) {
360 6 : RunLoadStore<int16_t>(MachineType::Int16(), TestAlignment::kUnaligned);
361 6 : RunLoadStore<uint16_t>(MachineType::Uint16(), TestAlignment::kUnaligned);
362 6 : RunLoadStore<int32_t>(MachineType::Int32(), TestAlignment::kUnaligned);
363 6 : RunLoadStore<uint32_t>(MachineType::Uint32(), TestAlignment::kUnaligned);
364 6 : RunLoadStore<void*>(MachineType::AnyTagged(), TestAlignment::kUnaligned);
365 6 : RunLoadStore<float>(MachineType::Float32(), TestAlignment::kUnaligned);
366 6 : RunLoadStore<double>(MachineType::Float64(), TestAlignment::kUnaligned);
367 : #if V8_TARGET_ARCH_64_BIT
368 6 : RunLoadStore<int64_t>(MachineType::Int64(), TestAlignment::kUnaligned);
369 : #endif
370 6 : }
371 :
372 23724 : TEST(RunUnalignedLoadStoreUnalignedAccess) {
373 6 : RunUnalignedLoadStoreUnalignedAccess<int16_t>(MachineType::Int16());
374 6 : RunUnalignedLoadStoreUnalignedAccess<uint16_t>(MachineType::Uint16());
375 6 : RunUnalignedLoadStoreUnalignedAccess<int32_t>(MachineType::Int32());
376 6 : RunUnalignedLoadStoreUnalignedAccess<uint32_t>(MachineType::Uint32());
377 6 : RunUnalignedLoadStoreUnalignedAccess<void*>(MachineType::AnyTagged());
378 6 : RunUnalignedLoadStoreUnalignedAccess<float>(MachineType::Float32());
379 6 : RunUnalignedLoadStoreUnalignedAccess<double>(MachineType::Float64());
380 : #if V8_TARGET_ARCH_64_BIT
381 6 : RunUnalignedLoadStoreUnalignedAccess<int64_t>(MachineType::Int64());
382 : #endif
383 6 : }
384 :
385 : #if V8_TARGET_LITTLE_ENDIAN
386 : #define LSB(addr, bytes) addr
387 : #elif V8_TARGET_BIG_ENDIAN
388 : #define LSB(addr, bytes) reinterpret_cast<byte*>(addr + 1) - bytes
389 : #else
390 : #error "Unknown Architecture"
391 : #endif
392 :
393 : namespace {
394 12 : void RunLoadStoreSignExtend32(TestAlignment t) {
395 : int32_t buffer[4];
396 12 : RawMachineAssemblerTester<int32_t> m;
397 12 : Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Int8());
398 12 : if (t == TestAlignment::kAligned) {
399 6 : Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Int16());
400 6 : Node* load32 = m.LoadFromPointer(&buffer[0], MachineType::Int32());
401 6 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord32, load8);
402 6 : m.StoreToPointer(&buffer[2], MachineRepresentation::kWord32, load16);
403 6 : m.StoreToPointer(&buffer[3], MachineRepresentation::kWord32, load32);
404 6 : } else if (t == TestAlignment::kUnaligned) {
405 : Node* load16 =
406 6 : m.UnalignedLoadFromPointer(LSB(&buffer[0], 2), MachineType::Int16());
407 6 : Node* load32 = m.UnalignedLoadFromPointer(&buffer[0], MachineType::Int32());
408 6 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord32, load8);
409 : m.UnalignedStoreToPointer(&buffer[2], MachineRepresentation::kWord32,
410 6 : load16);
411 : m.UnalignedStoreToPointer(&buffer[3], MachineRepresentation::kWord32,
412 6 : load32);
413 : } else {
414 0 : UNREACHABLE();
415 : }
416 12 : m.Return(load8);
417 :
418 708 : FOR_INT32_INPUTS(i) {
419 696 : buffer[0] = *i;
420 :
421 1392 : CHECK_EQ(static_cast<int8_t>(*i & 0xff), m.Call());
422 696 : CHECK_EQ(static_cast<int8_t>(*i & 0xff), buffer[1]);
423 1392 : CHECK_EQ(static_cast<int16_t>(*i & 0xffff), buffer[2]);
424 696 : CHECK_EQ(*i, buffer[3]);
425 : }
426 12 : }
427 :
428 12 : void RunLoadStoreZeroExtend32(TestAlignment t) {
429 : uint32_t buffer[4];
430 12 : RawMachineAssemblerTester<uint32_t> m;
431 12 : Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Uint8());
432 12 : if (t == TestAlignment::kAligned) {
433 6 : Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Uint16());
434 6 : Node* load32 = m.LoadFromPointer(&buffer[0], MachineType::Uint32());
435 6 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord32, load8);
436 6 : m.StoreToPointer(&buffer[2], MachineRepresentation::kWord32, load16);
437 6 : m.StoreToPointer(&buffer[3], MachineRepresentation::kWord32, load32);
438 6 : } else if (t == TestAlignment::kUnaligned) {
439 : Node* load16 =
440 6 : m.UnalignedLoadFromPointer(LSB(&buffer[0], 2), MachineType::Uint16());
441 : Node* load32 =
442 6 : m.UnalignedLoadFromPointer(&buffer[0], MachineType::Uint32());
443 6 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord32, load8);
444 : m.UnalignedStoreToPointer(&buffer[2], MachineRepresentation::kWord32,
445 6 : load16);
446 : m.UnalignedStoreToPointer(&buffer[3], MachineRepresentation::kWord32,
447 6 : load32);
448 : }
449 12 : m.Return(load8);
450 :
451 708 : FOR_UINT32_INPUTS(i) {
452 696 : buffer[0] = *i;
453 :
454 696 : CHECK_EQ((*i & 0xff), m.Call());
455 696 : CHECK_EQ((*i & 0xff), buffer[1]);
456 696 : CHECK_EQ((*i & 0xffff), buffer[2]);
457 696 : CHECK_EQ(*i, buffer[3]);
458 : }
459 12 : }
460 : } // namespace
461 :
462 23724 : TEST(RunLoadStoreSignExtend32) {
463 6 : RunLoadStoreSignExtend32(TestAlignment::kAligned);
464 6 : }
465 :
466 23724 : TEST(RunUnalignedLoadStoreSignExtend32) {
467 6 : RunLoadStoreSignExtend32(TestAlignment::kUnaligned);
468 6 : }
469 :
470 23724 : TEST(RunLoadStoreZeroExtend32) {
471 6 : RunLoadStoreZeroExtend32(TestAlignment::kAligned);
472 6 : }
473 :
474 23724 : TEST(RunUnalignedLoadStoreZeroExtend32) {
475 6 : RunLoadStoreZeroExtend32(TestAlignment::kUnaligned);
476 6 : }
477 :
478 : #if V8_TARGET_ARCH_64_BIT
479 :
480 : namespace {
481 : void RunLoadStoreSignExtend64(TestAlignment t) {
482 : if (true) return; // TODO(titzer): sign extension of loads to 64-bit.
483 : int64_t buffer[5];
484 : RawMachineAssemblerTester<int64_t> m;
485 : Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Int8());
486 : if (t == TestAlignment::kAligned) {
487 : Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Int16());
488 : Node* load32 = m.LoadFromPointer(LSB(&buffer[0], 4), MachineType::Int32());
489 : Node* load64 = m.LoadFromPointer(&buffer[0], MachineType::Int64());
490 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord64, load8);
491 : m.StoreToPointer(&buffer[2], MachineRepresentation::kWord64, load16);
492 : m.StoreToPointer(&buffer[3], MachineRepresentation::kWord64, load32);
493 : m.StoreToPointer(&buffer[4], MachineRepresentation::kWord64, load64);
494 : } else if (t == TestAlignment::kUnaligned) {
495 : Node* load16 =
496 : m.UnalignedLoadFromPointer(LSB(&buffer[0], 2), MachineType::Int16());
497 : Node* load32 =
498 : m.UnalignedLoadFromPointer(LSB(&buffer[0], 4), MachineType::Int32());
499 : Node* load64 = m.UnalignedLoadFromPointer(&buffer[0], MachineType::Int64());
500 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord64, load8);
501 : m.UnalignedStoreToPointer(&buffer[2], MachineRepresentation::kWord64,
502 : load16);
503 : m.UnalignedStoreToPointer(&buffer[3], MachineRepresentation::kWord64,
504 : load32);
505 : m.UnalignedStoreToPointer(&buffer[4], MachineRepresentation::kWord64,
506 : load64);
507 : } else {
508 : UNREACHABLE();
509 : }
510 : m.Return(load8);
511 :
512 : FOR_INT64_INPUTS(i) {
513 : buffer[0] = *i;
514 :
515 : CHECK_EQ(static_cast<int8_t>(*i & 0xff), m.Call());
516 : CHECK_EQ(static_cast<int8_t>(*i & 0xff), buffer[1]);
517 : CHECK_EQ(static_cast<int16_t>(*i & 0xffff), buffer[2]);
518 : CHECK_EQ(static_cast<int32_t>(*i & 0xffffffff), buffer[3]);
519 : CHECK_EQ(*i, buffer[4]);
520 : }
521 : }
522 :
523 12 : void RunLoadStoreZeroExtend64(TestAlignment t) {
524 12 : if (kPointerSize < 8) return;
525 : uint64_t buffer[5];
526 12 : RawMachineAssemblerTester<uint64_t> m;
527 12 : Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Uint8());
528 12 : if (t == TestAlignment::kAligned) {
529 6 : Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Uint16());
530 6 : Node* load32 = m.LoadFromPointer(LSB(&buffer[0], 4), MachineType::Uint32());
531 6 : Node* load64 = m.LoadFromPointer(&buffer[0], MachineType::Uint64());
532 6 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord64, load8);
533 6 : m.StoreToPointer(&buffer[2], MachineRepresentation::kWord64, load16);
534 6 : m.StoreToPointer(&buffer[3], MachineRepresentation::kWord64, load32);
535 6 : m.StoreToPointer(&buffer[4], MachineRepresentation::kWord64, load64);
536 6 : } else if (t == TestAlignment::kUnaligned) {
537 : Node* load16 =
538 6 : m.UnalignedLoadFromPointer(LSB(&buffer[0], 2), MachineType::Uint16());
539 : Node* load32 =
540 6 : m.UnalignedLoadFromPointer(LSB(&buffer[0], 4), MachineType::Uint32());
541 : Node* load64 =
542 6 : m.UnalignedLoadFromPointer(&buffer[0], MachineType::Uint64());
543 6 : m.StoreToPointer(&buffer[1], MachineRepresentation::kWord64, load8);
544 : m.UnalignedStoreToPointer(&buffer[2], MachineRepresentation::kWord64,
545 6 : load16);
546 : m.UnalignedStoreToPointer(&buffer[3], MachineRepresentation::kWord64,
547 6 : load32);
548 : m.UnalignedStoreToPointer(&buffer[4], MachineRepresentation::kWord64,
549 6 : load64);
550 : } else {
551 0 : UNREACHABLE();
552 : }
553 12 : m.Return(load8);
554 :
555 984 : FOR_UINT64_INPUTS(i) {
556 972 : buffer[0] = *i;
557 :
558 972 : CHECK_EQ((*i & 0xff), m.Call());
559 972 : CHECK_EQ((*i & 0xff), buffer[1]);
560 972 : CHECK_EQ((*i & 0xffff), buffer[2]);
561 972 : CHECK_EQ((*i & 0xffffffff), buffer[3]);
562 972 : CHECK_EQ(*i, buffer[4]);
563 : }
564 : }
565 :
566 : } // namespace
567 :
568 23724 : TEST(RunCheckedLoadInt64) {
569 6 : int64_t buffer[] = {0x66bbccddeeff0011LL, 0x1122334455667788LL};
570 6 : RawMachineAssemblerTester<int64_t> m(MachineType::Int32());
571 : Node* base = m.PointerConstant(buffer);
572 6 : Node* index = m.Parameter(0);
573 6 : Node* length = m.Int32Constant(16);
574 : Node* load = m.AddNode(m.machine()->CheckedLoad(MachineType::Int64()), base,
575 6 : index, length);
576 6 : m.Return(load);
577 :
578 6 : CHECK_EQ(buffer[0], m.Call(0));
579 6 : CHECK_EQ(buffer[1], m.Call(8));
580 6 : CheckOobValue(m.Call(16));
581 6 : }
582 :
583 23724 : TEST(RunLoadStoreSignExtend64) {
584 : RunLoadStoreSignExtend64(TestAlignment::kAligned);
585 6 : }
586 :
587 23724 : TEST(RunUnalignedLoadStoreSignExtend64) {
588 : RunLoadStoreSignExtend64(TestAlignment::kUnaligned);
589 6 : }
590 :
591 23724 : TEST(RunLoadStoreZeroExtend64) {
592 6 : RunLoadStoreZeroExtend64(TestAlignment::kAligned);
593 6 : }
594 :
595 23724 : TEST(RunUnalignedLoadStoreZeroExtend64) {
596 6 : RunLoadStoreZeroExtend64(TestAlignment::kUnaligned);
597 6 : }
598 :
599 23724 : TEST(RunCheckedStoreInt64) {
600 : const int64_t write = 0x5566778899aabbLL;
601 : const int64_t before = 0x33bbccddeeff0011LL;
602 6 : int64_t buffer[] = {before, before};
603 6 : RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
604 : Node* base = m.PointerConstant(buffer);
605 6 : Node* index = m.Parameter(0);
606 6 : Node* length = m.Int32Constant(16);
607 6 : Node* value = m.Int64Constant(write);
608 : Node* store =
609 : m.AddNode(m.machine()->CheckedStore(MachineRepresentation::kWord64), base,
610 6 : index, length, value);
611 : USE(store);
612 6 : m.Return(m.Int32Constant(11));
613 :
614 6 : CHECK_EQ(11, m.Call(16));
615 6 : CHECK_EQ(before, buffer[0]);
616 6 : CHECK_EQ(before, buffer[1]);
617 :
618 6 : CHECK_EQ(11, m.Call(0));
619 6 : CHECK_EQ(write, buffer[0]);
620 6 : CHECK_EQ(before, buffer[1]);
621 :
622 6 : CHECK_EQ(11, m.Call(8));
623 6 : CHECK_EQ(write, buffer[0]);
624 6 : CHECK_EQ(write, buffer[1]);
625 6 : }
626 : #endif
627 :
628 : namespace {
629 : template <typename IntType>
630 18 : void LoadStoreTruncation(MachineType kRepresentation, TestAlignment t) {
631 : IntType input;
632 :
633 18 : RawMachineAssemblerTester<int32_t> m;
634 : Node* ap1;
635 18 : if (t == TestAlignment::kAligned) {
636 12 : Node* a = m.LoadFromPointer(&input, kRepresentation);
637 12 : ap1 = m.Int32Add(a, m.Int32Constant(1));
638 12 : m.StoreToPointer(&input, kRepresentation.representation(), ap1);
639 6 : } else if (t == TestAlignment::kUnaligned) {
640 6 : Node* a = m.UnalignedLoadFromPointer(&input, kRepresentation);
641 6 : ap1 = m.Int32Add(a, m.Int32Constant(1));
642 6 : m.UnalignedStoreToPointer(&input, kRepresentation.representation(), ap1);
643 : } else {
644 0 : UNREACHABLE();
645 : }
646 18 : m.Return(ap1);
647 :
648 : const IntType max = std::numeric_limits<IntType>::max();
649 : const IntType min = std::numeric_limits<IntType>::min();
650 :
651 : // Test upper bound.
652 18 : input = max;
653 18 : CHECK_EQ(max + 1, m.Call());
654 18 : CHECK_EQ(min, input);
655 :
656 : // Test lower bound.
657 18 : input = min;
658 18 : CHECK_EQ(static_cast<IntType>(max + 2), m.Call());
659 18 : CHECK_EQ(min + 1, input);
660 :
661 : // Test all one byte values that are not one byte bounds.
662 4572 : for (int i = -127; i < 127; i++) {
663 4572 : input = i;
664 4572 : int expected = i >= 0 ? i + 1 : max + (i - min) + 2;
665 9144 : CHECK_EQ(static_cast<IntType>(expected), m.Call());
666 4572 : CHECK_EQ(static_cast<IntType>(i + 1), input);
667 : }
668 18 : }
669 : } // namespace
670 :
671 23724 : TEST(RunLoadStoreTruncation) {
672 6 : LoadStoreTruncation<int8_t>(MachineType::Int8(), TestAlignment::kAligned);
673 6 : LoadStoreTruncation<int16_t>(MachineType::Int16(), TestAlignment::kAligned);
674 6 : }
675 :
676 23724 : TEST(RunUnalignedLoadStoreTruncation) {
677 6 : LoadStoreTruncation<int16_t>(MachineType::Int16(), TestAlignment::kUnaligned);
678 6 : }
679 :
680 12 : void TestRunOobCheckedLoad(bool length_is_immediate) {
681 : USE(CheckOobValue<int32_t>);
682 : USE(CheckOobValue<int64_t>);
683 : USE(CheckOobValue<float>);
684 : USE(CheckOobValue<double>);
685 :
686 : RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
687 12 : MachineType::Int32());
688 12 : MachineOperatorBuilder machine(m.zone());
689 : const int32_t kNumElems = 27;
690 : const int32_t kLength = kNumElems * 4;
691 :
692 : int32_t buffer[kNumElems];
693 : Node* base = m.PointerConstant(buffer);
694 12 : Node* offset = m.Parameter(0);
695 12 : Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
696 : Node* node =
697 12 : m.AddNode(machine.CheckedLoad(MachineType::Int32()), base, offset, len);
698 12 : m.Return(node);
699 :
700 : {
701 : // randomize memory.
702 12 : v8::base::RandomNumberGenerator rng;
703 12 : rng.SetSeed(100);
704 12 : rng.NextBytes(&buffer[0], sizeof(buffer));
705 : }
706 :
707 : // in-bounds accesses.
708 336 : for (int32_t i = 0; i < kNumElems; i++) {
709 324 : int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
710 324 : int32_t expected = buffer[i];
711 324 : CHECK_EQ(expected, m.Call(offset, kLength));
712 : }
713 :
714 : // slightly out-of-bounds accesses.
715 : for (int32_t i = kLength; i < kNumElems + 30; i++) {
716 : int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
717 : CheckOobValue(m.Call(offset, kLength));
718 : }
719 :
720 : // way out-of-bounds accesses.
721 492 : for (int32_t offset = -2000000000; offset <= 2000000000;
722 : offset += 100000000) {
723 492 : if (offset == 0) continue;
724 480 : CheckOobValue(m.Call(offset, kLength));
725 : }
726 12 : }
727 :
728 23724 : TEST(RunOobCheckedLoad) { TestRunOobCheckedLoad(false); }
729 :
730 23724 : TEST(RunOobCheckedLoadImm) { TestRunOobCheckedLoad(true); }
731 :
732 12 : void TestRunOobCheckedStore(bool length_is_immediate) {
733 : RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
734 12 : MachineType::Int32());
735 12 : MachineOperatorBuilder machine(m.zone());
736 : const int32_t kNumElems = 29;
737 : const int32_t kValue = -78227234;
738 : const int32_t kLength = kNumElems * 4;
739 :
740 : int32_t buffer[kNumElems + kNumElems];
741 : Node* base = m.PointerConstant(buffer);
742 12 : Node* offset = m.Parameter(0);
743 12 : Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
744 12 : Node* val = m.Int32Constant(kValue);
745 : m.AddNode(machine.CheckedStore(MachineRepresentation::kWord32), base, offset,
746 12 : len, val);
747 12 : m.Return(val);
748 :
749 : // in-bounds accesses.
750 360 : for (int32_t i = 0; i < kNumElems; i++) {
751 : memset(buffer, 0, sizeof(buffer));
752 348 : int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
753 348 : CHECK_EQ(kValue, m.Call(offset, kLength));
754 20184 : for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
755 20184 : if (i == j) {
756 348 : CHECK_EQ(kValue, buffer[j]);
757 : } else {
758 19836 : CHECK_EQ(0, buffer[j]);
759 : }
760 : }
761 : }
762 :
763 : memset(buffer, 0, sizeof(buffer));
764 :
765 : // slightly out-of-bounds accesses.
766 : for (int32_t i = kLength; i < kNumElems + 30; i++) {
767 : int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
768 : CHECK_EQ(kValue, m.Call(offset, kLength));
769 : for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
770 : CHECK_EQ(0, buffer[j]);
771 : }
772 : }
773 :
774 : // way out-of-bounds accesses.
775 504 : for (int32_t offset = -2000000000; offset <= 2000000000;
776 : offset += 100000000) {
777 492 : if (offset == 0) continue;
778 480 : CHECK_EQ(kValue, m.Call(offset, kLength));
779 27840 : for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
780 27840 : CHECK_EQ(0, buffer[j]);
781 : }
782 : }
783 12 : }
784 :
785 23724 : TEST(RunOobCheckedStore) { TestRunOobCheckedStore(false); }
786 :
787 23724 : TEST(RunOobCheckedStoreImm) { TestRunOobCheckedStore(true); }
788 :
789 : // TODO(titzer): CheckedLoad/CheckedStore don't support 64-bit offsets.
790 : #define ALLOW_64_BIT_OFFSETS 0
791 :
792 : #if V8_TARGET_ARCH_64_BIT && ALLOW_64_BIT_OFFSETS
793 :
794 : void TestRunOobCheckedLoad64(uint32_t pseudo_base, bool length_is_immediate) {
795 : RawMachineAssemblerTester<int32_t> m(MachineType::Uint64(),
796 : MachineType::Uint64());
797 : MachineOperatorBuilder machine(m.zone());
798 : const uint32_t kNumElems = 25;
799 : const uint32_t kLength = kNumElems * 4;
800 : int32_t real_buffer[kNumElems];
801 :
802 : // Simulate the end of a large buffer.
803 : int32_t* buffer = real_buffer - (pseudo_base / 4);
804 : uint64_t length = kLength + pseudo_base;
805 :
806 : Node* base = m.PointerConstant(buffer);
807 : Node* offset = m.Parameter(0);
808 : Node* len = length_is_immediate ? m.Int64Constant(length) : m.Parameter(1);
809 : Node* node =
810 : m.AddNode(machine.CheckedLoad(MachineType::Int32()), base, offset, len);
811 : m.Return(node);
812 :
813 : {
814 : // randomize memory.
815 : v8::base::RandomNumberGenerator rng;
816 : rng.SetSeed(100);
817 : rng.NextBytes(&real_buffer[0], sizeof(real_buffer));
818 : }
819 :
820 : // in-bounds accesses.
821 : for (uint32_t i = 0; i < kNumElems; i++) {
822 : uint64_t offset = pseudo_base + i * 4;
823 : int32_t expected = real_buffer[i];
824 : CHECK_EQ(expected, m.Call(offset, length));
825 : }
826 :
827 : // in-bounds accesses w.r.t lower 32-bits, but upper bits set.
828 : for (uint64_t i = 0x100000000ULL; i != 0; i <<= 1) {
829 : uint64_t offset = pseudo_base + i;
830 : CheckOobValue(m.Call(offset, length));
831 : }
832 :
833 : // slightly out-of-bounds accesses.
834 : for (uint32_t i = kLength; i < kNumElems + 30; i++) {
835 : uint64_t offset = pseudo_base + i * 4;
836 : CheckOobValue(0, m.Call(offset, length));
837 : }
838 :
839 : // way out-of-bounds accesses.
840 : for (uint64_t offset = length; offset < 100 * A_BILLION; offset += A_GIG) {
841 : if (offset < length) continue;
842 : CheckOobValue(0, m.Call(offset, length));
843 : }
844 : }
845 :
846 : TEST(RunOobCheckedLoad64_0) {
847 : TestRunOobCheckedLoad64(0, false);
848 : TestRunOobCheckedLoad64(0, true);
849 : }
850 :
851 : TEST(RunOobCheckedLoad64_1) {
852 : TestRunOobCheckedLoad64(1 * A_BILLION, false);
853 : TestRunOobCheckedLoad64(1 * A_BILLION, true);
854 : }
855 :
856 : TEST(RunOobCheckedLoad64_2) {
857 : TestRunOobCheckedLoad64(2 * A_BILLION, false);
858 : TestRunOobCheckedLoad64(2 * A_BILLION, true);
859 : }
860 :
861 : TEST(RunOobCheckedLoad64_3) {
862 : TestRunOobCheckedLoad64(3 * A_BILLION, false);
863 : TestRunOobCheckedLoad64(3 * A_BILLION, true);
864 : }
865 :
866 : TEST(RunOobCheckedLoad64_4) {
867 : TestRunOobCheckedLoad64(4 * A_BILLION, false);
868 : TestRunOobCheckedLoad64(4 * A_BILLION, true);
869 : }
870 :
871 : void TestRunOobCheckedStore64(uint32_t pseudo_base, bool length_is_immediate) {
872 : RawMachineAssemblerTester<int32_t> m(MachineType::Uint64(),
873 : MachineType::Uint64());
874 : MachineOperatorBuilder machine(m.zone());
875 : const uint32_t kNumElems = 21;
876 : const uint32_t kLength = kNumElems * 4;
877 : const uint32_t kValue = 897234987;
878 : int32_t real_buffer[kNumElems + kNumElems];
879 :
880 : // Simulate the end of a large buffer.
881 : int32_t* buffer = real_buffer - (pseudo_base / 4);
882 : uint64_t length = kLength + pseudo_base;
883 :
884 : Node* base = m.PointerConstant(buffer);
885 : Node* offset = m.Parameter(0);
886 : Node* len = length_is_immediate ? m.Int64Constant(length) : m.Parameter(1);
887 : Node* val = m.Int32Constant(kValue);
888 : m.AddNode(machine.CheckedStore(MachineRepresentation::kWord32), base, offset,
889 : len, val);
890 : m.Return(val);
891 :
892 : // in-bounds accesses.
893 : for (uint32_t i = 0; i < kNumElems; i++) {
894 : memset(real_buffer, 0, sizeof(real_buffer));
895 : uint64_t offset = pseudo_base + i * 4;
896 : CHECK_EQ(kValue, m.Call(offset, length));
897 : for (uint32_t j = 0; j < kNumElems + kNumElems; j++) {
898 : if (i == j) {
899 : CHECK_EQ(kValue, real_buffer[j]);
900 : } else {
901 : CHECK_EQ(0, real_buffer[j]);
902 : }
903 : }
904 : }
905 :
906 : memset(real_buffer, 0, sizeof(real_buffer));
907 :
908 : // in-bounds accesses w.r.t lower 32-bits, but upper bits set.
909 : for (uint64_t i = 0x100000000ULL; i != 0; i <<= 1) {
910 : uint64_t offset = pseudo_base + i;
911 : CHECK_EQ(kValue, m.Call(offset, length));
912 : for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
913 : CHECK_EQ(0, real_buffer[j]);
914 : }
915 : }
916 :
917 : // slightly out-of-bounds accesses.
918 : for (uint32_t i = kLength; i < kNumElems + 30; i++) {
919 : uint64_t offset = pseudo_base + i * 4;
920 : CHECK_EQ(kValue, m.Call(offset, length));
921 : for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
922 : CHECK_EQ(0, real_buffer[j]);
923 : }
924 : }
925 :
926 : // way out-of-bounds accesses.
927 : for (uint64_t offset = length; offset < 100 * A_BILLION; offset += A_GIG) {
928 : if (offset < length) continue;
929 : CHECK_EQ(kValue, m.Call(offset, length));
930 : for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
931 : CHECK_EQ(0, real_buffer[j]);
932 : }
933 : }
934 : }
935 :
936 : TEST(RunOobCheckedStore64_0) {
937 : TestRunOobCheckedStore64(0, false);
938 : TestRunOobCheckedStore64(0, true);
939 : }
940 :
941 : TEST(RunOobCheckedStore64_1) {
942 : TestRunOobCheckedStore64(1 * A_BILLION, false);
943 : TestRunOobCheckedStore64(1 * A_BILLION, true);
944 : }
945 :
946 : TEST(RunOobCheckedStore64_2) {
947 : TestRunOobCheckedStore64(2 * A_BILLION, false);
948 : TestRunOobCheckedStore64(2 * A_BILLION, true);
949 : }
950 :
951 : TEST(RunOobCheckedStore64_3) {
952 : TestRunOobCheckedStore64(3 * A_BILLION, false);
953 : TestRunOobCheckedStore64(3 * A_BILLION, true);
954 : }
955 :
956 : TEST(RunOobCheckedStore64_4) {
957 : TestRunOobCheckedStore64(4 * A_BILLION, false);
958 : TestRunOobCheckedStore64(4 * A_BILLION, true);
959 : }
960 :
961 : #endif
962 :
963 108 : void TestRunOobCheckedLoad_pseudo(uint64_t x, bool length_is_immediate) {
964 : RawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
965 108 : MachineType::Uint32());
966 :
967 108 : uint32_t pseudo_base = static_cast<uint32_t>(x);
968 108 : MachineOperatorBuilder machine(m.zone());
969 : const uint32_t kNumElems = 29;
970 108 : const uint32_t kLength = pseudo_base + kNumElems * 4;
971 :
972 : int32_t buffer[kNumElems];
973 108 : Node* base = m.PointerConstant(reinterpret_cast<byte*>(buffer) - pseudo_base);
974 108 : Node* offset = m.Parameter(0);
975 108 : Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
976 : Node* node =
977 108 : m.AddNode(machine.CheckedLoad(MachineType::Int32()), base, offset, len);
978 108 : m.Return(node);
979 :
980 : {
981 : // randomize memory.
982 108 : v8::base::RandomNumberGenerator rng;
983 108 : rng.SetSeed(100);
984 108 : rng.NextBytes(&buffer[0], sizeof(buffer));
985 : }
986 :
987 : // in-bounds accesses.
988 3240 : for (uint32_t i = 0; i < kNumElems; i++) {
989 3132 : uint32_t offset = static_cast<uint32_t>(i * sizeof(int32_t));
990 3132 : uint32_t expected = buffer[i];
991 3132 : CHECK_EQ(expected,
992 : static_cast<uint32_t>(m.Call(offset + pseudo_base, kLength)));
993 : }
994 :
995 : // slightly out-of-bounds accesses.
996 3240 : for (uint32_t i = kNumElems; i < kNumElems + 30; i++) {
997 3240 : uint32_t offset = i * sizeof(int32_t);
998 3240 : CheckOobValue(m.Call(offset + pseudo_base, kLength));
999 : }
1000 :
1001 : // way out-of-bounds accesses.
1002 456 : for (uint64_t i = pseudo_base + sizeof(buffer); i < 0xFFFFFFFF;
1003 : i += A_BILLION) {
1004 348 : uint32_t offset = static_cast<uint32_t>(i);
1005 348 : CheckOobValue(m.Call(offset, kLength));
1006 : }
1007 108 : }
1008 :
1009 23724 : TEST(RunOobCheckedLoad_pseudo0) {
1010 6 : TestRunOobCheckedLoad_pseudo(0, false);
1011 6 : TestRunOobCheckedLoad_pseudo(0, true);
1012 6 : }
1013 :
1014 23724 : TEST(RunOobCheckedLoad_pseudo1) {
1015 6 : TestRunOobCheckedLoad_pseudo(100000, false);
1016 6 : TestRunOobCheckedLoad_pseudo(100000, true);
1017 6 : }
1018 :
1019 23724 : TEST(RunOobCheckedLoad_pseudo2) {
1020 6 : TestRunOobCheckedLoad_pseudo(A_BILLION, false);
1021 6 : TestRunOobCheckedLoad_pseudo(A_BILLION, true);
1022 6 : }
1023 :
1024 23724 : TEST(RunOobCheckedLoad_pseudo3) {
1025 6 : TestRunOobCheckedLoad_pseudo(A_GIG, false);
1026 6 : TestRunOobCheckedLoad_pseudo(A_GIG, true);
1027 6 : }
1028 :
1029 23724 : TEST(RunOobCheckedLoad_pseudo4) {
1030 6 : TestRunOobCheckedLoad_pseudo(2 * A_BILLION, false);
1031 6 : TestRunOobCheckedLoad_pseudo(2 * A_BILLION, true);
1032 6 : }
1033 :
1034 23724 : TEST(RunOobCheckedLoad_pseudo5) {
1035 6 : TestRunOobCheckedLoad_pseudo(2 * A_GIG, false);
1036 6 : TestRunOobCheckedLoad_pseudo(2 * A_GIG, true);
1037 6 : }
1038 :
1039 23724 : TEST(RunOobCheckedLoad_pseudo6) {
1040 6 : TestRunOobCheckedLoad_pseudo(3 * A_BILLION, false);
1041 6 : TestRunOobCheckedLoad_pseudo(3 * A_BILLION, true);
1042 6 : }
1043 :
1044 23724 : TEST(RunOobCheckedLoad_pseudo7) {
1045 6 : TestRunOobCheckedLoad_pseudo(3 * A_GIG, false);
1046 6 : TestRunOobCheckedLoad_pseudo(3 * A_GIG, true);
1047 6 : }
1048 :
1049 23724 : TEST(RunOobCheckedLoad_pseudo8) {
1050 6 : TestRunOobCheckedLoad_pseudo(4 * A_BILLION, false);
1051 6 : TestRunOobCheckedLoad_pseudo(4 * A_BILLION, true);
1052 6 : }
1053 :
1054 : template <typename MemType>
1055 324 : void TestRunOobCheckedLoadT_pseudo(uint64_t x, bool length_is_immediate) {
1056 : const int32_t kReturn = 11999;
1057 : const uint32_t kNumElems = 29;
1058 : MemType buffer[kNumElems];
1059 324 : uint32_t pseudo_base = static_cast<uint32_t>(x);
1060 324 : const uint32_t kLength = static_cast<uint32_t>(pseudo_base + sizeof(buffer));
1061 :
1062 : MemType result;
1063 :
1064 : RawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
1065 324 : MachineType::Uint32());
1066 324 : MachineOperatorBuilder machine(m.zone());
1067 324 : Node* base = m.PointerConstant(reinterpret_cast<byte*>(buffer) - pseudo_base);
1068 324 : Node* offset = m.Parameter(0);
1069 324 : Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
1070 : Node* node = m.AddNode(machine.CheckedLoad(MachineTypeForC<MemType>()), base,
1071 324 : offset, len);
1072 : Node* store = m.StoreToPointer(
1073 324 : &result, MachineTypeForC<MemType>().representation(), node);
1074 : USE(store);
1075 324 : m.Return(m.Int32Constant(kReturn));
1076 :
1077 : {
1078 : // randomize memory.
1079 324 : v8::base::RandomNumberGenerator rng;
1080 324 : rng.SetSeed(103);
1081 324 : rng.NextBytes(&buffer[0], sizeof(buffer));
1082 : }
1083 :
1084 : // in-bounds accesses.
1085 9720 : for (uint32_t i = 0; i < kNumElems; i++) {
1086 9396 : uint32_t offset = static_cast<uint32_t>(i * sizeof(MemType));
1087 9396 : MemType expected = buffer[i];
1088 9396 : CHECK_EQ(kReturn, m.Call(offset + pseudo_base, kLength));
1089 9396 : CHECK_EQ(expected, result);
1090 : }
1091 :
1092 : // slightly out-of-bounds accesses.
1093 9720 : for (uint32_t i = kNumElems; i < kNumElems + 30; i++) {
1094 9720 : uint32_t offset = static_cast<uint32_t>(i * sizeof(MemType));
1095 9720 : CHECK_EQ(kReturn, m.Call(offset + pseudo_base, kLength));
1096 9720 : CheckOobValue(result);
1097 : }
1098 :
1099 : // way out-of-bounds accesses.
1100 1368 : for (uint64_t i = pseudo_base + sizeof(buffer); i < 0xFFFFFFFF;
1101 : i += A_BILLION) {
1102 1044 : uint32_t offset = static_cast<uint32_t>(i);
1103 1044 : CHECK_EQ(kReturn, m.Call(offset, kLength));
1104 1044 : CheckOobValue(result);
1105 : }
1106 324 : }
1107 :
1108 23724 : TEST(RunOobCheckedLoadT_pseudo0) {
1109 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(0, false);
1110 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(0, true);
1111 6 : TestRunOobCheckedLoadT_pseudo<float>(0, false);
1112 6 : TestRunOobCheckedLoadT_pseudo<float>(0, true);
1113 6 : TestRunOobCheckedLoadT_pseudo<double>(0, false);
1114 6 : TestRunOobCheckedLoadT_pseudo<double>(0, true);
1115 6 : }
1116 :
1117 23724 : TEST(RunOobCheckedLoadT_pseudo1) {
1118 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(100000, false);
1119 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(100000, true);
1120 6 : TestRunOobCheckedLoadT_pseudo<float>(100000, false);
1121 6 : TestRunOobCheckedLoadT_pseudo<float>(100000, true);
1122 6 : TestRunOobCheckedLoadT_pseudo<double>(100000, false);
1123 6 : TestRunOobCheckedLoadT_pseudo<double>(100000, true);
1124 6 : }
1125 :
1126 23724 : TEST(RunOobCheckedLoadT_pseudo2) {
1127 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(A_BILLION, false);
1128 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(A_BILLION, true);
1129 6 : TestRunOobCheckedLoadT_pseudo<float>(A_BILLION, false);
1130 6 : TestRunOobCheckedLoadT_pseudo<float>(A_BILLION, true);
1131 6 : TestRunOobCheckedLoadT_pseudo<double>(A_BILLION, false);
1132 6 : TestRunOobCheckedLoadT_pseudo<double>(A_BILLION, true);
1133 6 : }
1134 :
1135 23724 : TEST(RunOobCheckedLoadT_pseudo3) {
1136 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(A_GIG, false);
1137 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(A_GIG, true);
1138 6 : TestRunOobCheckedLoadT_pseudo<float>(A_GIG, false);
1139 6 : TestRunOobCheckedLoadT_pseudo<float>(A_GIG, true);
1140 6 : TestRunOobCheckedLoadT_pseudo<double>(A_GIG, false);
1141 6 : TestRunOobCheckedLoadT_pseudo<double>(A_GIG, true);
1142 6 : }
1143 :
1144 23724 : TEST(RunOobCheckedLoadT_pseudo4) {
1145 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_BILLION, false);
1146 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_BILLION, true);
1147 6 : TestRunOobCheckedLoadT_pseudo<float>(2 * A_BILLION, false);
1148 6 : TestRunOobCheckedLoadT_pseudo<float>(2 * A_BILLION, true);
1149 6 : TestRunOobCheckedLoadT_pseudo<double>(2 * A_BILLION, false);
1150 6 : TestRunOobCheckedLoadT_pseudo<double>(2 * A_BILLION, true);
1151 6 : }
1152 :
1153 23724 : TEST(RunOobCheckedLoadT_pseudo5) {
1154 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_GIG, false);
1155 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_GIG, true);
1156 6 : TestRunOobCheckedLoadT_pseudo<float>(2 * A_GIG, false);
1157 6 : TestRunOobCheckedLoadT_pseudo<float>(2 * A_GIG, true);
1158 6 : TestRunOobCheckedLoadT_pseudo<double>(2 * A_GIG, false);
1159 6 : TestRunOobCheckedLoadT_pseudo<double>(2 * A_GIG, true);
1160 6 : }
1161 :
1162 23724 : TEST(RunOobCheckedLoadT_pseudo6) {
1163 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_BILLION, false);
1164 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_BILLION, true);
1165 6 : TestRunOobCheckedLoadT_pseudo<float>(3 * A_BILLION, false);
1166 6 : TestRunOobCheckedLoadT_pseudo<float>(3 * A_BILLION, true);
1167 6 : TestRunOobCheckedLoadT_pseudo<double>(3 * A_BILLION, false);
1168 6 : TestRunOobCheckedLoadT_pseudo<double>(3 * A_BILLION, true);
1169 6 : }
1170 :
1171 23724 : TEST(RunOobCheckedLoadT_pseudo7) {
1172 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_GIG, false);
1173 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_GIG, true);
1174 6 : TestRunOobCheckedLoadT_pseudo<float>(3 * A_GIG, false);
1175 6 : TestRunOobCheckedLoadT_pseudo<float>(3 * A_GIG, true);
1176 6 : TestRunOobCheckedLoadT_pseudo<double>(3 * A_GIG, false);
1177 6 : TestRunOobCheckedLoadT_pseudo<double>(3 * A_GIG, true);
1178 6 : }
1179 :
1180 23724 : TEST(RunOobCheckedLoadT_pseudo8) {
1181 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(4 * A_BILLION, false);
1182 6 : TestRunOobCheckedLoadT_pseudo<int32_t>(4 * A_BILLION, true);
1183 6 : TestRunOobCheckedLoadT_pseudo<float>(4 * A_BILLION, false);
1184 6 : TestRunOobCheckedLoadT_pseudo<float>(4 * A_BILLION, true);
1185 6 : TestRunOobCheckedLoadT_pseudo<double>(4 * A_BILLION, false);
1186 6 : TestRunOobCheckedLoadT_pseudo<double>(4 * A_BILLION, true);
1187 6 : }
1188 :
1189 : } // namespace compiler
1190 : } // namespace internal
1191 71154 : } // namespace v8
|