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.
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"
26 const ExternalArrayType kExternalArrayTypes[] = {
27 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
28 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
29 kExternalFloat32Array, kExternalFloat64Array};
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};
53 const size_t kIndices[] = {0, 1, 42, 100, 1024};
56 const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0,
58 1000.0, INT_MAX, UINT_MAX, V8_INFINITY};
61 Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
62 Type::Number(), Type::String(), Type::Object()};
65 STATIC_ASSERT(LANGUAGE_END == 3);
66 const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG};
71 class JSTypedLoweringTest : public TypedGraphTest {
73 JSTypedLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
74 ~JSTypedLoweringTest() OVERRIDE {}
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);
84 Node* EmptyFrameState() {
85 MachineOperatorBuilder machine(zone());
86 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
87 return jsgraph.EmptyFrameState();
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);
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));
101 JSOperatorBuilder* javascript() { return &javascript_; }
104 JSOperatorBuilder javascript_;
108 // -----------------------------------------------------------------------------
112 TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
113 Node* input = Parameter(Type::Boolean(), 0);
114 Node* context = Parameter(Type::Any(), 1);
116 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
117 ASSERT_TRUE(r.Changed());
118 EXPECT_THAT(r.replacement(), IsBooleanNot(input));
122 TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
123 Node* input = Parameter(
133 Type::Undetectable(),
135 Type::Constant(factory()->false_value(), zone()),
136 Type::Range(0.0, 0.0, zone()), zone()),
143 Node* context = Parameter(Type::Any(), 1);
145 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
146 ASSERT_TRUE(r.Changed());
147 EXPECT_THAT(r.replacement(), IsTrueConstant());
151 TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
152 Node* input = Parameter(
154 Type::Constant(factory()->true_value(), zone()),
155 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
158 Node* context = Parameter(Type::Any(), 1);
160 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
161 ASSERT_TRUE(r.Changed());
162 EXPECT_THAT(r.replacement(), IsFalseConstant());
166 TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
167 Node* input = Parameter(Type::Range(1.0, 42.0, zone()), 0);
168 Node* context = Parameter(Type::Any(), 1);
170 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
171 ASSERT_TRUE(r.Changed());
172 EXPECT_THAT(r.replacement(), IsFalseConstant());
176 TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
177 Node* input = Parameter(Type::Any(), 0);
178 Node* context = Parameter(Type::Any(), 1);
180 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
181 ASSERT_TRUE(r.Changed());
182 EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input)));
186 // -----------------------------------------------------------------------------
187 // Constant propagation
190 TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
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));
198 Reduction r = Reduce(Parameter(Type::MinusZero()));
199 ASSERT_TRUE(r.Changed());
200 EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
203 Reduction r = Reduce(Parameter(
204 Type::Union(Type::MinusZero(),
205 Type::Constant(factory()->NewNumber(0), zone()), zone())));
206 EXPECT_FALSE(r.Changed());
211 TEST_F(JSTypedLoweringTest, ParameterWithNull) {
212 Handle<HeapObject> null = factory()->null_value();
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)));
220 Reduction r = Reduce(Parameter(Type::Null()));
221 ASSERT_TRUE(r.Changed());
222 EXPECT_THAT(r.replacement(),
223 IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
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()));
240 Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
241 ASSERT_TRUE(r.Changed());
242 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
245 Reduction r = Reduce(Parameter(Type::NaN()));
246 ASSERT_TRUE(r.Changed());
247 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
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));
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));
267 TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
268 Handle<HeapObject> undefined = factory()->undefined_value();
270 Reduction r = Reduce(Parameter(Type::Undefined()));
271 ASSERT_TRUE(r.Changed());
272 EXPECT_THAT(r.replacement(),
273 IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
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)));
284 // -----------------------------------------------------------------------------
288 TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
289 Node* input = Parameter(Type::Boolean(), 0);
290 Node* context = Parameter(Type::Any(), 1);
292 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
293 ASSERT_TRUE(r.Changed());
294 EXPECT_EQ(input, r.replacement());
298 TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
299 Node* input = Parameter(
309 Type::Undetectable(),
311 Type::Constant(factory()->false_value(), zone()),
312 Type::Range(0.0, 0.0, zone()), zone()),
319 Node* context = Parameter(Type::Any(), 1);
321 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
322 ASSERT_TRUE(r.Changed());
323 EXPECT_THAT(r.replacement(), IsFalseConstant());
327 TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
328 Node* input = Parameter(
330 Type::Constant(factory()->true_value(), zone()),
331 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
334 Node* context = Parameter(Type::Any(), 1);
336 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
337 ASSERT_TRUE(r.Changed());
338 EXPECT_THAT(r.replacement(), IsTrueConstant());
342 TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
343 Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
344 Node* context = Parameter(Type::Any(), 1);
346 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
347 ASSERT_TRUE(r.Changed());
348 EXPECT_THAT(r.replacement(), IsTrueConstant());
352 TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
353 Node* input = Parameter(Type::Any(), 0);
354 Node* context = Parameter(Type::Any(), 1);
356 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
357 ASSERT_TRUE(r.Changed());
358 EXPECT_THAT(r.replacement(), IsAnyToBoolean(input));
362 // -----------------------------------------------------------------------------
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();
372 FLAG_turbo_deoptimization
373 ? Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
374 EmptyFrameState(), effect, control))
375 : Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
377 ASSERT_TRUE(r.Changed());
378 EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
379 graph()->start(), control));
383 // -----------------------------------------------------------------------------
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());
402 // -----------------------------------------------------------------------------
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) {
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))));
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))));
436 // -----------------------------------------------------------------------------
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) {
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))));
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))));
470 // -----------------------------------------------------------------------------
471 // JSShiftRightLogical
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) {
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))));
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))));
504 // -----------------------------------------------------------------------------
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()));
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()));
537 // -----------------------------------------------------------------------------
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);
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));
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));
572 // -----------------------------------------------------------------------------
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());
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,
596 if (FLAG_turbo_deoptimization) {
597 node->AppendInput(zone(), UndefinedConstant());
599 node->AppendInput(zone(), effect);
600 node->AppendInput(zone(), control);
601 Reduction r = Reduce(node);
603 Matcher<Node*> offset_matcher =
606 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
608 ASSERT_TRUE(r.Changed());
611 IsLoadBuffer(BufferAccess(type),
612 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
614 IsNumberConstant(array->byte_length()->Number()), effect,
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);
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,
642 if (FLAG_turbo_deoptimization) {
643 node->AppendInput(zone(), UndefinedConstant());
645 node->AppendInput(zone(), effect);
646 node->AppendInput(zone(), control);
647 Reduction r = Reduce(node);
649 ASSERT_TRUE(r.Changed());
652 IsLoadElement(access,
653 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
654 key, effect, control));
659 // -----------------------------------------------------------------------------
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());
674 Node* key = Parameter(
675 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
676 Node* base = HeapConstant(array);
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());
687 node->AppendInput(zone(), effect);
688 node->AppendInput(zone(), control);
689 Reduction r = Reduce(node);
691 Matcher<Node*> offset_matcher =
694 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
696 ASSERT_TRUE(r.Changed());
699 IsStoreBuffer(BufferAccess(type),
700 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
702 IsNumberConstant(array->byte_length()->Number()), value,
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());
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());
732 node->AppendInput(zone(), effect);
733 node->AppendInput(zone(), control);
734 Reduction r = Reduce(node);
736 Matcher<Node*> offset_matcher =
739 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
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);
752 ASSERT_TRUE(r.Changed());
755 IsStoreBuffer(BufferAccess(type),
756 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
758 IsNumberConstant(array->byte_length()->Number()),
759 value_matcher, effect_matcher, control));
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);
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());
790 node->AppendInput(zone(), effect);
791 node->AppendInput(zone(), control);
792 Reduction r = Reduce(node);
794 ASSERT_TRUE(r.Changed());
798 access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
799 key, value, effect, control));
804 } // namespace compiler
805 } // namespace internal