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