• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "test/cctest/cctest.h"
13 #include "test/cctest/compiler/codegen-tester.h"
14 #include "test/cctest/compiler/graph-builder-tester.h"
15 #include "test/cctest/compiler/value-helper.h"
16 
17 using namespace v8::base;
18 
19 namespace {
20 template <typename Type>
CheckOobValue(Type val)21 void CheckOobValue(Type val) {
22   UNREACHABLE();
23 }
24 
25 template <>
CheckOobValue(int32_t val)26 void CheckOobValue(int32_t val) {
27   CHECK_EQ(0, val);
28 }
29 
30 template <>
CheckOobValue(int64_t val)31 void CheckOobValue(int64_t val) {
32   CHECK_EQ(0, val);
33 }
34 
35 template <>
CheckOobValue(float val)36 void CheckOobValue(float val) {
37   CHECK(std::isnan(val));
38 }
39 
40 template <>
CheckOobValue(double val)41 void CheckOobValue(double val) {
42   CHECK(std::isnan(val));
43 }
44 }  // namespace
45 
46 namespace v8 {
47 namespace internal {
48 namespace compiler {
49 
50 // This is a America!
51 #define A_BILLION 1000000000ULL
52 #define A_GIG (1024ULL * 1024ULL * 1024ULL)
53 
TEST(RunLoadInt32)54 TEST(RunLoadInt32) {
55   RawMachineAssemblerTester<int32_t> m;
56 
57   int32_t p1 = 0;  // loads directly from this location.
58   m.Return(m.LoadFromPointer(&p1, MachineType::Int32()));
59 
60   FOR_INT32_INPUTS(i) {
61     p1 = *i;
62     CHECK_EQ(p1, m.Call());
63   }
64 }
65 
TEST(RunLoadInt32Offset)66 TEST(RunLoadInt32Offset) {
67   int32_t p1 = 0;  // loads directly from this location.
68 
69   int32_t offsets[] = {-2000000, -100, -101, 1,          3,
70                        7,        120,  2000, 2000000000, 0xff};
71 
72   for (size_t i = 0; i < arraysize(offsets); i++) {
73     RawMachineAssemblerTester<int32_t> m;
74     int32_t offset = offsets[i];
75     byte* pointer = reinterpret_cast<byte*>(&p1) - offset;
76     // generate load [#base + #index]
77     m.Return(m.LoadFromPointer(pointer, MachineType::Int32(), offset));
78 
79     FOR_INT32_INPUTS(j) {
80       p1 = *j;
81       CHECK_EQ(p1, m.Call());
82     }
83   }
84 }
85 
TEST(RunLoadStoreFloat32Offset)86 TEST(RunLoadStoreFloat32Offset) {
87   float p1 = 0.0f;  // loads directly from this location.
88   float p2 = 0.0f;  // and stores directly into this location.
89 
90   FOR_INT32_INPUTS(i) {
91     int32_t magic = 0x2342aabb + *i * 3;
92     RawMachineAssemblerTester<int32_t> m;
93     int32_t offset = *i;
94     byte* from = reinterpret_cast<byte*>(&p1) - offset;
95     byte* to = reinterpret_cast<byte*>(&p2) - offset;
96     // generate load [#base + #index]
97     Node* load = m.Load(MachineType::Float32(), m.PointerConstant(from),
98                         m.IntPtrConstant(offset));
99     m.Store(MachineRepresentation::kFloat32, m.PointerConstant(to),
100             m.IntPtrConstant(offset), load, kNoWriteBarrier);
101     m.Return(m.Int32Constant(magic));
102 
103     FOR_FLOAT32_INPUTS(j) {
104       p1 = *j;
105       p2 = *j - 5;
106       CHECK_EQ(magic, m.Call());
107       CheckDoubleEq(p1, p2);
108     }
109   }
110 }
111 
TEST(RunLoadStoreFloat64Offset)112 TEST(RunLoadStoreFloat64Offset) {
113   double p1 = 0;  // loads directly from this location.
114   double p2 = 0;  // and stores directly into this location.
115 
116   FOR_INT32_INPUTS(i) {
117     int32_t magic = 0x2342aabb + *i * 3;
118     RawMachineAssemblerTester<int32_t> m;
119     int32_t offset = *i;
120     byte* from = reinterpret_cast<byte*>(&p1) - offset;
121     byte* to = reinterpret_cast<byte*>(&p2) - offset;
122     // generate load [#base + #index]
123     Node* load = m.Load(MachineType::Float64(), m.PointerConstant(from),
124                         m.IntPtrConstant(offset));
125     m.Store(MachineRepresentation::kFloat64, m.PointerConstant(to),
126             m.IntPtrConstant(offset), load, kNoWriteBarrier);
127     m.Return(m.Int32Constant(magic));
128 
129     FOR_FLOAT64_INPUTS(j) {
130       p1 = *j;
131       p2 = *j - 5;
132       CHECK_EQ(magic, m.Call());
133       CheckDoubleEq(p1, p2);
134     }
135   }
136 }
137 
138 namespace {
139 template <typename Type>
RunLoadImmIndex(MachineType rep)140 void RunLoadImmIndex(MachineType rep) {
141   const int kNumElems = 3;
142   Type buffer[kNumElems];
143 
144   // initialize the buffer with some raw data.
145   byte* raw = reinterpret_cast<byte*>(buffer);
146   for (size_t i = 0; i < sizeof(buffer); i++) {
147     raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
148   }
149 
150   // Test with various large and small offsets.
151   for (int offset = -1; offset <= 200000; offset *= -5) {
152     for (int i = 0; i < kNumElems; i++) {
153       BufferedRawMachineAssemblerTester<Type> m;
154       Node* base = m.PointerConstant(buffer - offset);
155       Node* index = m.Int32Constant((offset + i) * sizeof(buffer[0]));
156       m.Return(m.Load(rep, base, index));
157 
158       volatile Type expected = buffer[i];
159       volatile Type actual = m.Call();
160       CHECK_EQ(expected, actual);
161     }
162   }
163 }
164 
165 template <typename CType>
RunLoadStore(MachineType rep)166 void RunLoadStore(MachineType rep) {
167   const int kNumElems = 4;
168   CType buffer[kNumElems];
169 
170   for (int32_t x = 0; x < kNumElems; x++) {
171     int32_t y = kNumElems - x - 1;
172     // initialize the buffer with raw data.
173     byte* raw = reinterpret_cast<byte*>(buffer);
174     for (size_t i = 0; i < sizeof(buffer); i++) {
175       raw[i] = static_cast<byte>((i + sizeof(buffer)) ^ 0xAA);
176     }
177 
178     RawMachineAssemblerTester<int32_t> m;
179     int32_t OK = 0x29000 + x;
180     Node* base = m.PointerConstant(buffer);
181     Node* index0 = m.IntPtrConstant(x * sizeof(buffer[0]));
182     Node* load = m.Load(rep, base, index0);
183     Node* index1 = m.IntPtrConstant(y * sizeof(buffer[0]));
184     m.Store(rep.representation(), base, index1, load, kNoWriteBarrier);
185     m.Return(m.Int32Constant(OK));
186 
187     CHECK(buffer[x] != buffer[y]);
188     CHECK_EQ(OK, m.Call());
189     CHECK(buffer[x] == buffer[y]);
190   }
191 }
192 }  // namespace
193 
TEST(RunLoadImmIndex)194 TEST(RunLoadImmIndex) {
195   RunLoadImmIndex<int8_t>(MachineType::Int8());
196   RunLoadImmIndex<uint8_t>(MachineType::Uint8());
197   RunLoadImmIndex<int16_t>(MachineType::Int16());
198   RunLoadImmIndex<uint16_t>(MachineType::Uint16());
199   RunLoadImmIndex<int32_t>(MachineType::Int32());
200   RunLoadImmIndex<uint32_t>(MachineType::Uint32());
201   RunLoadImmIndex<int32_t*>(MachineType::AnyTagged());
202   RunLoadImmIndex<float>(MachineType::Float32());
203   RunLoadImmIndex<double>(MachineType::Float64());
204 #if V8_TARGET_ARCH_64_BIT
205   RunLoadImmIndex<int64_t>(MachineType::Int64());
206 #endif
207   // TODO(titzer): test various indexing modes.
208 }
209 
TEST(RunLoadStore)210 TEST(RunLoadStore) {
211   RunLoadStore<int8_t>(MachineType::Int8());
212   RunLoadStore<uint8_t>(MachineType::Uint8());
213   RunLoadStore<int16_t>(MachineType::Int16());
214   RunLoadStore<uint16_t>(MachineType::Uint16());
215   RunLoadStore<int32_t>(MachineType::Int32());
216   RunLoadStore<uint32_t>(MachineType::Uint32());
217   RunLoadStore<void*>(MachineType::AnyTagged());
218   RunLoadStore<float>(MachineType::Float32());
219   RunLoadStore<double>(MachineType::Float64());
220 #if V8_TARGET_ARCH_64_BIT
221   RunLoadStore<int64_t>(MachineType::Int64());
222 #endif
223 }
224 
225 #if V8_TARGET_LITTLE_ENDIAN
226 #define LSB(addr, bytes) addr
227 #elif V8_TARGET_BIG_ENDIAN
228 #define LSB(addr, bytes) reinterpret_cast<byte*>(addr + 1) - bytes
229 #else
230 #error "Unknown Architecture"
231 #endif
232 
TEST(RunLoadStoreSignExtend32)233 TEST(RunLoadStoreSignExtend32) {
234   int32_t buffer[4];
235   RawMachineAssemblerTester<int32_t> m;
236   Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Int8());
237   Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Int16());
238   Node* load32 = m.LoadFromPointer(&buffer[0], MachineType::Int32());
239   m.StoreToPointer(&buffer[1], MachineRepresentation::kWord32, load8);
240   m.StoreToPointer(&buffer[2], MachineRepresentation::kWord32, load16);
241   m.StoreToPointer(&buffer[3], MachineRepresentation::kWord32, load32);
242   m.Return(load8);
243 
244   FOR_INT32_INPUTS(i) {
245     buffer[0] = *i;
246 
247     CHECK_EQ(static_cast<int8_t>(*i & 0xff), m.Call());
248     CHECK_EQ(static_cast<int8_t>(*i & 0xff), buffer[1]);
249     CHECK_EQ(static_cast<int16_t>(*i & 0xffff), buffer[2]);
250     CHECK_EQ(*i, buffer[3]);
251   }
252 }
253 
TEST(RunLoadStoreZeroExtend32)254 TEST(RunLoadStoreZeroExtend32) {
255   uint32_t buffer[4];
256   RawMachineAssemblerTester<uint32_t> m;
257   Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Uint8());
258   Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Uint16());
259   Node* load32 = m.LoadFromPointer(&buffer[0], MachineType::Uint32());
260   m.StoreToPointer(&buffer[1], MachineRepresentation::kWord32, load8);
261   m.StoreToPointer(&buffer[2], MachineRepresentation::kWord32, load16);
262   m.StoreToPointer(&buffer[3], MachineRepresentation::kWord32, load32);
263   m.Return(load8);
264 
265   FOR_UINT32_INPUTS(i) {
266     buffer[0] = *i;
267 
268     CHECK_EQ((*i & 0xff), m.Call());
269     CHECK_EQ((*i & 0xff), buffer[1]);
270     CHECK_EQ((*i & 0xffff), buffer[2]);
271     CHECK_EQ(*i, buffer[3]);
272   }
273 }
274 
275 #if V8_TARGET_ARCH_64_BIT
TEST(RunCheckedLoadInt64)276 TEST(RunCheckedLoadInt64) {
277   int64_t buffer[] = {0x66bbccddeeff0011LL, 0x1122334455667788LL};
278   RawMachineAssemblerTester<int64_t> m(MachineType::Int32());
279   Node* base = m.PointerConstant(buffer);
280   Node* index = m.Parameter(0);
281   Node* length = m.Int32Constant(16);
282   Node* load = m.AddNode(m.machine()->CheckedLoad(MachineType::Int64()), base,
283                          index, length);
284   m.Return(load);
285 
286   CHECK_EQ(buffer[0], m.Call(0));
287   CHECK_EQ(buffer[1], m.Call(8));
288   CheckOobValue(m.Call(16));
289 }
290 
TEST(RunLoadStoreSignExtend64)291 TEST(RunLoadStoreSignExtend64) {
292   if (true) return;  // TODO(titzer): sign extension of loads to 64-bit.
293   int64_t buffer[5];
294   RawMachineAssemblerTester<int64_t> m;
295   Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Int8());
296   Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Int16());
297   Node* load32 = m.LoadFromPointer(LSB(&buffer[0], 4), MachineType::Int32());
298   Node* load64 = m.LoadFromPointer(&buffer[0], MachineType::Int64());
299   m.StoreToPointer(&buffer[1], MachineRepresentation::kWord64, load8);
300   m.StoreToPointer(&buffer[2], MachineRepresentation::kWord64, load16);
301   m.StoreToPointer(&buffer[3], MachineRepresentation::kWord64, load32);
302   m.StoreToPointer(&buffer[4], MachineRepresentation::kWord64, load64);
303   m.Return(load8);
304 
305   FOR_INT64_INPUTS(i) {
306     buffer[0] = *i;
307 
308     CHECK_EQ(static_cast<int8_t>(*i & 0xff), m.Call());
309     CHECK_EQ(static_cast<int8_t>(*i & 0xff), buffer[1]);
310     CHECK_EQ(static_cast<int16_t>(*i & 0xffff), buffer[2]);
311     CHECK_EQ(static_cast<int32_t>(*i & 0xffffffff), buffer[3]);
312     CHECK_EQ(*i, buffer[4]);
313   }
314 }
315 
TEST(RunLoadStoreZeroExtend64)316 TEST(RunLoadStoreZeroExtend64) {
317   if (kPointerSize < 8) return;
318   uint64_t buffer[5];
319   RawMachineAssemblerTester<int64_t> m;
320   Node* load8 = m.LoadFromPointer(LSB(&buffer[0], 1), MachineType::Uint8());
321   Node* load16 = m.LoadFromPointer(LSB(&buffer[0], 2), MachineType::Uint16());
322   Node* load32 = m.LoadFromPointer(LSB(&buffer[0], 4), MachineType::Uint32());
323   Node* load64 = m.LoadFromPointer(&buffer[0], MachineType::Uint64());
324   m.StoreToPointer(&buffer[1], MachineRepresentation::kWord64, load8);
325   m.StoreToPointer(&buffer[2], MachineRepresentation::kWord64, load16);
326   m.StoreToPointer(&buffer[3], MachineRepresentation::kWord64, load32);
327   m.StoreToPointer(&buffer[4], MachineRepresentation::kWord64, load64);
328   m.Return(load8);
329 
330   FOR_UINT64_INPUTS(i) {
331     buffer[0] = *i;
332 
333     CHECK_EQ((*i & 0xff), m.Call());
334     CHECK_EQ((*i & 0xff), buffer[1]);
335     CHECK_EQ((*i & 0xffff), buffer[2]);
336     CHECK_EQ((*i & 0xffffffff), buffer[3]);
337     CHECK_EQ(*i, buffer[4]);
338   }
339 }
340 
TEST(RunCheckedStoreInt64)341 TEST(RunCheckedStoreInt64) {
342   const int64_t write = 0x5566778899aabbLL;
343   const int64_t before = 0x33bbccddeeff0011LL;
344   int64_t buffer[] = {before, before};
345   RawMachineAssemblerTester<int32_t> m(MachineType::Int32());
346   Node* base = m.PointerConstant(buffer);
347   Node* index = m.Parameter(0);
348   Node* length = m.Int32Constant(16);
349   Node* value = m.Int64Constant(write);
350   Node* store =
351       m.AddNode(m.machine()->CheckedStore(MachineRepresentation::kWord64), base,
352                 index, length, value);
353   USE(store);
354   m.Return(m.Int32Constant(11));
355 
356   CHECK_EQ(11, m.Call(16));
357   CHECK_EQ(before, buffer[0]);
358   CHECK_EQ(before, buffer[1]);
359 
360   CHECK_EQ(11, m.Call(0));
361   CHECK_EQ(write, buffer[0]);
362   CHECK_EQ(before, buffer[1]);
363 
364   CHECK_EQ(11, m.Call(8));
365   CHECK_EQ(write, buffer[0]);
366   CHECK_EQ(write, buffer[1]);
367 }
368 #endif
369 
370 namespace {
371 template <typename IntType>
LoadStoreTruncation(MachineType kRepresentation)372 void LoadStoreTruncation(MachineType kRepresentation) {
373   IntType input;
374 
375   RawMachineAssemblerTester<int32_t> m;
376   Node* a = m.LoadFromPointer(&input, kRepresentation);
377   Node* ap1 = m.Int32Add(a, m.Int32Constant(1));
378   m.StoreToPointer(&input, kRepresentation.representation(), ap1);
379   m.Return(ap1);
380 
381   const IntType max = std::numeric_limits<IntType>::max();
382   const IntType min = std::numeric_limits<IntType>::min();
383 
384   // Test upper bound.
385   input = max;
386   CHECK_EQ(max + 1, m.Call());
387   CHECK_EQ(min, input);
388 
389   // Test lower bound.
390   input = min;
391   CHECK_EQ(static_cast<IntType>(max + 2), m.Call());
392   CHECK_EQ(min + 1, input);
393 
394   // Test all one byte values that are not one byte bounds.
395   for (int i = -127; i < 127; i++) {
396     input = i;
397     int expected = i >= 0 ? i + 1 : max + (i - min) + 2;
398     CHECK_EQ(static_cast<IntType>(expected), m.Call());
399     CHECK_EQ(static_cast<IntType>(i + 1), input);
400   }
401 }
402 }  // namespace
403 
TEST(RunLoadStoreTruncation)404 TEST(RunLoadStoreTruncation) {
405   LoadStoreTruncation<int8_t>(MachineType::Int8());
406   LoadStoreTruncation<int16_t>(MachineType::Int16());
407 }
408 
TestRunOobCheckedLoad(bool length_is_immediate)409 void TestRunOobCheckedLoad(bool length_is_immediate) {
410   USE(CheckOobValue<int32_t>);
411   USE(CheckOobValue<int64_t>);
412   USE(CheckOobValue<float>);
413   USE(CheckOobValue<double>);
414 
415   RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
416                                        MachineType::Int32());
417   MachineOperatorBuilder machine(m.zone());
418   const int32_t kNumElems = 27;
419   const int32_t kLength = kNumElems * 4;
420 
421   int32_t buffer[kNumElems];
422   Node* base = m.PointerConstant(buffer);
423   Node* offset = m.Parameter(0);
424   Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
425   Node* node =
426       m.AddNode(machine.CheckedLoad(MachineType::Int32()), base, offset, len);
427   m.Return(node);
428 
429   {
430     // randomize memory.
431     v8::base::RandomNumberGenerator rng;
432     rng.SetSeed(100);
433     rng.NextBytes(&buffer[0], sizeof(buffer));
434   }
435 
436   // in-bounds accesses.
437   for (int32_t i = 0; i < kNumElems; i++) {
438     int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
439     int32_t expected = buffer[i];
440     CHECK_EQ(expected, m.Call(offset, kLength));
441   }
442 
443   // slightly out-of-bounds accesses.
444   for (int32_t i = kLength; i < kNumElems + 30; i++) {
445     int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
446     CheckOobValue(m.Call(offset, kLength));
447   }
448 
449   // way out-of-bounds accesses.
450   for (int32_t offset = -2000000000; offset <= 2000000000;
451        offset += 100000000) {
452     if (offset == 0) continue;
453     CheckOobValue(m.Call(offset, kLength));
454   }
455 }
456 
TEST(RunOobCheckedLoad)457 TEST(RunOobCheckedLoad) { TestRunOobCheckedLoad(false); }
458 
TEST(RunOobCheckedLoadImm)459 TEST(RunOobCheckedLoadImm) { TestRunOobCheckedLoad(true); }
460 
TestRunOobCheckedStore(bool length_is_immediate)461 void TestRunOobCheckedStore(bool length_is_immediate) {
462   RawMachineAssemblerTester<int32_t> m(MachineType::Int32(),
463                                        MachineType::Int32());
464   MachineOperatorBuilder machine(m.zone());
465   const int32_t kNumElems = 29;
466   const int32_t kValue = -78227234;
467   const int32_t kLength = kNumElems * 4;
468 
469   int32_t buffer[kNumElems + kNumElems];
470   Node* base = m.PointerConstant(buffer);
471   Node* offset = m.Parameter(0);
472   Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
473   Node* val = m.Int32Constant(kValue);
474   m.AddNode(machine.CheckedStore(MachineRepresentation::kWord32), base, offset,
475             len, val);
476   m.Return(val);
477 
478   // in-bounds accesses.
479   for (int32_t i = 0; i < kNumElems; i++) {
480     memset(buffer, 0, sizeof(buffer));
481     int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
482     CHECK_EQ(kValue, m.Call(offset, kLength));
483     for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
484       if (i == j) {
485         CHECK_EQ(kValue, buffer[j]);
486       } else {
487         CHECK_EQ(0, buffer[j]);
488       }
489     }
490   }
491 
492   memset(buffer, 0, sizeof(buffer));
493 
494   // slightly out-of-bounds accesses.
495   for (int32_t i = kLength; i < kNumElems + 30; i++) {
496     int32_t offset = static_cast<int32_t>(i * sizeof(int32_t));
497     CHECK_EQ(kValue, m.Call(offset, kLength));
498     for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
499       CHECK_EQ(0, buffer[j]);
500     }
501   }
502 
503   // way out-of-bounds accesses.
504   for (int32_t offset = -2000000000; offset <= 2000000000;
505        offset += 100000000) {
506     if (offset == 0) continue;
507     CHECK_EQ(kValue, m.Call(offset, kLength));
508     for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
509       CHECK_EQ(0, buffer[j]);
510     }
511   }
512 }
513 
TEST(RunOobCheckedStore)514 TEST(RunOobCheckedStore) { TestRunOobCheckedStore(false); }
515 
TEST(RunOobCheckedStoreImm)516 TEST(RunOobCheckedStoreImm) { TestRunOobCheckedStore(true); }
517 
518 // TODO(titzer): CheckedLoad/CheckedStore don't support 64-bit offsets.
519 #define ALLOW_64_BIT_OFFSETS 0
520 
521 #if V8_TARGET_ARCH_64_BIT && ALLOW_64_BIT_OFFSETS
522 
TestRunOobCheckedLoad64(uint32_t pseudo_base,bool length_is_immediate)523 void TestRunOobCheckedLoad64(uint32_t pseudo_base, bool length_is_immediate) {
524   RawMachineAssemblerTester<int32_t> m(MachineType::Uint64(),
525                                        MachineType::Uint64());
526   MachineOperatorBuilder machine(m.zone());
527   const uint32_t kNumElems = 25;
528   const uint32_t kLength = kNumElems * 4;
529   int32_t real_buffer[kNumElems];
530 
531   // Simulate the end of a large buffer.
532   int32_t* buffer = real_buffer - (pseudo_base / 4);
533   uint64_t length = kLength + pseudo_base;
534 
535   Node* base = m.PointerConstant(buffer);
536   Node* offset = m.Parameter(0);
537   Node* len = length_is_immediate ? m.Int64Constant(length) : m.Parameter(1);
538   Node* node =
539       m.AddNode(machine.CheckedLoad(MachineType::Int32()), base, offset, len);
540   m.Return(node);
541 
542   {
543     // randomize memory.
544     v8::base::RandomNumberGenerator rng;
545     rng.SetSeed(100);
546     rng.NextBytes(&real_buffer[0], sizeof(real_buffer));
547   }
548 
549   // in-bounds accesses.
550   for (uint32_t i = 0; i < kNumElems; i++) {
551     uint64_t offset = pseudo_base + i * 4;
552     int32_t expected = real_buffer[i];
553     CHECK_EQ(expected, m.Call(offset, length));
554   }
555 
556   // in-bounds accesses w.r.t lower 32-bits, but upper bits set.
557   for (uint64_t i = 0x100000000ULL; i != 0; i <<= 1) {
558     uint64_t offset = pseudo_base + i;
559     CheckOobValue(m.Call(offset, length));
560   }
561 
562   // slightly out-of-bounds accesses.
563   for (uint32_t i = kLength; i < kNumElems + 30; i++) {
564     uint64_t offset = pseudo_base + i * 4;
565     CheckOobValue(0, m.Call(offset, length));
566   }
567 
568   // way out-of-bounds accesses.
569   for (uint64_t offset = length; offset < 100 * A_BILLION; offset += A_GIG) {
570     if (offset < length) continue;
571     CheckOobValue(0, m.Call(offset, length));
572   }
573 }
574 
TEST(RunOobCheckedLoad64_0)575 TEST(RunOobCheckedLoad64_0) {
576   TestRunOobCheckedLoad64(0, false);
577   TestRunOobCheckedLoad64(0, true);
578 }
579 
TEST(RunOobCheckedLoad64_1)580 TEST(RunOobCheckedLoad64_1) {
581   TestRunOobCheckedLoad64(1 * A_BILLION, false);
582   TestRunOobCheckedLoad64(1 * A_BILLION, true);
583 }
584 
TEST(RunOobCheckedLoad64_2)585 TEST(RunOobCheckedLoad64_2) {
586   TestRunOobCheckedLoad64(2 * A_BILLION, false);
587   TestRunOobCheckedLoad64(2 * A_BILLION, true);
588 }
589 
TEST(RunOobCheckedLoad64_3)590 TEST(RunOobCheckedLoad64_3) {
591   TestRunOobCheckedLoad64(3 * A_BILLION, false);
592   TestRunOobCheckedLoad64(3 * A_BILLION, true);
593 }
594 
TEST(RunOobCheckedLoad64_4)595 TEST(RunOobCheckedLoad64_4) {
596   TestRunOobCheckedLoad64(4 * A_BILLION, false);
597   TestRunOobCheckedLoad64(4 * A_BILLION, true);
598 }
599 
TestRunOobCheckedStore64(uint32_t pseudo_base,bool length_is_immediate)600 void TestRunOobCheckedStore64(uint32_t pseudo_base, bool length_is_immediate) {
601   RawMachineAssemblerTester<int32_t> m(MachineType::Uint64(),
602                                        MachineType::Uint64());
603   MachineOperatorBuilder machine(m.zone());
604   const uint32_t kNumElems = 21;
605   const uint32_t kLength = kNumElems * 4;
606   const uint32_t kValue = 897234987;
607   int32_t real_buffer[kNumElems + kNumElems];
608 
609   // Simulate the end of a large buffer.
610   int32_t* buffer = real_buffer - (pseudo_base / 4);
611   uint64_t length = kLength + pseudo_base;
612 
613   Node* base = m.PointerConstant(buffer);
614   Node* offset = m.Parameter(0);
615   Node* len = length_is_immediate ? m.Int64Constant(length) : m.Parameter(1);
616   Node* val = m.Int32Constant(kValue);
617   m.AddNode(machine.CheckedStore(MachineRepresentation::kWord32), base, offset,
618             len, val);
619   m.Return(val);
620 
621   // in-bounds accesses.
622   for (uint32_t i = 0; i < kNumElems; i++) {
623     memset(real_buffer, 0, sizeof(real_buffer));
624     uint64_t offset = pseudo_base + i * 4;
625     CHECK_EQ(kValue, m.Call(offset, length));
626     for (uint32_t j = 0; j < kNumElems + kNumElems; j++) {
627       if (i == j) {
628         CHECK_EQ(kValue, real_buffer[j]);
629       } else {
630         CHECK_EQ(0, real_buffer[j]);
631       }
632     }
633   }
634 
635   memset(real_buffer, 0, sizeof(real_buffer));
636 
637   // in-bounds accesses w.r.t lower 32-bits, but upper bits set.
638   for (uint64_t i = 0x100000000ULL; i != 0; i <<= 1) {
639     uint64_t offset = pseudo_base + i;
640     CHECK_EQ(kValue, m.Call(offset, length));
641     for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
642       CHECK_EQ(0, real_buffer[j]);
643     }
644   }
645 
646   // slightly out-of-bounds accesses.
647   for (uint32_t i = kLength; i < kNumElems + 30; i++) {
648     uint64_t offset = pseudo_base + i * 4;
649     CHECK_EQ(kValue, m.Call(offset, length));
650     for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
651       CHECK_EQ(0, real_buffer[j]);
652     }
653   }
654 
655   // way out-of-bounds accesses.
656   for (uint64_t offset = length; offset < 100 * A_BILLION; offset += A_GIG) {
657     if (offset < length) continue;
658     CHECK_EQ(kValue, m.Call(offset, length));
659     for (int32_t j = 0; j < kNumElems + kNumElems; j++) {
660       CHECK_EQ(0, real_buffer[j]);
661     }
662   }
663 }
664 
TEST(RunOobCheckedStore64_0)665 TEST(RunOobCheckedStore64_0) {
666   TestRunOobCheckedStore64(0, false);
667   TestRunOobCheckedStore64(0, true);
668 }
669 
TEST(RunOobCheckedStore64_1)670 TEST(RunOobCheckedStore64_1) {
671   TestRunOobCheckedStore64(1 * A_BILLION, false);
672   TestRunOobCheckedStore64(1 * A_BILLION, true);
673 }
674 
TEST(RunOobCheckedStore64_2)675 TEST(RunOobCheckedStore64_2) {
676   TestRunOobCheckedStore64(2 * A_BILLION, false);
677   TestRunOobCheckedStore64(2 * A_BILLION, true);
678 }
679 
TEST(RunOobCheckedStore64_3)680 TEST(RunOobCheckedStore64_3) {
681   TestRunOobCheckedStore64(3 * A_BILLION, false);
682   TestRunOobCheckedStore64(3 * A_BILLION, true);
683 }
684 
TEST(RunOobCheckedStore64_4)685 TEST(RunOobCheckedStore64_4) {
686   TestRunOobCheckedStore64(4 * A_BILLION, false);
687   TestRunOobCheckedStore64(4 * A_BILLION, true);
688 }
689 
690 #endif
691 
TestRunOobCheckedLoad_pseudo(uint64_t x,bool length_is_immediate)692 void TestRunOobCheckedLoad_pseudo(uint64_t x, bool length_is_immediate) {
693   RawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
694                                        MachineType::Uint32());
695 
696   uint32_t pseudo_base = static_cast<uint32_t>(x);
697   MachineOperatorBuilder machine(m.zone());
698   const uint32_t kNumElems = 29;
699   const uint32_t kLength = pseudo_base + kNumElems * 4;
700 
701   int32_t buffer[kNumElems];
702   Node* base = m.PointerConstant(reinterpret_cast<byte*>(buffer) - pseudo_base);
703   Node* offset = m.Parameter(0);
704   Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
705   Node* node =
706       m.AddNode(machine.CheckedLoad(MachineType::Int32()), base, offset, len);
707   m.Return(node);
708 
709   {
710     // randomize memory.
711     v8::base::RandomNumberGenerator rng;
712     rng.SetSeed(100);
713     rng.NextBytes(&buffer[0], sizeof(buffer));
714   }
715 
716   // in-bounds accesses.
717   for (uint32_t i = 0; i < kNumElems; i++) {
718     uint32_t offset = static_cast<uint32_t>(i * sizeof(int32_t));
719     uint32_t expected = buffer[i];
720     CHECK_EQ(expected, m.Call(offset + pseudo_base, kLength));
721   }
722 
723   // slightly out-of-bounds accesses.
724   for (int32_t i = kNumElems; i < kNumElems + 30; i++) {
725     uint32_t offset = static_cast<uint32_t>(i * sizeof(int32_t));
726     CheckOobValue(m.Call(offset + pseudo_base, kLength));
727   }
728 
729   // way out-of-bounds accesses.
730   for (uint64_t i = pseudo_base + sizeof(buffer); i < 0xFFFFFFFF;
731        i += A_BILLION) {
732     uint32_t offset = static_cast<uint32_t>(i);
733     CheckOobValue(m.Call(offset, kLength));
734   }
735 }
736 
TEST(RunOobCheckedLoad_pseudo0)737 TEST(RunOobCheckedLoad_pseudo0) {
738   TestRunOobCheckedLoad_pseudo(0, false);
739   TestRunOobCheckedLoad_pseudo(0, true);
740 }
741 
TEST(RunOobCheckedLoad_pseudo1)742 TEST(RunOobCheckedLoad_pseudo1) {
743   TestRunOobCheckedLoad_pseudo(100000, false);
744   TestRunOobCheckedLoad_pseudo(100000, true);
745 }
746 
TEST(RunOobCheckedLoad_pseudo2)747 TEST(RunOobCheckedLoad_pseudo2) {
748   TestRunOobCheckedLoad_pseudo(A_BILLION, false);
749   TestRunOobCheckedLoad_pseudo(A_BILLION, true);
750 }
751 
TEST(RunOobCheckedLoad_pseudo3)752 TEST(RunOobCheckedLoad_pseudo3) {
753   TestRunOobCheckedLoad_pseudo(A_GIG, false);
754   TestRunOobCheckedLoad_pseudo(A_GIG, true);
755 }
756 
TEST(RunOobCheckedLoad_pseudo4)757 TEST(RunOobCheckedLoad_pseudo4) {
758   TestRunOobCheckedLoad_pseudo(2 * A_BILLION, false);
759   TestRunOobCheckedLoad_pseudo(2 * A_BILLION, true);
760 }
761 
TEST(RunOobCheckedLoad_pseudo5)762 TEST(RunOobCheckedLoad_pseudo5) {
763   TestRunOobCheckedLoad_pseudo(2 * A_GIG, false);
764   TestRunOobCheckedLoad_pseudo(2 * A_GIG, true);
765 }
766 
TEST(RunOobCheckedLoad_pseudo6)767 TEST(RunOobCheckedLoad_pseudo6) {
768   TestRunOobCheckedLoad_pseudo(3 * A_BILLION, false);
769   TestRunOobCheckedLoad_pseudo(3 * A_BILLION, true);
770 }
771 
TEST(RunOobCheckedLoad_pseudo7)772 TEST(RunOobCheckedLoad_pseudo7) {
773   TestRunOobCheckedLoad_pseudo(3 * A_GIG, false);
774   TestRunOobCheckedLoad_pseudo(3 * A_GIG, true);
775 }
776 
TEST(RunOobCheckedLoad_pseudo8)777 TEST(RunOobCheckedLoad_pseudo8) {
778   TestRunOobCheckedLoad_pseudo(4 * A_BILLION, false);
779   TestRunOobCheckedLoad_pseudo(4 * A_BILLION, true);
780 }
781 
782 template <typename MemType>
TestRunOobCheckedLoadT_pseudo(uint64_t x,bool length_is_immediate)783 void TestRunOobCheckedLoadT_pseudo(uint64_t x, bool length_is_immediate) {
784   const int32_t kReturn = 11999;
785   const uint32_t kNumElems = 29;
786   MemType buffer[kNumElems];
787   uint32_t pseudo_base = static_cast<uint32_t>(x);
788   const uint32_t kLength = static_cast<uint32_t>(pseudo_base + sizeof(buffer));
789 
790   MemType result;
791 
792   RawMachineAssemblerTester<int32_t> m(MachineType::Uint32(),
793                                        MachineType::Uint32());
794   MachineOperatorBuilder machine(m.zone());
795   Node* base = m.PointerConstant(reinterpret_cast<byte*>(buffer) - pseudo_base);
796   Node* offset = m.Parameter(0);
797   Node* len = length_is_immediate ? m.Int32Constant(kLength) : m.Parameter(1);
798   Node* node = m.AddNode(machine.CheckedLoad(MachineTypeForC<MemType>()), base,
799                          offset, len);
800   Node* store = m.StoreToPointer(
801       &result, MachineTypeForC<MemType>().representation(), node);
802   USE(store);
803   m.Return(m.Int32Constant(kReturn));
804 
805   {
806     // randomize memory.
807     v8::base::RandomNumberGenerator rng;
808     rng.SetSeed(103);
809     rng.NextBytes(&buffer[0], sizeof(buffer));
810   }
811 
812   // in-bounds accesses.
813   for (uint32_t i = 0; i < kNumElems; i++) {
814     uint32_t offset = static_cast<uint32_t>(i * sizeof(MemType));
815     MemType expected = buffer[i];
816     CHECK_EQ(kReturn, m.Call(offset + pseudo_base, kLength));
817     CHECK_EQ(expected, result);
818   }
819 
820   // slightly out-of-bounds accesses.
821   for (int32_t i = kNumElems; i < kNumElems + 30; i++) {
822     uint32_t offset = static_cast<uint32_t>(i * sizeof(MemType));
823     CHECK_EQ(kReturn, m.Call(offset + pseudo_base, kLength));
824     CheckOobValue(result);
825   }
826 
827   // way out-of-bounds accesses.
828   for (uint64_t i = pseudo_base + sizeof(buffer); i < 0xFFFFFFFF;
829        i += A_BILLION) {
830     uint32_t offset = static_cast<uint32_t>(i);
831     CHECK_EQ(kReturn, m.Call(offset, kLength));
832     CheckOobValue(result);
833   }
834 }
835 
TEST(RunOobCheckedLoadT_pseudo0)836 TEST(RunOobCheckedLoadT_pseudo0) {
837   TestRunOobCheckedLoadT_pseudo<int32_t>(0, false);
838   TestRunOobCheckedLoadT_pseudo<int32_t>(0, true);
839   TestRunOobCheckedLoadT_pseudo<float>(0, false);
840   TestRunOobCheckedLoadT_pseudo<float>(0, true);
841   TestRunOobCheckedLoadT_pseudo<double>(0, false);
842   TestRunOobCheckedLoadT_pseudo<double>(0, true);
843 }
844 
TEST(RunOobCheckedLoadT_pseudo1)845 TEST(RunOobCheckedLoadT_pseudo1) {
846   TestRunOobCheckedLoadT_pseudo<int32_t>(100000, false);
847   TestRunOobCheckedLoadT_pseudo<int32_t>(100000, true);
848   TestRunOobCheckedLoadT_pseudo<float>(100000, false);
849   TestRunOobCheckedLoadT_pseudo<float>(100000, true);
850   TestRunOobCheckedLoadT_pseudo<double>(100000, false);
851   TestRunOobCheckedLoadT_pseudo<double>(100000, true);
852 }
853 
TEST(RunOobCheckedLoadT_pseudo2)854 TEST(RunOobCheckedLoadT_pseudo2) {
855   TestRunOobCheckedLoadT_pseudo<int32_t>(A_BILLION, false);
856   TestRunOobCheckedLoadT_pseudo<int32_t>(A_BILLION, true);
857   TestRunOobCheckedLoadT_pseudo<float>(A_BILLION, false);
858   TestRunOobCheckedLoadT_pseudo<float>(A_BILLION, true);
859   TestRunOobCheckedLoadT_pseudo<double>(A_BILLION, false);
860   TestRunOobCheckedLoadT_pseudo<double>(A_BILLION, true);
861 }
862 
TEST(RunOobCheckedLoadT_pseudo3)863 TEST(RunOobCheckedLoadT_pseudo3) {
864   TestRunOobCheckedLoadT_pseudo<int32_t>(A_GIG, false);
865   TestRunOobCheckedLoadT_pseudo<int32_t>(A_GIG, true);
866   TestRunOobCheckedLoadT_pseudo<float>(A_GIG, false);
867   TestRunOobCheckedLoadT_pseudo<float>(A_GIG, true);
868   TestRunOobCheckedLoadT_pseudo<double>(A_GIG, false);
869   TestRunOobCheckedLoadT_pseudo<double>(A_GIG, true);
870 }
871 
TEST(RunOobCheckedLoadT_pseudo4)872 TEST(RunOobCheckedLoadT_pseudo4) {
873   TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_BILLION, false);
874   TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_BILLION, true);
875   TestRunOobCheckedLoadT_pseudo<float>(2 * A_BILLION, false);
876   TestRunOobCheckedLoadT_pseudo<float>(2 * A_BILLION, true);
877   TestRunOobCheckedLoadT_pseudo<double>(2 * A_BILLION, false);
878   TestRunOobCheckedLoadT_pseudo<double>(2 * A_BILLION, true);
879 }
880 
TEST(RunOobCheckedLoadT_pseudo5)881 TEST(RunOobCheckedLoadT_pseudo5) {
882   TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_GIG, false);
883   TestRunOobCheckedLoadT_pseudo<int32_t>(2 * A_GIG, true);
884   TestRunOobCheckedLoadT_pseudo<float>(2 * A_GIG, false);
885   TestRunOobCheckedLoadT_pseudo<float>(2 * A_GIG, true);
886   TestRunOobCheckedLoadT_pseudo<double>(2 * A_GIG, false);
887   TestRunOobCheckedLoadT_pseudo<double>(2 * A_GIG, true);
888 }
889 
TEST(RunOobCheckedLoadT_pseudo6)890 TEST(RunOobCheckedLoadT_pseudo6) {
891   TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_BILLION, false);
892   TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_BILLION, true);
893   TestRunOobCheckedLoadT_pseudo<float>(3 * A_BILLION, false);
894   TestRunOobCheckedLoadT_pseudo<float>(3 * A_BILLION, true);
895   TestRunOobCheckedLoadT_pseudo<double>(3 * A_BILLION, false);
896   TestRunOobCheckedLoadT_pseudo<double>(3 * A_BILLION, true);
897 }
898 
TEST(RunOobCheckedLoadT_pseudo7)899 TEST(RunOobCheckedLoadT_pseudo7) {
900   TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_GIG, false);
901   TestRunOobCheckedLoadT_pseudo<int32_t>(3 * A_GIG, true);
902   TestRunOobCheckedLoadT_pseudo<float>(3 * A_GIG, false);
903   TestRunOobCheckedLoadT_pseudo<float>(3 * A_GIG, true);
904   TestRunOobCheckedLoadT_pseudo<double>(3 * A_GIG, false);
905   TestRunOobCheckedLoadT_pseudo<double>(3 * A_GIG, true);
906 }
907 
TEST(RunOobCheckedLoadT_pseudo8)908 TEST(RunOobCheckedLoadT_pseudo8) {
909   TestRunOobCheckedLoadT_pseudo<int32_t>(4 * A_BILLION, false);
910   TestRunOobCheckedLoadT_pseudo<int32_t>(4 * A_BILLION, true);
911   TestRunOobCheckedLoadT_pseudo<float>(4 * A_BILLION, false);
912   TestRunOobCheckedLoadT_pseudo<float>(4 * A_BILLION, true);
913   TestRunOobCheckedLoadT_pseudo<double>(4 * A_BILLION, false);
914   TestRunOobCheckedLoadT_pseudo<double>(4 * A_BILLION, true);
915 }
916 
917 }  // namespace compiler
918 }  // namespace internal
919 }  // namespace v8
920