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 "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"
27 const ExternalArrayType kExternalArrayTypes[] = {
28 kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
29 kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
30 kExternalFloat32Array, kExternalFloat64Array};
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};
54 const size_t kIndices[] = {0, 1, 42, 100, 1024};
57 const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0,
59 1000.0, INT_MAX, UINT_MAX, V8_INFINITY};
62 Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
63 Type::Number(), Type::String(), Type::Object()};
66 STATIC_ASSERT(LANGUAGE_END == 3);
67 const LanguageMode kLanguageModes[] = {SLOPPY, STRICT, STRONG};
72 class JSTypedLoweringTest : public TypedGraphTest {
74 JSTypedLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
75 ~JSTypedLoweringTest() OVERRIDE {}
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);
85 Node* EmptyFrameState() {
86 MachineOperatorBuilder machine(zone());
87 JSGraph jsgraph(isolate(), graph(), common(), javascript(), &machine);
88 return jsgraph.EmptyFrameState();
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);
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));
102 JSOperatorBuilder* javascript() { return &javascript_; }
105 JSOperatorBuilder javascript_;
109 // -----------------------------------------------------------------------------
113 TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
114 Node* input = Parameter(Type::Boolean(), 0);
115 Node* context = Parameter(Type::Any(), 1);
117 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
118 ASSERT_TRUE(r.Changed());
119 EXPECT_THAT(r.replacement(), IsBooleanNot(input));
123 TEST_F(JSTypedLoweringTest, JSUnaryNotWithOrderedNumber) {
124 Node* input = Parameter(Type::OrderedNumber(), 0);
125 Node* context = Parameter(Type::Any(), 1);
127 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
128 ASSERT_TRUE(r.Changed());
129 EXPECT_THAT(r.replacement(), IsNumberEqual(input, IsNumberConstant(0)));
133 TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
134 Node* input = Parameter(
144 Type::Undetectable(),
146 Type::Constant(factory()->false_value(), zone()),
147 Type::Range(0.0, 0.0, zone()), zone()),
154 Node* context = Parameter(Type::Any(), 1);
156 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
157 ASSERT_TRUE(r.Changed());
158 EXPECT_THAT(r.replacement(), IsTrueConstant());
162 TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
163 Node* input = Parameter(
165 Type::Constant(factory()->true_value(), zone()),
166 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
169 Node* context = Parameter(Type::Any(), 1);
171 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
172 ASSERT_TRUE(r.Changed());
173 EXPECT_THAT(r.replacement(), IsFalseConstant());
177 TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
178 Node* input = Parameter(Type::Range(1.0, 42.0, zone()), 0);
179 Node* context = Parameter(Type::Any(), 1);
181 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
182 ASSERT_TRUE(r.Changed());
183 EXPECT_THAT(r.replacement(), IsFalseConstant());
187 TEST_F(JSTypedLoweringTest, JSUnaryNotWithString) {
188 Node* input = Parameter(Type::String(), 0);
189 Node* context = Parameter(Type::Any(), 1);
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)));
200 TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
201 Node* input = Parameter(Type::Any(), 0);
202 Node* context = Parameter(Type::Any(), 1);
204 Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
205 ASSERT_FALSE(r.Changed());
209 // -----------------------------------------------------------------------------
210 // Constant propagation
213 TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
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));
221 Reduction r = Reduce(Parameter(Type::MinusZero()));
222 ASSERT_TRUE(r.Changed());
223 EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
226 Reduction r = Reduce(Parameter(
227 Type::Union(Type::MinusZero(),
228 Type::Constant(factory()->NewNumber(0), zone()), zone())));
229 EXPECT_FALSE(r.Changed());
234 TEST_F(JSTypedLoweringTest, ParameterWithNull) {
235 Handle<HeapObject> null = factory()->null_value();
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)));
243 Reduction r = Reduce(Parameter(Type::Null()));
244 ASSERT_TRUE(r.Changed());
245 EXPECT_THAT(r.replacement(),
246 IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
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()));
263 Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
264 ASSERT_TRUE(r.Changed());
265 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
268 Reduction r = Reduce(Parameter(Type::NaN()));
269 ASSERT_TRUE(r.Changed());
270 EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
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));
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));
290 TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
291 Handle<HeapObject> undefined = factory()->undefined_value();
293 Reduction r = Reduce(Parameter(Type::Undefined()));
294 ASSERT_TRUE(r.Changed());
295 EXPECT_THAT(r.replacement(),
296 IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
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)));
307 // -----------------------------------------------------------------------------
311 TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
312 Node* input = Parameter(Type::Boolean(), 0);
313 Node* context = Parameter(Type::Any(), 1);
315 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
316 ASSERT_TRUE(r.Changed());
317 EXPECT_EQ(input, r.replacement());
321 TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
322 Node* input = Parameter(
332 Type::Undetectable(),
334 Type::Constant(factory()->false_value(), zone()),
335 Type::Range(0.0, 0.0, zone()), zone()),
342 Node* context = Parameter(Type::Any(), 1);
344 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
345 ASSERT_TRUE(r.Changed());
346 EXPECT_THAT(r.replacement(), IsFalseConstant());
350 TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
351 Node* input = Parameter(
353 Type::Constant(factory()->true_value(), zone()),
354 Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
357 Node* context = Parameter(Type::Any(), 1);
359 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
360 ASSERT_TRUE(r.Changed());
361 EXPECT_THAT(r.replacement(), IsTrueConstant());
365 TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
366 Node* input = Parameter(Type::Range(1, V8_INFINITY, zone()), 0);
367 Node* context = Parameter(Type::Any(), 1);
369 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
370 ASSERT_TRUE(r.Changed());
371 EXPECT_THAT(r.replacement(), IsTrueConstant());
375 TEST_F(JSTypedLoweringTest, JSToBooleanWithOrderedNumber) {
376 Node* input = Parameter(Type::OrderedNumber(), 0);
377 Node* context = Parameter(Type::Any(), 1);
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))));
386 TEST_F(JSTypedLoweringTest, JSToBooleanWithString) {
387 Node* input = Parameter(Type::String(), 0);
388 Node* context = Parameter(Type::Any(), 1);
390 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
391 ASSERT_TRUE(r.Changed());
394 IsNumberLessThan(IsNumberConstant(0.0),
395 IsLoadField(AccessBuilder::ForStringLength(), input,
396 graph()->start(), graph()->start())));
400 TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
401 Node* input = Parameter(Type::Any(), 0);
402 Node* context = Parameter(Type::Any(), 1);
404 Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
405 ASSERT_FALSE(r.Changed());
409 // -----------------------------------------------------------------------------
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();
419 FLAG_turbo_deoptimization
420 ? Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
421 EmptyFrameState(), effect, control))
422 : Reduce(graph()->NewNode(javascript()->ToNumber(), input, context,
424 ASSERT_TRUE(r.Changed());
425 EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
426 graph()->start(), control));
430 // -----------------------------------------------------------------------------
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());
449 // -----------------------------------------------------------------------------
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) {
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))));
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))));
483 // -----------------------------------------------------------------------------
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) {
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))));
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))));
517 // -----------------------------------------------------------------------------
518 // JSShiftRightLogical
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) {
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))));
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))));
551 // -----------------------------------------------------------------------------
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()));
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()));
584 // -----------------------------------------------------------------------------
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);
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));
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));
619 // -----------------------------------------------------------------------------
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());
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,
643 if (FLAG_turbo_deoptimization) {
644 node->AppendInput(zone(), UndefinedConstant());
646 node->AppendInput(zone(), effect);
647 node->AppendInput(zone(), control);
648 Reduction r = Reduce(node);
650 Matcher<Node*> offset_matcher =
653 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
655 ASSERT_TRUE(r.Changed());
658 IsLoadBuffer(BufferAccess(type),
659 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
661 IsNumberConstant(array->byte_length()->Number()), effect,
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);
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,
689 if (FLAG_turbo_deoptimization) {
690 node->AppendInput(zone(), UndefinedConstant());
692 node->AppendInput(zone(), effect);
693 node->AppendInput(zone(), control);
694 Reduction r = Reduce(node);
696 ASSERT_TRUE(r.Changed());
699 IsLoadElement(access,
700 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
701 key, effect, control));
706 // -----------------------------------------------------------------------------
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());
721 Node* key = Parameter(
722 Type::Range(kMinInt / element_size, kMaxInt / element_size, zone()));
723 Node* base = HeapConstant(array);
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);
732 i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
733 node->AppendInput(zone(), EmptyFrameState());
735 node->AppendInput(zone(), effect);
736 node->AppendInput(zone(), control);
737 Reduction r = Reduce(node);
739 Matcher<Node*> offset_matcher =
742 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
744 ASSERT_TRUE(r.Changed());
747 IsStoreBuffer(BufferAccess(type),
748 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
750 IsNumberConstant(array->byte_length()->Number()), value,
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());
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);
778 i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
779 node->AppendInput(zone(), EmptyFrameState());
781 node->AppendInput(zone(), effect);
782 node->AppendInput(zone(), control);
783 Reduction r = Reduce(node);
785 Matcher<Node*> offset_matcher =
788 : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
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);
801 ASSERT_TRUE(r.Changed());
804 IsStoreBuffer(BufferAccess(type),
805 IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
807 IsNumberConstant(array->byte_length()->Number()),
808 value_matcher, effect_matcher, control));
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);
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);
837 i < OperatorProperties::GetFrameStateInputCount(node->op()); i++) {
838 node->AppendInput(zone(), EmptyFrameState());
840 node->AppendInput(zone(), effect);
841 node->AppendInput(zone(), control);
842 Reduction r = Reduce(node);
844 ASSERT_TRUE(r.Changed());
848 access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
849 key, value, effect, control));
854 } // namespace compiler
855 } // namespace internal