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