[turbofan] Add length operand to LoadElement and StoreElement.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Wed, 24 Sep 2014 09:28:56 +0000 (09:28 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Wed, 24 Sep 2014 09:28:56 +0000 (09:28 +0000)
This is preliminary work, required to properly support bounds checking for typed array loads/stores.

TEST=compiler-unittests,cctest
R=mstarzinger@chromium.org

Review URL: https://codereview.chromium.org/602563002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@24172 ce2b1a6d-e550-0410-aec6-3dcde31c8c00

src/compiler/generic-node-inl.h
src/compiler/generic-node.h
src/compiler/js-generic-lowering.cc
src/compiler/js-typed-lowering.cc
src/compiler/simplified-lowering.cc
src/compiler/simplified-operator-unittest.cc
src/compiler/simplified-operator.cc
src/compiler/simplified-operator.h
test/cctest/compiler/simplified-graph-builder.h
test/cctest/compiler/test-node.cc
test/cctest/compiler/test-simplified-lowering.cc

index 82fd907..c2dc24e 100644 (file)
@@ -178,6 +178,16 @@ void GenericNode<B, S>::InsertInput(Zone* zone, int index,
 }
 
 template <class B, class S>
+void GenericNode<B, S>::RemoveInput(int index) {
+  DCHECK(index >= 0 && index < InputCount());
+  // TODO(turbofan): Optimize this implementation!
+  for (; index < InputCount() - 1; ++index) {
+    ReplaceInput(index, InputAt(index + 1));
+  }
+  TrimInputCount(InputCount() - 1);
+}
+
+template <class B, class S>
 void GenericNode<B, S>::AppendUse(Use* use) {
   use->next = NULL;
   use->prev = last_use_;
index d909943..3dc324d 100644 (file)
@@ -41,6 +41,7 @@ class GenericNode : public B {
   inline void ReplaceInput(int index, GenericNode* new_input);
   inline void AppendInput(Zone* zone, GenericNode* new_input);
   inline void InsertInput(Zone* zone, int index, GenericNode* new_input);
+  inline void RemoveInput(int index);
 
   int UseCount() { return use_count_; }
   S* UseAt(int index) {
@@ -56,7 +57,7 @@ class GenericNode : public B {
   inline void ReplaceUsesIf(UnaryPredicate pred, GenericNode* replace_to);
   inline void RemoveAllInputs();
 
-  void TrimInputCount(int input_count);
+  inline void TrimInputCount(int input_count);
 
   class Inputs {
    public:
index 586b6b5..300604e 100644 (file)
@@ -176,14 +176,7 @@ void JSGenericLowering::ReplaceWithCompareIC(Node* node, Token::Value token,
 
   if (has_frame_state) {
     // Remove the frame state from inputs.
-    // TODO(jarin) This should use Node::RemoveInput (which does not exist yet).
-    int dest = NodeProperties::FirstFrameStateIndex(node);
-    for (int i = NodeProperties::PastFrameStateIndex(node);
-         i < node->InputCount(); i++) {
-      node->ReplaceInput(dest, node->InputAt(i));
-      dest++;
-    }
-    node->TrimInputCount(dest);
+    node->RemoveInput(NodeProperties::FirstFrameStateIndex(node));
   }
 
   ReplaceWithRuntimeCall(node, Runtime::kBooleanize);
index 130c5cb..be12534 100644 (file)
@@ -540,6 +540,8 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
     JSTypedArray* array = JSTypedArray::cast(*base_type->AsConstant()->Value());
     ElementsKind elements_kind = array->map()->elements_kind();
     ExternalArrayType type = array->type();
+    uint32_t length;
+    CHECK(array->length()->ToUint32(&length));
     ElementAccess element_access;
     Node* elements = graph()->NewNode(
         simplified()->LoadField(AccessBuilder::ForJSObjectElements()), base,
@@ -555,7 +557,8 @@ Reduction JSTypedLowering::ReduceJSLoadProperty(Node* node) {
     }
     Node* value =
         graph()->NewNode(simplified()->LoadElement(element_access), elements,
-                         key, NodeProperties::GetEffectInput(node));
+                         key, jsgraph()->Uint32Constant(length),
+                         NodeProperties::GetEffectInput(node));
     return ReplaceEagerly(node, value);
   }
   return NoChange();
@@ -599,9 +602,10 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
                                     NodeProperties::GetControlInput(node));
 
     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-    Node* store = graph()->NewNode(
-        simplified()->StoreElement(element_access), elements, key, value,
-        NodeProperties::GetEffectInput(node), if_true);
+    Node* store =
+        graph()->NewNode(simplified()->StoreElement(element_access), elements,
+                         key, jsgraph()->Uint32Constant(length), value,
+                         NodeProperties::GetEffectInput(node), if_true);
 
     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
 
index e3ddf5c..8ac2a85 100644 (file)
@@ -596,7 +596,8 @@ class RepresentationSelector {
         ElementAccess access = ElementAccessOf(node->op());
         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
         ProcessInput(node, 1, kMachInt32);  // element index
-        ProcessRemainingInputs(node, 2);
+        ProcessInput(node, 2, kMachInt32);  // length
+        ProcessRemainingInputs(node, 3);
         SetOutput(node, AssumeImplicitFloat32Change(access.machine_type));
         if (lower()) lowering->DoLoadElement(node);
         break;
@@ -605,8 +606,9 @@ class RepresentationSelector {
         ElementAccess access = ElementAccessOf(node->op());
         ProcessInput(node, 0, changer_->TypeForBasePointer(access));
         ProcessInput(node, 1, kMachInt32);  // element index
-        ProcessInput(node, 2, AssumeImplicitFloat32Change(access.machine_type));
-        ProcessRemainingInputs(node, 3);
+        ProcessInput(node, 2, kMachInt32);  // length
+        ProcessInput(node, 3, AssumeImplicitFloat32Change(access.machine_type));
+        ProcessRemainingInputs(node, 4);
         SetOutput(node, 0);
         if (lower()) lowering->DoStoreElement(node);
         break;
@@ -867,6 +869,7 @@ void SimplifiedLowering::DoLoadElement(Node* node) {
   const ElementAccess& access = ElementAccessOf(node->op());
   node->set_op(machine()->Load(access.machine_type));
   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
+  node->RemoveInput(2);
 }
 
 
@@ -877,6 +880,7 @@ void SimplifiedLowering::DoStoreElement(Node* node) {
   node->set_op(
       machine()->Store(StoreRepresentation(access.machine_type, kind)));
   node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
+  node->RemoveInput(2);
 }
 
 
index ef13dac..4014f24 100644 (file)
@@ -11,6 +11,14 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+// TODO(bmeurer): Drop once we use std::ostream instead of our OStream.
+inline std::ostream& operator<<(std::ostream& os, const ElementAccess& access) {
+  OStringStream ost;
+  ost << access;
+  return os << ost.c_str();
+}
+
+
 // -----------------------------------------------------------------------------
 // Pure operators.
 
@@ -112,6 +120,103 @@ TEST_P(SimplifiedPureOperatorTest, Properties) {
 INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
                         ::testing::ValuesIn(kPureOperators));
 
+
+// -----------------------------------------------------------------------------
+// Element access operators.
+
+namespace {
+
+const ElementAccess kElementAccesses[] = {
+    {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged},
+    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
+     kMachInt8},
+    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
+     kMachInt16},
+    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
+     kMachInt32},
+    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
+     kMachUint8},
+    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
+     kMachUint16},
+    {kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag, Type::Any(),
+     kMachUint32},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt8},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt16},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
+    {kUntaggedBase, 0, Type::Signed32(), kMachInt32},
+    {kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
+    {kUntaggedBase, 0, Type::Number(), kRepFloat32},
+    {kUntaggedBase, 0, Type::Number(), kRepFloat64},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt8},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint8},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt16},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint16},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Signed32(),
+     kMachInt32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Unsigned32(),
+     kMachUint32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
+     kRepFloat32},
+    {kTaggedBase, FixedTypedArrayBase::kDataOffset, Type::Number(),
+     kRepFloat64}};
+
+}  // namespace
+
+
+class SimplifiedElementAccessOperatorTest
+    : public TestWithZone,
+      public ::testing::WithParamInterface<ElementAccess> {};
+
+
+TEST_P(SimplifiedElementAccessOperatorTest, LoadElement) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const ElementAccess& access = GetParam();
+  const Operator* op = simplified.LoadElement(access);
+
+  EXPECT_EQ(IrOpcode::kLoadElement, op->opcode());
+  EXPECT_EQ(Operator::kNoThrow | Operator::kNoWrite, op->properties());
+  EXPECT_EQ(access, ElementAccessOf(op));
+
+  EXPECT_EQ(3, OperatorProperties::GetValueInputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlInputCount(op));
+  EXPECT_EQ(4, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(1, OperatorProperties::GetValueOutputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+}
+
+
+TEST_P(SimplifiedElementAccessOperatorTest, StoreElement) {
+  SimplifiedOperatorBuilder simplified(zone());
+  const ElementAccess& access = GetParam();
+  const Operator* op = simplified.StoreElement(access);
+
+  EXPECT_EQ(IrOpcode::kStoreElement, op->opcode());
+  EXPECT_EQ(Operator::kNoRead | Operator::kNoThrow, op->properties());
+  EXPECT_EQ(access, ElementAccessOf(op));
+
+  EXPECT_EQ(4, OperatorProperties::GetValueInputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetEffectInputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetControlInputCount(op));
+  EXPECT_EQ(6, OperatorProperties::GetTotalInputCount(op));
+
+  EXPECT_EQ(0, OperatorProperties::GetValueOutputCount(op));
+  EXPECT_EQ(1, OperatorProperties::GetEffectOutputCount(op));
+  EXPECT_EQ(0, OperatorProperties::GetControlOutputCount(op));
+}
+
+
+INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest,
+                        SimplifiedElementAccessOperatorTest,
+                        ::testing::ValuesIn(kElementAccesses));
+
 }  // namespace compiler
 }  // namespace internal
 }  // namespace v8
index 75b6e22..642ffc7 100644 (file)
@@ -13,6 +13,38 @@ namespace v8 {
 namespace internal {
 namespace compiler {
 
+OStream& operator<<(OStream& os, BaseTaggedness base_taggedness) {
+  switch (base_taggedness) {
+    case kUntaggedBase:
+      return os << "untagged base";
+    case kTaggedBase:
+      return os << "tagged base";
+  }
+  UNREACHABLE();
+  return os;
+}
+
+
+bool operator==(ElementAccess const& lhs, ElementAccess const& rhs) {
+  return lhs.base_is_tagged == rhs.base_is_tagged &&
+         lhs.header_size == rhs.header_size && lhs.type == rhs.type &&
+         lhs.machine_type == rhs.machine_type;
+}
+
+
+bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
+  return !(lhs == rhs);
+}
+
+
+OStream& operator<<(OStream& os, ElementAccess const& access) {
+  os << "[" << access.base_is_tagged << ", " << access.header_size << ", ";
+  access.type->PrintTo(os);
+  os << ", " << access.machine_type << "]";
+  return os;
+}
+
+
 const FieldAccess& FieldAccessOf(const Operator* op) {
   DCHECK_NOT_NULL(op);
   DCHECK(op->opcode() == IrOpcode::kLoadField ||
@@ -49,11 +81,11 @@ struct StaticParameterTraits<FieldAccess> {
 // Specialization for static parameters of type {ElementAccess}.
 template <>
 struct StaticParameterTraits<ElementAccess> {
-  static OStream& PrintTo(OStream& os, const ElementAccess& val) {
-    return os << val.header_size;
+  static OStream& PrintTo(OStream& os, const ElementAccess& access) {
+    return os << access;
   }
-  static int HashCode(const ElementAccess& val) {
-    return (val.header_size < 16) | (val.machine_type & 0xffff);
+  static int HashCode(const ElementAccess& access) {
+    return (access.header_size < 16) | (access.machine_type & 0xffff);
   }
   static bool Equals(const ElementAccess& lhs, const ElementAccess& rhs) {
     return lhs.base_is_tagged == rhs.base_is_tagged &&
@@ -93,8 +125,8 @@ struct StaticParameterTraits<ElementAccess> {
 #define ACCESS_OP_LIST(V)                                 \
   V(LoadField, FieldAccess, Operator::kNoWrite, 1, 1)     \
   V(StoreField, FieldAccess, Operator::kNoRead, 2, 0)     \
-  V(LoadElement, ElementAccess, Operator::kNoWrite, 2, 1) \
-  V(StoreElement, ElementAccess, Operator::kNoRead, 3, 0)
+  V(LoadElement, ElementAccess, Operator::kNoWrite, 3, 1) \
+  V(StoreElement, ElementAccess, Operator::kNoRead, 4, 0)
 
 
 struct SimplifiedOperatorBuilderImpl FINAL {
index 907507c..32f0e8b 100644 (file)
@@ -28,6 +28,8 @@ struct SimplifiedOperatorBuilderImpl;
 
 enum BaseTaggedness { kUntaggedBase, kTaggedBase };
 
+OStream& operator<<(OStream&, BaseTaggedness);
+
 // An access descriptor for loads/stores of fixed structures like field
 // accesses of heap objects. Accesses from either tagged or untagged base
 // pointers are supported; untagging is done automatically during lowering.
@@ -55,6 +57,11 @@ struct ElementAccess {
   int tag() const { return base_is_tagged == kTaggedBase ? kHeapObjectTag : 0; }
 };
 
+bool operator==(ElementAccess const& lhs, ElementAccess const& rhs);
+bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs);
+
+OStream& operator<<(OStream&, ElementAccess const&);
+
 
 // If the accessed object is not a heap object, add this to the header_size.
 static const int kNonHeapObjectHeaderSize = kHeapObjectTag;
@@ -122,8 +129,12 @@ class SimplifiedOperatorBuilder FINAL {
 
   const Operator* LoadField(const FieldAccess&);
   const Operator* StoreField(const FieldAccess&);
-  const Operator* LoadElement(const ElementAccess&);
-  const Operator* StoreElement(const ElementAccess&);
+
+  // load-element [base + index], length
+  const Operator* LoadElement(ElementAccess const&);
+
+  // store-element [base + index], length, value
+  const Operator* StoreElement(ElementAccess const&);
 
  private:
   Zone* zone() const { return zone_; }
index 586b39f..1b637b7 100644 (file)
@@ -127,12 +127,14 @@ class SimplifiedGraphBuilder : public GraphBuilder {
   Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
     return NewNode(simplified()->StoreField(access), object, value);
   }
-  Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
-    return NewNode(simplified()->LoadElement(access), object, index);
+  Node* LoadElement(const ElementAccess& access, Node* object, Node* index,
+                    Node* length) {
+    return NewNode(simplified()->LoadElement(access), object, index, length);
   }
   Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
-                     Node* value) {
-    return NewNode(simplified()->StoreElement(access), object, index, value);
+                     Node* length, Node* value) {
+    return NewNode(simplified()->StoreElement(access), object, index, length,
+                   value);
   }
 
  protected:
index da10d25..28d807e 100644 (file)
@@ -338,6 +338,27 @@ TEST(Inputs) {
 }
 
 
+TEST(RemoveInput) {
+  GraphTester graph;
+
+  Node* n0 = graph.NewNode(&dummy_operator);
+  Node* n1 = graph.NewNode(&dummy_operator, n0);
+  Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
+
+  n1->RemoveInput(0);
+  CHECK_EQ(0, n1->InputCount());
+  CHECK_EQ(1, n0->UseCount());
+
+  n2->RemoveInput(0);
+  CHECK_EQ(1, n2->InputCount());
+  CHECK_EQ(0, n0->UseCount());
+  CHECK_EQ(1, n1->UseCount());
+
+  n2->RemoveInput(0);
+  CHECK_EQ(0, n2->InputCount());
+}
+
+
 TEST(AppendInputsAndIterator) {
   GraphTester graph;
 
index 2c97379..a8ff7da 100644 (file)
@@ -207,8 +207,10 @@ TEST(RunLoadStoreMap) {
 TEST(RunLoadStoreFixedArrayIndex) {
   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
   ElementAccess access = AccessBuilder::ForFixedArrayElement();
-  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
-  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
+  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
+                             t.Int32Constant(2));
+  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
+                 load);
   t.Return(load);
 
   t.LowerAllNodes();
@@ -231,14 +233,16 @@ TEST(RunLoadStoreFixedArrayIndex) {
 TEST(RunLoadStoreArrayBuffer) {
   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
   const int index = 12;
+  const int array_length = 2 * index;
   ElementAccess buffer_access =
       AccessBuilder::ForBackingStoreElement(kMachInt8);
   Node* backing_store = t.LoadField(
       AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
   Node* load =
-      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
+      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
+                    t.Int32Constant(array_length));
   t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
-                 load);
+                 t.Int32Constant(array_length), load);
   t.Return(t.jsgraph.TrueConstant());
 
   t.LowerAllNodes();
@@ -246,7 +250,6 @@ TEST(RunLoadStoreArrayBuffer) {
 
   if (Pipeline::SupportedTarget()) {
     Handle<JSArrayBuffer> array = t.factory()->NewJSArrayBuffer();
-    const int array_length = 2 * index;
     Runtime::SetupArrayBufferAllocatingData(t.isolate(), array, array_length);
     uint8_t* data = reinterpret_cast<uint8_t*>(array->backing_store());
     for (int i = 0; i < array_length; i++) {
@@ -326,8 +329,9 @@ TEST(RunLoadElementFromUntaggedBase) {
                               kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t;
-      Node* load = t.LoadElement(access, t.PointerConstant(smis),
-                                 t.Int32Constant(static_cast<int>(j)));
+      Node* load = t.LoadElement(
+          access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
+          t.Int32Constant(static_cast<int>(arraysize(smis))));
       t.Return(load);
       t.LowerAllNodes();
 
@@ -356,7 +360,8 @@ TEST(RunStoreElementFromUntaggedBase) {
       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
       Node* p0 = t.Parameter(0);
       t.StoreElement(access, t.PointerConstant(smis),
-                     t.Int32Constant(static_cast<int>(j)), p0);
+                     t.Int32Constant(static_cast<int>(j)),
+                     t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
       t.Return(p0);
       t.LowerAllNodes();
 
@@ -422,8 +427,10 @@ class AccessTester : public HandleAndZoneScope {
 
     SimplifiedLoweringTester<Object*> t;
     Node* ptr = GetBaseNode(&t);
-    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
-    t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
+    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
+                               t.Int32Constant(num_elements));
+    t.StoreElement(access, ptr, t.Int32Constant(to_index),
+                   t.Int32Constant(num_elements), load);
     t.Return(t.jsgraph.TrueConstant());
     t.LowerAllNodes();
     t.GenerateCode();
@@ -633,11 +640,13 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
   JSGraph jsgraph;
   Node* p0;
   Node* p1;
+  Node* p2;
   Node* start;
   Node* end;
   Node* ret;
 
-  explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None())
+  explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
+                        Type* p2_type = Type::None())
       : GraphAndBuilders(main_zone()),
         typer(main_zone()),
         javascript(main_zone()),
@@ -650,8 +659,10 @@ class TestingGraph : public HandleAndZoneScope, public GraphAndBuilders {
     graph()->SetEnd(end);
     p0 = graph()->NewNode(common()->Parameter(0), start);
     p1 = graph()->NewNode(common()->Parameter(1), start);
+    p2 = graph()->NewNode(common()->Parameter(2), start);
     NodeProperties::SetBounds(p0, Bounds(p0_type));
     NodeProperties::SetBounds(p1, Bounds(p1_type));
+    NodeProperties::SetBounds(p2, Bounds(p2_type));
   }
 
   void CheckLoweringBinop(IrOpcode::Value expected, const Operator* op) {
@@ -1341,8 +1352,9 @@ TEST(LowerLoadElement_to_load) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
                             Type::Any(), machine_reps[i]};
 
-    Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                    t.p1, t.start);
+    Node* load =
+        t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
+                           t.jsgraph.Int32Constant(1024), t.start);
     Node* use = t.Use(load, machine_reps[i]);
     t.Return(use);
     t.Lower();
@@ -1365,7 +1377,8 @@ TEST(LowerStoreElement_to_store) {
 
     Node* val = t.ExampleWithOutput(machine_reps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                     t.p1, val, t.start, t.start);
+                                     t.p1, t.jsgraph.Int32Constant(1024), val,
+                                     t.start, t.start);
     t.Effect(store);
     t.Lower();
     CHECK_EQ(IrOpcode::kStore, store->opcode());
@@ -1382,14 +1395,14 @@ TEST(LowerStoreElement_to_store) {
 
 
 TEST(InsertChangeForLoadElementIndex) {
-  // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged) =>
+  // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
-  TestingGraph t(Type::Any(), Type::Signed32());
+  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.start);
+                                  t.p1, t.p2, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1401,14 +1414,14 @@ TEST(InsertChangeForLoadElementIndex) {
 
 
 TEST(InsertChangeForStoreElementIndex) {
-  // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, val) =>
+  // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
-  TestingGraph t(Type::Any(), Type::Signed32());
+  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* store =
-      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
                          t.jsgraph.TrueConstant(), t.start, t.start);
   t.Effect(store);
   t.Lower();
@@ -1422,12 +1435,12 @@ TEST(InsertChangeForStoreElementIndex) {
 
 TEST(InsertChangeForLoadElement) {
   // TODO(titzer): test all load/store representation change insertions.
-  TestingGraph t(Type::Any(), Type::Signed32());
+  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.start);
+                                  t.p1, t.p1, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1454,13 +1467,13 @@ TEST(InsertChangeForLoadField) {
 
 TEST(InsertChangeForStoreElement) {
   // TODO(titzer): test all load/store representation change insertions.
-  TestingGraph t(Type::Any(), Type::Signed32());
+  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
-  Node* store =
-      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                         t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
+  Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
+                                   t.jsgraph.Int32Constant(0), t.p2, t.p1,
+                                   t.start, t.start);
   t.Effect(store);
   t.Lower();