Update V8 to version 4.1.0.21
This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.
Original commit message:
Version 4.1.0.21 (cherry-pick)
Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412
Unlink pages from the space page list after evacuation.
BUG=430201
LOG=N
R=jkummerow@chromium.org
Review URL: https://codereview.chromium.org/953813002
Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}
---
FPIIM-449
Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/test/unittests/compiler/js-typed-lowering-unittest.cc b/test/unittests/compiler/js-typed-lowering-unittest.cc
new file mode 100644
index 0000000..97ff106
--- /dev/null
+++ b/test/unittests/compiler/js-typed-lowering-unittest.cc
@@ -0,0 +1,808 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "test/unittests/compiler/compiler-test-utils.h"
+#include "test/unittests/compiler/graph-unittest.h"
+#include "test/unittests/compiler/node-test-utils.h"
+#include "testing/gmock-support.h"
+
+using testing::BitEq;
+using testing::IsNaN;
+
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+namespace {
+
+const ExternalArrayType kExternalArrayTypes[] = {
+ kExternalUint8Array, kExternalInt8Array, kExternalUint16Array,
+ kExternalInt16Array, kExternalUint32Array, kExternalInt32Array,
+ kExternalFloat32Array, kExternalFloat64Array};
+
+
+const double kFloat64Values[] = {
+ -V8_INFINITY, -4.23878e+275, -5.82632e+265, -6.60355e+220, -6.26172e+212,
+ -2.56222e+211, -4.82408e+201, -1.84106e+157, -1.63662e+127, -1.55772e+100,
+ -1.67813e+72, -2.3382e+55, -3.179e+30, -1.441e+09, -1.0647e+09,
+ -7.99361e+08, -5.77375e+08, -2.20984e+08, -32757, -13171, -9970, -3984,
+ -107, -105, -92, -77, -61, -0.000208163, -1.86685e-06, -1.17296e-10,
+ -9.26358e-11, -5.08004e-60, -1.74753e-65, -1.06561e-71, -5.67879e-79,
+ -5.78459e-130, -2.90989e-171, -7.15489e-243, -3.76242e-252, -1.05639e-263,
+ -4.40497e-267, -2.19666e-273, -4.9998e-276, -5.59821e-278, -2.03855e-282,
+ -5.99335e-283, -7.17554e-284, -3.11744e-309, -0.0, 0.0, 2.22507e-308,
+ 1.30127e-270, 7.62898e-260, 4.00313e-249, 3.16829e-233, 1.85244e-228,
+ 2.03544e-129, 1.35126e-110, 1.01182e-106, 5.26333e-94, 1.35292e-90,
+ 2.85394e-83, 1.78323e-77, 5.4967e-57, 1.03207e-25, 4.57401e-25, 1.58738e-05,
+ 2, 125, 2310, 9636, 14802, 17168, 28945, 29305, 4.81336e+07, 1.41207e+08,
+ 4.65962e+08, 1.40499e+09, 2.12648e+09, 8.80006e+30, 1.4446e+45, 1.12164e+54,
+ 2.48188e+89, 6.71121e+102, 3.074e+112, 4.9699e+152, 5.58383e+166,
+ 4.30654e+172, 7.08824e+185, 9.6586e+214, 2.028e+223, 6.63277e+243,
+ 1.56192e+261, 1.23202e+269, 5.72883e+289, 8.5798e+290, 1.40256e+294,
+ 1.79769e+308, V8_INFINITY};
+
+
+const size_t kIndices[] = {0, 1, 42, 100, 1024};
+
+
+const double kIntegerValues[] = {-V8_INFINITY, INT_MIN, -1000.0, -42.0,
+ -1.0, 0.0, 1.0, 42.0,
+ 1000.0, INT_MAX, UINT_MAX, V8_INFINITY};
+
+
+Type* const kJSTypes[] = {Type::Undefined(), Type::Null(), Type::Boolean(),
+ Type::Number(), Type::String(), Type::Object()};
+
+
+const StrictMode kStrictModes[] = {SLOPPY, STRICT};
+
+} // namespace
+
+
+class JSTypedLoweringTest : public TypedGraphTest {
+ public:
+ JSTypedLoweringTest() : TypedGraphTest(3), javascript_(zone()) {}
+ ~JSTypedLoweringTest() OVERRIDE {}
+
+ protected:
+ Reduction Reduce(Node* node) {
+ MachineOperatorBuilder machine(zone());
+ JSGraph jsgraph(graph(), common(), javascript(), &machine);
+ JSTypedLowering reducer(&jsgraph, zone());
+ return reducer.Reduce(node);
+ }
+
+ Handle<JSArrayBuffer> NewArrayBuffer(void* bytes, size_t byte_length) {
+ Handle<JSArrayBuffer> buffer = factory()->NewJSArrayBuffer();
+ Runtime::SetupArrayBuffer(isolate(), buffer, true, bytes, byte_length);
+ return buffer;
+ }
+
+ Matcher<Node*> IsIntPtrConstant(intptr_t value) {
+ return sizeof(value) == 4 ? IsInt32Constant(static_cast<int32_t>(value))
+ : IsInt64Constant(static_cast<int64_t>(value));
+ }
+
+ JSOperatorBuilder* javascript() { return &javascript_; }
+
+ private:
+ JSOperatorBuilder javascript_;
+};
+
+
+// -----------------------------------------------------------------------------
+// JSUnaryNot
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithBoolean) {
+ Node* input = Parameter(Type::Boolean(), 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsBooleanNot(input));
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithFalsish) {
+ Handle<Object> zero = factory()->NewNumber(0);
+ Node* input = Parameter(
+ Type::Union(
+ Type::MinusZero(),
+ Type::Union(
+ Type::NaN(),
+ Type::Union(
+ Type::Null(),
+ Type::Union(
+ Type::Undefined(),
+ Type::Union(
+ Type::Undetectable(),
+ Type::Union(
+ Type::Constant(factory()->false_value(), zone()),
+ Type::Range(zero, zero, zone()), zone()),
+ zone()),
+ zone()),
+ zone()),
+ zone()),
+ zone()),
+ 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithTruish) {
+ Node* input = Parameter(
+ Type::Union(
+ Type::Constant(factory()->true_value(), zone()),
+ Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
+ zone()),
+ 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithNonZeroPlainNumber) {
+ Node* input = Parameter(
+ Type::Range(factory()->NewNumber(1), factory()->NewNumber(42), zone()),
+ 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSUnaryNotWithAny) {
+ Node* input = Parameter(Type::Any(), 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->UnaryNot(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsBooleanNot(IsAnyToBoolean(input)));
+}
+
+
+// -----------------------------------------------------------------------------
+// Constant propagation
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithMinusZero) {
+ {
+ Reduction r = Reduce(
+ Parameter(Type::Constant(factory()->minus_zero_value(), zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
+ }
+ {
+ Reduction r = Reduce(Parameter(Type::MinusZero()));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(-0.0));
+ }
+ {
+ Reduction r = Reduce(Parameter(
+ Type::Union(Type::MinusZero(),
+ Type::Constant(factory()->NewNumber(0), zone()), zone())));
+ EXPECT_FALSE(r.Changed());
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithNull) {
+ Handle<HeapObject> null = factory()->null_value();
+ {
+ Reduction r = Reduce(Parameter(Type::Constant(null, zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
+ }
+ {
+ Reduction r = Reduce(Parameter(Type::Null()));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsHeapConstant(Unique<HeapObject>::CreateImmovable(null)));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithNaN) {
+ const double kNaNs[] = {base::OS::nan_value(),
+ std::numeric_limits<double>::quiet_NaN(),
+ std::numeric_limits<double>::signaling_NaN()};
+ TRACED_FOREACH(double, nan, kNaNs) {
+ Handle<Object> constant = factory()->NewNumber(nan);
+ Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+ }
+ {
+ Reduction r =
+ Reduce(Parameter(Type::Constant(factory()->nan_value(), zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+ }
+ {
+ Reduction r = Reduce(Parameter(Type::NaN()));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(IsNaN()));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithPlainNumber) {
+ TRACED_FOREACH(double, value, kFloat64Values) {
+ Handle<Object> constant = factory()->NewNumber(value);
+ Reduction r = Reduce(Parameter(Type::Constant(constant, zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(value));
+ }
+ TRACED_FOREACH(double, value, kIntegerValues) {
+ Handle<Object> constant = factory()->NewNumber(value);
+ Reduction r = Reduce(Parameter(Type::Range(constant, constant, zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsNumberConstant(value));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, ParameterWithUndefined) {
+ Handle<HeapObject> undefined = factory()->undefined_value();
+ {
+ Reduction r = Reduce(Parameter(Type::Undefined()));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
+ }
+ {
+ Reduction r = Reduce(Parameter(Type::Constant(undefined, zone())));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsHeapConstant(Unique<HeapObject>::CreateImmovable(undefined)));
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSToBoolean
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithBoolean) {
+ Node* input = Parameter(Type::Boolean(), 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_EQ(input, r.replacement());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithFalsish) {
+ Handle<Object> zero = factory()->NewNumber(0);
+ Node* input = Parameter(
+ Type::Union(
+ Type::MinusZero(),
+ Type::Union(
+ Type::NaN(),
+ Type::Union(
+ Type::Null(),
+ Type::Union(
+ Type::Undefined(),
+ Type::Union(
+ Type::Undetectable(),
+ Type::Union(
+ Type::Constant(factory()->false_value(), zone()),
+ Type::Range(zero, zero, zone()), zone()),
+ zone()),
+ zone()),
+ zone()),
+ zone()),
+ zone()),
+ 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFalseConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithTruish) {
+ Node* input = Parameter(
+ Type::Union(
+ Type::Constant(factory()->true_value(), zone()),
+ Type::Union(Type::DetectableReceiver(), Type::Symbol(), zone()),
+ zone()),
+ 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithNonZeroPlainNumber) {
+ Node* input =
+ Parameter(Type::Range(factory()->NewNumber(1),
+ factory()->NewNumber(V8_INFINITY), zone()),
+ 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsTrueConstant());
+}
+
+
+TEST_F(JSTypedLoweringTest, JSToBooleanWithAny) {
+ Node* input = Parameter(Type::Any(), 0);
+ Node* context = Parameter(Type::Any(), 1);
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ToBoolean(), input, context));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsAnyToBoolean(input));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSToNumber
+
+
+TEST_F(JSTypedLoweringTest, JSToNumberWithPlainPrimitive) {
+ Node* const input = Parameter(Type::PlainPrimitive(), 0);
+ Node* const context = Parameter(Type::Any(), 1);
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Reduction r = Reduce(graph()->NewNode(javascript()->ToNumber(), input,
+ context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsToNumber(input, IsNumberConstant(BitEq(0.0)),
+ graph()->start(), control));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStrictEqual
+
+
+TEST_F(JSTypedLoweringTest, JSStrictEqualWithTheHole) {
+ Node* const the_hole = HeapConstant(factory()->the_hole_value());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ TRACED_FOREACH(Type*, type, kJSTypes) {
+ Node* const lhs = Parameter(type);
+ Reduction r = Reduce(graph()->NewNode(javascript()->StrictEqual(), lhs,
+ the_hole, context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(), IsFalseConstant());
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftLeft
+
+
+TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndConstant) {
+ Node* const lhs = Parameter(Type::Signed32());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ TRACED_FORRANGE(double, rhs, 0, 31) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs,
+ NumberConstant(rhs), context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shl(lhs, IsNumberConstant(BitEq(rhs))));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftLeftWithSigned32AndUnsigned32) {
+ Node* const lhs = Parameter(Type::Signed32());
+ Node* const rhs = Parameter(Type::Unsigned32());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Reduction r = Reduce(graph()->NewNode(javascript()->ShiftLeft(), lhs, rhs,
+ context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shl(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftRight
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndConstant) {
+ Node* const lhs = Parameter(Type::Signed32());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ TRACED_FORRANGE(double, rhs, 0, 31) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs,
+ NumberConstant(rhs), context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Sar(lhs, IsNumberConstant(BitEq(rhs))));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightWithSigned32AndUnsigned32) {
+ Node* const lhs = Parameter(Type::Signed32());
+ Node* const rhs = Parameter(Type::Unsigned32());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRight(), lhs, rhs,
+ context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Sar(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSShiftRightLogical
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndConstant) {
+ Node* const lhs = Parameter(Type::Unsigned32());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ TRACED_FORRANGE(double, rhs, 0, 31) {
+ Reduction r =
+ Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
+ NumberConstant(rhs), context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shr(lhs, IsNumberConstant(BitEq(rhs))));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSShiftRightLogicalWithUnsigned32AndUnsigned32) {
+ Node* const lhs = Parameter(Type::Unsigned32());
+ Node* const rhs = Parameter(Type::Unsigned32());
+ Node* const context = UndefinedConstant();
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ Reduction r = Reduce(graph()->NewNode(javascript()->ShiftRightLogical(), lhs,
+ rhs, context, effect, control));
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(r.replacement(),
+ IsWord32Shr(lhs, IsWord32And(rhs, IsInt32Constant(0x1f))));
+}
+
+
+// -----------------------------------------------------------------------------
+// JSLoadContext
+
+
+TEST_F(JSTypedLoweringTest, JSLoadContext) {
+ Node* const context = Parameter(Type::Any());
+ Node* const effect = graph()->start();
+ static bool kBooleans[] = {false, true};
+ TRACED_FOREACH(size_t, index, kIndices) {
+ TRACED_FOREACH(bool, immutable, kBooleans) {
+ Reduction const r1 = Reduce(
+ graph()->NewNode(javascript()->LoadContext(0, index, immutable),
+ context, context, effect));
+ ASSERT_TRUE(r1.Changed());
+ EXPECT_THAT(r1.replacement(),
+ IsLoadField(AccessBuilder::ForContextSlot(index), context,
+ effect, graph()->start()));
+
+ Reduction const r2 = Reduce(
+ graph()->NewNode(javascript()->LoadContext(1, index, immutable),
+ context, context, effect));
+ ASSERT_TRUE(r2.Changed());
+ EXPECT_THAT(r2.replacement(),
+ IsLoadField(AccessBuilder::ForContextSlot(index),
+ IsLoadField(AccessBuilder::ForContextSlot(
+ Context::PREVIOUS_INDEX),
+ context, effect, graph()->start()),
+ effect, graph()->start()));
+ }
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreContext
+
+
+TEST_F(JSTypedLoweringTest, JSStoreContext) {
+ Node* const context = Parameter(Type::Any());
+ Node* const effect = graph()->start();
+ Node* const control = graph()->start();
+ TRACED_FOREACH(size_t, index, kIndices) {
+ TRACED_FOREACH(Type*, type, kJSTypes) {
+ Node* const value = Parameter(type);
+
+ Reduction const r1 =
+ Reduce(graph()->NewNode(javascript()->StoreContext(0, index), context,
+ value, context, effect, control));
+ ASSERT_TRUE(r1.Changed());
+ EXPECT_THAT(r1.replacement(),
+ IsStoreField(AccessBuilder::ForContextSlot(index), context,
+ value, effect, control));
+
+ Reduction const r2 =
+ Reduce(graph()->NewNode(javascript()->StoreContext(1, index), context,
+ value, context, effect, control));
+ ASSERT_TRUE(r2.Changed());
+ EXPECT_THAT(r2.replacement(),
+ IsStoreField(AccessBuilder::ForContextSlot(index),
+ IsLoadField(AccessBuilder::ForContextSlot(
+ Context::PREVIOUS_INDEX),
+ context, effect, graph()->start()),
+ value, effect, control));
+ }
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSLoadProperty
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArray) {
+ const size_t kLength = 17;
+ double backing_store[kLength];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, sizeof(backing_store));
+ VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+ FeedbackVectorICSlot::Invalid());
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, 0, kLength);
+ int const element_size = static_cast<int>(array->element_size());
+
+ Node* key = Parameter(
+ Type::Range(factory()->NewNumber(kMinInt / element_size),
+ factory()->NewNumber(kMaxInt / element_size), zone()));
+ Node* base = HeapConstant(array);
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
+ key, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ Matcher<Node*> offset_matcher =
+ element_size == 1
+ ? key
+ : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsLoadBuffer(BufferAccess(type),
+ IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+ offset_matcher,
+ IsNumberConstant(array->byte_length()->Number()), effect,
+ control));
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSLoadPropertyFromExternalTypedArrayWithSafeKey) {
+ const size_t kLength = 17;
+ double backing_store[kLength];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, sizeof(backing_store));
+ VectorSlotPair feedback(Handle<TypeFeedbackVector>::null(),
+ FeedbackVectorICSlot::Invalid());
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, 0, kLength);
+ ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
+
+ int min = random_number_generator()->NextInt(static_cast<int>(kLength));
+ int max = random_number_generator()->NextInt(static_cast<int>(kLength));
+ if (min > max) std::swap(min, max);
+ Node* key = Parameter(Type::Range(factory()->NewNumber(min),
+ factory()->NewNumber(max), zone()));
+ Node* base = HeapConstant(array);
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->LoadProperty(feedback), base,
+ key, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsLoadElement(access,
+ IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+ key, effect, control));
+ }
+}
+
+
+// -----------------------------------------------------------------------------
+// JSStoreProperty
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArray) {
+ const size_t kLength = 17;
+ double backing_store[kLength];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, sizeof(backing_store));
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, 0, kLength);
+ int const element_size = static_cast<int>(array->element_size());
+
+ Node* key = Parameter(
+ Type::Range(factory()->NewNumber(kMinInt / element_size),
+ factory()->NewNumber(kMaxInt / element_size), zone()));
+ Node* base = HeapConstant(array);
+ Node* value =
+ Parameter(AccessBuilder::ForTypedArrayElement(type, true).type);
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+ base, key, value, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ Matcher<Node*> offset_matcher =
+ element_size == 1
+ ? key
+ : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsStoreBuffer(BufferAccess(type),
+ IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+ offset_matcher,
+ IsNumberConstant(array->byte_length()->Number()), value,
+ effect, control));
+ }
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithConversion) {
+ const size_t kLength = 17;
+ double backing_store[kLength];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, sizeof(backing_store));
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, 0, kLength);
+ int const element_size = static_cast<int>(array->element_size());
+
+ Node* key = Parameter(
+ Type::Range(factory()->NewNumber(kMinInt / element_size),
+ factory()->NewNumber(kMaxInt / element_size), zone()));
+ Node* base = HeapConstant(array);
+ Node* value = Parameter(Type::Any());
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+ base, key, value, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ Matcher<Node*> offset_matcher =
+ element_size == 1
+ ? key
+ : IsWord32Shl(key, IsInt32Constant(WhichPowerOf2(element_size)));
+
+ Matcher<Node*> value_matcher =
+ IsToNumber(value, context, effect, control);
+ Matcher<Node*> effect_matcher = value_matcher;
+ if (AccessBuilder::ForTypedArrayElement(type, true)
+ .type->Is(Type::Signed32())) {
+ value_matcher = IsNumberToInt32(value_matcher);
+ } else if (AccessBuilder::ForTypedArrayElement(type, true)
+ .type->Is(Type::Unsigned32())) {
+ value_matcher = IsNumberToUint32(value_matcher);
+ }
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsStoreBuffer(BufferAccess(type),
+ IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+ offset_matcher,
+ IsNumberConstant(array->byte_length()->Number()),
+ value_matcher, effect_matcher, control));
+ }
+ }
+}
+
+
+TEST_F(JSTypedLoweringTest, JSStorePropertyToExternalTypedArrayWithSafeKey) {
+ const size_t kLength = 17;
+ double backing_store[kLength];
+ Handle<JSArrayBuffer> buffer =
+ NewArrayBuffer(backing_store, sizeof(backing_store));
+ TRACED_FOREACH(ExternalArrayType, type, kExternalArrayTypes) {
+ TRACED_FOREACH(StrictMode, strict_mode, kStrictModes) {
+ Handle<JSTypedArray> array =
+ factory()->NewJSTypedArray(type, buffer, 0, kLength);
+ ElementAccess access = AccessBuilder::ForTypedArrayElement(type, true);
+
+ int min = random_number_generator()->NextInt(static_cast<int>(kLength));
+ int max = random_number_generator()->NextInt(static_cast<int>(kLength));
+ if (min > max) std::swap(min, max);
+ Node* key = Parameter(Type::Range(factory()->NewNumber(min),
+ factory()->NewNumber(max), zone()));
+ Node* base = HeapConstant(array);
+ Node* value = Parameter(access.type);
+ Node* context = UndefinedConstant();
+ Node* effect = graph()->start();
+ Node* control = graph()->start();
+ Node* node = graph()->NewNode(javascript()->StoreProperty(strict_mode),
+ base, key, value, context);
+ if (FLAG_turbo_deoptimization) {
+ node->AppendInput(zone(), UndefinedConstant());
+ }
+ node->AppendInput(zone(), effect);
+ node->AppendInput(zone(), control);
+ Reduction r = Reduce(node);
+
+ ASSERT_TRUE(r.Changed());
+ EXPECT_THAT(
+ r.replacement(),
+ IsStoreElement(
+ access, IsIntPtrConstant(bit_cast<intptr_t>(&backing_store[0])),
+ key, value, effect, control));
+ }
+ }
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8