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