deps: update v8 to 4.3.61.21
[platform/upstream/nodejs.git] / deps / v8 / test / unittests / compiler / js-typed-lowering-unittest.cc
1 // Copyright 2014 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "src/compiler/access-builder.h"
6 #include "src/compiler/js-graph.h"
7 #include "src/compiler/js-operator.h"
8 #include "src/compiler/js-typed-lowering.h"
9 #include "src/compiler/machine-operator.h"
10 #include "src/compiler/node-properties.h"
11 #include "src/compiler/operator-properties.h"
12 #include "test/unittests/compiler/compiler-test-utils.h"
13 #include "test/unittests/compiler/graph-unittest.h"
14 #include "test/unittests/compiler/node-test-utils.h"
15 #include "testing/gmock-support.h"
16
17 using testing::BitEq;
18 using testing::IsNaN;
19
20
21 namespace v8 {
22 namespace internal {
23 namespace compiler {
24
25 namespace {
26
27 const ExternalArrayType kExternalArrayTypes[] = {
28     kExternalUint8Array,   kExternalInt8Array,   kExternalUint16Array,
29     kExternalInt16Array,   kExternalUint32Array, kExternalInt32Array,
30     kExternalFloat32Array, kExternalFloat64Array};
31
32
33 const double kFloat64Values[] = {
34     -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
35     -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
36     -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09,
37     -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984,
38     -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10,
39     -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79,
40     -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
41     -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282,
42     -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308,
43     1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228,
44     2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90,
45     2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05,
46     2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08,
47     4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54,
48     2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166,
49     4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243,
50     1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294,
51     1.79769e+308, V8_INFINITY};
52
53
54 const size_t kIndices[] = {0, 1, 42, 100, 1024};
55
56
57 const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0,  -42.0,
58                                  -1.0,         0.0,     1.0,      42.0,
59                                  1000.0,       INT_MAX, UINT_MAX, V8_INFINITY};
60
61
62 Type* const kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
63                           Type::Number(),    Type::String(), Type::Object()};
64
65
66 STATIC_ASSERT(LANGUAGE_END == 3);
67 const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG};
68
69 }  // namespace
70
71
72 class JSTypedLoweringTest : public TypedGraphTest {
73  public:
74   JSTypedLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
75   ~JSTypedLoweringTest() OVERRIDE {}
76
77  protected:
78   Reduction Reduce(Node* node) {
79     MachineOperatorBuilder machine(zone());
80     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
81     JSTypedLowering reducer(&jsgraph, zone());
82     return reducer.Reduce(node);
83   }
84
85   Node* EmptyFrameState() {
86     MachineOperatorBuilder machine(zone());
87     JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
88     return jsgraph.EmptyFrameState();
89   }
90
91   Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
92     Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
93     Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length);
94     return buffer;
95   }
96
97   Matcher<Node*> IsIntPtrConstant(intptr_t value) {
98     return sizeof(value) == 4 ? IsInt32Constant(static_cast<int32_t>(value))
99                               : IsInt64Constant(static_cast<int64_t>(value));
100   }
101
102   JSOperatorBuilder* javascript() { return &javascript_; }
103
104  private:
105   JSOperatorBuilder javascript_;
106 };
107
108
109 // -----------------------------------------------------------------------------
110 // JSUnaryNot
111
112
113 TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
114   Node* input = Parameter(Type::Boolean(), 0);
115   Node* context = Parameter(Type::Any(), 1);
116   Reduction r =
117       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
118   ASSERT_TRUE(r.Changed());
119   EXPECT_THAT(r.replacement(), IsBooleanNot(input));
120 }
121
122
123 TEST_F(JSTypedLoweringTest, JSUnaryNotWithOrderedNumber) {
124   Node* input = Parameter(Type::OrderedNumber(), 0);
125   Node* context = Parameter(Type::Any(), 1);
126   Reduction r =
127       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
128   ASSERT_TRUE(r.Changed());
129   EXPECT_THAT(r.replacement(), IsNumberEqual(input, IsNumberConstant(0)));
130 }
131
132
133 TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
134   Node* input = Parameter(
135       Type::Union(
136           Type::MinusZero(),
137           Type::Union(
138               Type::NaN(),
139               Type::Union(
140                   Type::Null(),
141                   Type::Union(
142                       Type::Undefined(),
143                       Type::Union(
144                           Type::Undetectable(),
145                           Type::Union(
146                               Type::Constant(factory()->false_value(), zone()),
147                               Type::Range(0.0, 0.0, zone()), zone()),
148                           zone()),
149                       zone()),
150                   zone()),
151               zone()),
152           zone()),
153       0);
154   Node* context = Parameter(Type::Any(), 1);
155   Reduction r =
156       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
157   ASSERT_TRUE(r.Changed());
158   EXPECT_THAT(r.replacement(), IsTrueConstant());
159 }
160
161
162 TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
163   Node* input = Parameter(
164       Type::Union(
165           Type::Constant(factory()->true_value(), zone()),
166           Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
167           zone()),
168       0);
169   Node* context = Parameter(Type::Any(), 1);
170   Reduction r =
171       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
172   ASSERT_TRUE(r.Changed());
173   EXPECT_THAT(r.replacement(), IsFalseConstant());
174 }
175
176
177 TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
178   Node* input = Parameter(Type::Range(1.0, 42.0, zone()), 0);
179   Node* context = Parameter(Type::Any(), 1);
180   Reduction r =
181       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
182   ASSERT_TRUE(r.Changed());
183   EXPECT_THAT(r.replacement(), IsFalseConstant());
184 }
185
186
187 TEST_F(JSTypedLoweringTest, JSUnaryNotWithString) {
188   Node* input = Parameter(Type::String(), 0);
189   Node* context = Parameter(Type::Any(), 1);
190   Reduction r =
191       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
192   ASSERT_TRUE(r.Changed());
193   EXPECT_THAT(r.replacement(),
194               IsNumberEqual(IsLoadField(AccessBuilder::ForStringLength(), input,
195                                         graph()->start(), graph()->start()),
196                             IsNumberConstant(0.0)));
197 }
198
199
200 TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
201   Node* input = Parameter(Type::Any(), 0);
202   Node* context = Parameter(Type::Any(), 1);
203   Reduction r =
204       Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
205   ASSERT_FALSE(r.Changed());
206 }
207
208
209 // -----------------------------------------------------------------------------
210 // Constant propagation
211
212
213 TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
214   {
215     Reduction r = Reduce(
216         Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
217     ASSERT_TRUE(r.Changed());
218     EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
219   }
220   {
221     Reduction r = Reduce(Parameter(Type::MinusZero()));
222     ASSERT_TRUE(r.Changed());
223     EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
224   }
225   {
226     Reduction r = Reduce(Parameter(
227         Type::Union(Type::MinusZero(),
228                     Type::Constant(factory()->NewNumber(0), zone()), zone())));
229     EXPECT_FALSE(r.Changed());
230   }
231 }
232
233
234 TEST_F(JSTypedLoweringTest, ParameterWithNull) {
235   Handle<HeapObject> null = factory()->null_value();
236   {
237     Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
238     ASSERT_TRUE(r.Changed());
239     EXPECT_THAT(r.replacement(),
240                 IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
241   }
242   {
243     Reduction r = Reduce(Parameter(Type::Null()));
244     ASSERT_TRUE(r.Changed());
245     EXPECT_THAT(r.replacement(),
246                 IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
247   }
248 }
249
250
251 TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
252   const double kNaNs[] = {-std::numeric_limits<double>::quiet_NaN(),
253                           std::numeric_limits<double>::quiet_NaN(),
254                           std::numeric_limits<double>::signaling_NaN()};
255   TRACED_FOREACH(double, nan, kNaNs) {
256     Handle<Object> constant = factory()->NewNumber(nan);
257     Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
258     ASSERT_TRUE(r.Changed());
259     EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
260   }
261   {
262     Reduction r =
263         Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
264     ASSERT_TRUE(r.Changed());
265     EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
266   }
267   {
268     Reduction r = Reduce(Parameter(Type::NaN()));
269     ASSERT_TRUE(r.Changed());
270     EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
271   }
272 }
273
274
275 TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
276   TRACED_FOREACH(double, value, kFloat64Values) {
277     Handle<Object> constant = factory()->NewNumber(value);
278     Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
279     ASSERT_TRUE(r.Changed());
280     EXPECT_THAT(r.replacement(), IsNumberConstant(value));
281   }
282   TRACED_FOREACH(double, value, kIntegerValues) {
283     Reduction r = Reduce(Parameter(Type::Range(value, value, zone())));
284     ASSERT_TRUE(r.Changed());
285     EXPECT_THAT(r.replacement(), IsNumberConstant(value));
286   }
287 }
288
289
290 TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
291   Handle<HeapObject> undefined = factory()->undefined_value();
292   {
293     Reduction r = Reduce(Parameter(Type::Undefined()));
294     ASSERT_TRUE(r.Changed());
295     EXPECT_THAT(r.replacement(),
296                 IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
297   }
298   {
299     Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
300     ASSERT_TRUE(r.Changed());
301     EXPECT_THAT(r.replacement(),
302                 IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
303   }
304 }
305
306
307 // -----------------------------------------------------------------------------
308 // JSToBoolean
309
310
311 TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
312   Node* input = Parameter(Type::Boolean(), 0);
313   Node* context = Parameter(Type::Any(), 1);
314   Reduction r =
315       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
316   ASSERT_TRUE(r.Changed());
317   EXPECT_EQ(input, r.replacement());
318 }
319
320
321 TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
322   Node* input = Parameter(
323       Type::Union(
324           Type::MinusZero(),
325           Type::Union(
326               Type::NaN(),
327               Type::Union(
328                   Type::Null(),
329                   Type::Union(
330                       Type::Undefined(),
331                       Type::Union(
332                           Type::Undetectable(),
333                           Type::Union(
334                               Type::Constant(factory()->false_value(), zone()),
335                               Type::Range(0.0, 0.0, zone()), zone()),
336                           zone()),
337                       zone()),
338                   zone()),
339               zone()),
340           zone()),
341       0);
342   Node* context = Parameter(Type::Any(), 1);
343   Reduction r =
344       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
345   ASSERT_TRUE(r.Changed());
346   EXPECT_THAT(r.replacement(), IsFalseConstant());
347 }
348
349
350 TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
351   Node* input = Parameter(
352       Type::Union(
353           Type::Constant(factory()->true_value(), zone()),
354           Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
355           zone()),
356       0);
357   Node* context = Parameter(Type::Any(), 1);
358   Reduction r =
359       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
360   ASSERT_TRUE(r.Changed());
361   EXPECT_THAT(r.replacement(), IsTrueConstant());
362 }
363
364
365 TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
366   Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
367   Node* context = Parameter(Type::Any(), 1);
368   Reduction r =
369       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
370   ASSERT_TRUE(r.Changed());
371   EXPECT_THAT(r.replacement(), IsTrueConstant());
372 }
373
374
375 TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
376   Node* input = Parameter(Type::OrderedNumber(), 0);
377   Node* context = Parameter(Type::Any(), 1);
378   Reduction r =
379       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
380   ASSERT_TRUE(r.Changed());
381   EXPECT_THAT(r.replacement(),
382               IsBooleanNot(IsNumberEqual(input, IsNumberConstant(0.0))));
383 }
384
385
386 TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
387   Node* input = Parameter(Type::String(), 0);
388   Node* context = Parameter(Type::Any(), 1);
389   Reduction r =
390       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
391   ASSERT_TRUE(r.Changed());
392   EXPECT_THAT(
393       r.replacement(),
394       IsNumberLessThan(IsNumberConstant(0.0),
395                        IsLoadField(AccessBuilder::ForStringLength(), input,
396                                    graph()->start(), graph()->start())));
397 }
398
399
400 TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
401   Node* input = Parameter(Type::Any(), 0);
402   Node* context = Parameter(Type::Any(), 1);
403   Reduction r =
404       Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
405   ASSERT_FALSE(r.Changed());
406 }
407
408
409 // -----------------------------------------------------------------------------
410 // JSToNumber
411
412
413 TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
414   Node* const input = Parameter(Type::PlainPrimitive(), 0);
415   Node* const context = Parameter(Type::Any(), 1);
416   Node* const effect = graph()->start();
417   Node* const control = graph()->start();
418   Reduction r =
419       FLAG_turbo_deoptimization
420           ? Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
421                                     EmptyFrameState(), effect, control))
422           : Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
423                                     effect, control));
424   ASSERT_TRUE(r.Changed());
425   EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
426                                           graph()->start(), control));
427 }
428
429
430 // -----------------------------------------------------------------------------
431 // JSStrictEqual
432
433
434 TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
435   Node* const the_hole = HeapConstant(factory()->the_hole_value());
436   Node* const context = UndefinedConstant();
437   Node* const effect = graph()->start();
438   Node* const control = graph()->start();
439   TRACED_FOREACH(Type*, type, kJSTypes) {
440     Node* const lhs = Parameter(type);
441     Reduction r = Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs,
442                                           the_hole, context, effect, control));
443     ASSERT_TRUE(r.Changed());
444     EXPECT_THAT(r.replacement(), IsFalseConstant());
445   }
446 }
447
448
449 // -----------------------------------------------------------------------------
450 // JSShiftLeft
451
452
453 TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
454   Node* const lhs = Parameter(Type::Signed32());
455   Node* const context = UndefinedConstant();
456   Node* const effect = graph()->start();
457   Node* const control = graph()->start();
458   TRACED_FORRANGE(double, rhs, 0, 31) {
459     Reduction r =
460         Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs,
461                                 NumberConstant(rhs), context, effect, control));
462     ASSERT_TRUE(r.Changed());
463     EXPECT_THAT(r.replacement(),
464                 IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
465   }
466 }
467
468
469 TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
470   Node* const lhs = Parameter(Type::Signed32());
471   Node* const rhs = Parameter(Type::Unsigned32());
472   Node* const context = UndefinedConstant();
473   Node* const effect = graph()->start();
474   Node* const control = graph()->start();
475   Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs, rhs,
476                                         context, effect, control));
477   ASSERT_TRUE(r.Changed());
478   EXPECT_THAT(r.replacement(),
479               IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
480 }
481
482
483 // -----------------------------------------------------------------------------
484 // JSShiftRight
485
486
487 TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
488   Node* const lhs = Parameter(Type::Signed32());
489   Node* const context = UndefinedConstant();
490   Node* const effect = graph()->start();
491   Node* const control = graph()->start();
492   TRACED_FORRANGE(double, rhs, 0, 31) {
493     Reduction r =
494         Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs,
495                                 NumberConstant(rhs), context, effect, control));
496     ASSERT_TRUE(r.Changed());
497     EXPECT_THAT(r.replacement(),
498                 IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
499   }
500 }
501
502
503 TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
504   Node* const lhs = Parameter(Type::Signed32());
505   Node* const rhs = Parameter(Type::Unsigned32());
506   Node* const context = UndefinedConstant();
507   Node* const effect = graph()->start();
508   Node* const control = graph()->start();
509   Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs, rhs,
510                                         context, effect, control));
511   ASSERT_TRUE(r.Changed());
512   EXPECT_THAT(r.replacement(),
513               IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
514 }
515
516
517 // -----------------------------------------------------------------------------
518 // JSShiftRightLogical
519
520
521 TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndConstant) {
522   Node* const lhs = Parameter(Type::Unsigned32());
523   Node* const context = UndefinedConstant();
524   Node* const effect = graph()->start();
525   Node* const control = graph()->start();
526   TRACED_FORRANGE(double, rhs, 0, 31) {
527     Reduction r =
528         Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
529                                 NumberConstant(rhs), context, effect, control));
530     ASSERT_TRUE(r.Changed());
531     EXPECT_THAT(r.replacement(),
532                 IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
533   }
534 }
535
536
537 TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
538   Node* const lhs = Parameter(Type::Unsigned32());
539   Node* const rhs = Parameter(Type::Unsigned32());
540   Node* const context = UndefinedConstant();
541   Node* const effect = graph()->start();
542   Node* const control = graph()->start();
543   Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
544                                         rhs, context, effect, control));
545   ASSERT_TRUE(r.Changed());
546   EXPECT_THAT(r.replacement(),
547               IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
548 }
549
550
551 // -----------------------------------------------------------------------------
552 // JSLoadContext
553
554
555 TEST_F(JSTypedLoweringTest, JSLoadContext) {
556   Node* const context = Parameter(Type::Any());
557   Node* const effect = graph()->start();
558   static bool kBooleans[] = {false, true};
559   TRACED_FOREACH(size_t, index, kIndices) {
560     TRACED_FOREACH(bool, immutable, kBooleans) {
561       Reduction const r1 = Reduce(
562           graph()->NewNode(javascript()->LoadContext(0, index, immutable),
563                            context, context, effect));
564       ASSERT_TRUE(r1.Changed());
565       EXPECT_THAT(r1.replacement(),
566                   IsLoadField(AccessBuilder::ForContextSlot(index), context,
567                               effect, graph()->start()));
568
569       Reduction const r2 = Reduce(
570           graph()->NewNode(javascript()->LoadContext(1, index, immutable),
571                            context, context, effect));
572       ASSERT_TRUE(r2.Changed());
573       EXPECT_THAT(r2.replacement(),
574                   IsLoadField(AccessBuilder::ForContextSlot(index),
575                               IsLoadField(AccessBuilder::ForContextSlot(
576                                               Context::PREVIOUS_INDEX),
577                                           context, effect, graph()->start()),
578                               effect, graph()->start()));
579     }
580   }
581 }
582
583
584 // -----------------------------------------------------------------------------
585 // JSStoreContext
586
587
588 TEST_F(JSTypedLoweringTest, JSStoreContext) {
589   Node* const context = Parameter(Type::Any());
590   Node* const effect = graph()->start();
591   Node* const control = graph()->start();
592   TRACED_FOREACH(size_t, index, kIndices) {
593     TRACED_FOREACH(Type*, type, kJSTypes) {
594       Node* const value = Parameter(type);
595
596       Reduction const r1 =
597           Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
598                                   value, context, effect, control));
599       ASSERT_TRUE(r1.Changed());
600       EXPECT_THAT(r1.replacement(),
601                   IsStoreField(AccessBuilder::ForContextSlot(index), context,
602                                value, effect, control));
603
604       Reduction const r2 =
605           Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
606                                   value, context, effect, control));
607       ASSERT_TRUE(r2.Changed());
608       EXPECT_THAT(r2.replacement(),
609                   IsStoreField(AccessBuilder::ForContextSlot(index),
610                                IsLoadField(AccessBuilder::ForContextSlot(
611                                                Context::PREVIOUS_INDEX),
612                                            context, effect, graph()->start()),
613                                value, effect, control));
614     }
615   }
616 }
617
618
619 // -----------------------------------------------------------------------------
620 // JSLoadProperty
621
622
623 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
624   const size_t kLength = 17;
625   double backing_store[kLength];
626   Handle<JSArrayBuffer> buffer =
627       NewArrayBuffer(backing_store, sizeof(backing_store));
628   VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
629                           FeedbackVectorICSlot::Invalid());
630   TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
631     Handle<JSTypedArray> array =
632         factory()->NewJSTypedArray(type, buffer, 0, kLength);
633     int const element_size = static_cast<int>(array->element_size());
634
635     Node* key = Parameter(
636         Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
637     Node* base = HeapConstant(array);
638     Node* context = UndefinedConstant();
639     Node* effect = graph()->start();
640     Node* control = graph()->start();
641     Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
642                                   key, context);
643     if (FLAG_turbo_deoptimization) {
644       node->AppendInput(zone(), UndefinedConstant());
645     }
646     node->AppendInput(zone(), effect);
647     node->AppendInput(zone(), control);
648     Reduction r = Reduce(node);
649
650     Matcher<Node*> offset_matcher =
651         element_size == 1
652             ? key
653             : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
654
655     ASSERT_TRUE(r.Changed());
656     EXPECT_THAT(
657         r.replacement(),
658         IsLoadBuffer(BufferAccess(type),
659                      IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
660                      offset_matcher,
661                      IsNumberConstant(array->byte_length()->Number()), effect,
662                      control));
663   }
664 }
665
666
667 TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
668   const size_t kLength = 17;
669   double backing_store[kLength];
670   Handle<JSArrayBuffer> buffer =
671       NewArrayBuffer(backing_store, sizeof(backing_store));
672   VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
673                           FeedbackVectorICSlot::Invalid());
674   TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
675     Handle<JSTypedArray> array =
676         factory()->NewJSTypedArray(type, buffer, 0, kLength);
677     ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
678
679     int min = random_number_generator()->NextInt(static_cast<int>(kLength));
680     int max = random_number_generator()->NextInt(static_cast<int>(kLength));
681     if (min > max) std::swap(min, max);
682     Node* key = Parameter(Type::Range(min, max, zone()));
683     Node* base = HeapConstant(array);
684     Node* context = UndefinedConstant();
685     Node* effect = graph()->start();
686     Node* control = graph()->start();
687     Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
688                                   key, context);
689     if (FLAG_turbo_deoptimization) {
690       node->AppendInput(zone(), UndefinedConstant());
691     }
692     node->AppendInput(zone(), effect);
693     node->AppendInput(zone(), control);
694     Reduction r = Reduce(node);
695
696     ASSERT_TRUE(r.Changed());
697     EXPECT_THAT(
698         r.replacement(),
699         IsLoadElement(access,
700                       IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
701                       key, effect, control));
702   }
703 }
704
705
706 // -----------------------------------------------------------------------------
707 // JSStoreProperty
708
709
710 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
711   const size_t kLength = 17;
712   double backing_store[kLength];
713   Handle<JSArrayBuffer> buffer =
714       NewArrayBuffer(backing_store, sizeof(backing_store));
715   TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
716     TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
717       Handle<JSTypedArray> array =
718           factory()->NewJSTypedArray(type, buffer, 0, kLength);
719       int const element_size = static_cast<int>(array->element_size());
720
721       Node* key = Parameter(
722           Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
723       Node* base = HeapConstant(array);
724       Node* value =
725           Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
726       Node* context = UndefinedConstant();
727       Node* effect = graph()->start();
728       Node* control = graph()->start();
729       Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode),
730                                     base, key, value, context);
731       for (int i = 0;
732            i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
733         node->AppendInput(zone(), EmptyFrameState());
734       }
735       node->AppendInput(zone(), effect);
736       node->AppendInput(zone(), control);
737       Reduction r = Reduce(node);
738
739       Matcher<Node*> offset_matcher =
740           element_size == 1
741               ? key
742               : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
743
744       ASSERT_TRUE(r.Changed());
745       EXPECT_THAT(
746           r.replacement(),
747           IsStoreBuffer(BufferAccess(type),
748                         IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
749                         offset_matcher,
750                         IsNumberConstant(array->byte_length()->Number()), value,
751                         effect, control));
752     }
753   }
754 }
755
756
757 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
758   const size_t kLength = 17;
759   double backing_store[kLength];
760   Handle<JSArrayBuffer> buffer =
761       NewArrayBuffer(backing_store, sizeof(backing_store));
762   TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
763     TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
764       Handle<JSTypedArray> array =
765           factory()->NewJSTypedArray(type, buffer, 0, kLength);
766       int const element_size = static_cast<int>(array->element_size());
767
768       Node* key = Parameter(
769           Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
770       Node* base = HeapConstant(array);
771       Node* value = Parameter(Type::Any());
772       Node* context = UndefinedConstant();
773       Node* effect = graph()->start();
774       Node* control = graph()->start();
775       Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode),
776                                     base, key, value, context);
777       for (int i = 0;
778            i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
779         node->AppendInput(zone(), EmptyFrameState());
780       }
781       node->AppendInput(zone(), effect);
782       node->AppendInput(zone(), control);
783       Reduction r = Reduce(node);
784
785       Matcher<Node*> offset_matcher =
786           element_size == 1
787               ? key
788               : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
789
790       Matcher<Node*> value_matcher =
791           IsToNumber(value, context, effect, control);
792       Matcher<Node*> effect_matcher = value_matcher;
793       if (AccessBuilder::ForTypedArrayElement(type, true)
794               .type->Is(Type::Signed32())) {
795         value_matcher = IsNumberToInt32(value_matcher);
796       } else if (AccessBuilder::ForTypedArrayElement(type, true)
797                      .type->Is(Type::Unsigned32())) {
798         value_matcher = IsNumberToUint32(value_matcher);
799       }
800
801       ASSERT_TRUE(r.Changed());
802       EXPECT_THAT(
803           r.replacement(),
804           IsStoreBuffer(BufferAccess(type),
805                         IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
806                         offset_matcher,
807                         IsNumberConstant(array->byte_length()->Number()),
808                         value_matcher, effect_matcher, control));
809     }
810   }
811 }
812
813
814 TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
815   const size_t kLength = 17;
816   double backing_store[kLength];
817   Handle<JSArrayBuffer> buffer =
818       NewArrayBuffer(backing_store, sizeof(backing_store));
819   TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
820     TRACED_FOREACH(LanguageMode, language_mode, kLanguageModes) {
821       Handle<JSTypedArray> array =
822           factory()->NewJSTypedArray(type, buffer, 0, kLength);
823       ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
824
825       int min = random_number_generator()->NextInt(static_cast<int>(kLength));
826       int max = random_number_generator()->NextInt(static_cast<int>(kLength));
827       if (min > max) std::swap(min, max);
828       Node* key = Parameter(Type::Range(min, max, zone()));
829       Node* base = HeapConstant(array);
830       Node* value = Parameter(access.type);
831       Node* context = UndefinedConstant();
832       Node* effect = graph()->start();
833       Node* control = graph()->start();
834       Node* node = graph()->NewNode(javascript()->StoreProperty(language_mode),
835                                     base, key, value, context);
836       for (int i = 0;
837            i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
838         node->AppendInput(zone(), EmptyFrameState());
839       }
840       node->AppendInput(zone(), effect);
841       node->AppendInput(zone(), control);
842       Reduction r = Reduce(node);
843
844       ASSERT_TRUE(r.Changed());
845       EXPECT_THAT(
846           r.replacement(),
847           IsStoreElement(
848               access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
849               key, value, effect, control));
850     }
851   }
852 }
853
854 }  // namespace compiler
855 }  // namespace internal
856 }  // namespace v8