[turbofan] Add BoundsCheckMode to ElementAccess.
authorbmeurer@chromium.org <bmeurer@chromium.org>
Wed, 1 Oct 2014 07:42:54 +0000 (07:42 +0000)
committerbmeurer@chromium.org <bmeurer@chromium.org>
Wed, 1 Oct 2014 07:42:54 +0000 (07:42 +0000)
This is currently only used for StoreElement. LoadElement will be
updated to make use of that in a follow-up CL (depends on additional
control input for loads first).

TEST=cctest,mjsunit
R=jarin@chromium.org, mstarzinger@chromium.org

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

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

src/compiler/access-builder.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/test-simplified-lowering.cc

index 749c04a..7f3b084 100644 (file)
@@ -53,7 +53,8 @@ FieldAccess AccessBuilder::ForExternalArrayPointer() {
 
 // static
 ElementAccess AccessBuilder::ForFixedArrayElement() {
-  return {kTaggedBase, FixedArray::kHeaderSize, Type::Any(), kMachAnyTagged};
+  return {kNoBoundsCheck, kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
+          kMachAnyTagged};
 }
 
 
@@ -64,25 +65,33 @@ ElementAccess AccessBuilder::ForTypedArrayElement(ExternalArrayType type,
   int header_size = is_external ? 0 : FixedTypedArrayBase::kDataOffset;
   switch (type) {
     case kExternalInt8Array:
-      return {taggedness, header_size, Type::Signed32(), kMachInt8};
+      return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Signed32(),
+              kMachInt8};
     case kExternalUint8Array:
     case kExternalUint8ClampedArray:
-      return {taggedness, header_size, Type::Unsigned32(), kMachUint8};
+      return {kTypedArrayBoundsCheck, taggedness, header_size,
+              Type::Unsigned32(), kMachUint8};
     case kExternalInt16Array:
-      return {taggedness, header_size, Type::Signed32(), kMachInt16};
+      return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Signed32(),
+              kMachInt16};
     case kExternalUint16Array:
-      return {taggedness, header_size, Type::Unsigned32(), kMachUint16};
+      return {kTypedArrayBoundsCheck, taggedness, header_size,
+              Type::Unsigned32(), kMachUint16};
     case kExternalInt32Array:
-      return {taggedness, header_size, Type::Signed32(), kMachInt32};
+      return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Signed32(),
+              kMachInt32};
     case kExternalUint32Array:
-      return {taggedness, header_size, Type::Unsigned32(), kMachUint32};
+      return {kTypedArrayBoundsCheck, taggedness, header_size,
+              Type::Unsigned32(), kMachUint32};
     case kExternalFloat32Array:
-      return {taggedness, header_size, Type::Number(), kRepFloat32};
+      return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Number(),
+              kRepFloat32};
     case kExternalFloat64Array:
-      return {taggedness, header_size, Type::Number(), kRepFloat64};
+      return {kTypedArrayBoundsCheck, taggedness, header_size, Type::Number(),
+              kRepFloat64};
   }
   UNREACHABLE();
-  return {kUntaggedBase, 0, Type::None(), kMachNone};
+  return {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::None(), kMachNone};
 }
 
 }  // namespace compiler
index 40854ab..4f4f5d3 100644 (file)
@@ -597,26 +597,12 @@ Reduction JSTypedLowering::ReduceJSStoreProperty(Node* node) {
       DCHECK(IsFixedTypedArrayElementsKind(elements_kind));
       element_access = AccessBuilder::ForTypedArrayElement(type, false);
     }
-
-    Node* check = graph()->NewNode(machine()->Uint32LessThan(), key,
-                                   jsgraph()->Uint32Constant(length));
-    Node* branch = graph()->NewNode(common()->Branch(), check,
-                                    NodeProperties::GetControlInput(node));
-
-    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-
     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);
-
-    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
-    Node* phi = graph()->NewNode(common()->EffectPhi(2), store,
-                                 NodeProperties::GetEffectInput(node), merge);
-
-    return ReplaceWith(phi);
+                         NodeProperties::GetEffectInput(node),
+                         NodeProperties::GetControlInput(node));
+    return ReplaceEagerly(node, store);
   }
   return NoChange();
 }
index 7ab20f5..8a34562 100644 (file)
@@ -876,12 +876,41 @@ void SimplifiedLowering::DoLoadElement(Node* node) {
 
 void SimplifiedLowering::DoStoreElement(Node* node) {
   const ElementAccess& access = ElementAccessOf(node->op());
-  WriteBarrierKind kind = ComputeWriteBarrierKind(
-      access.base_is_tagged, access.machine_type, access.type);
-  node->set_op(
-      machine()->Store(StoreRepresentation(access.machine_type, kind)));
-  node->ReplaceInput(1, ComputeIndex(access, node->InputAt(1)));
-  node->RemoveInput(2);
+  const Operator* op = machine()->Store(StoreRepresentation(
+      access.machine_type,
+      ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
+                              access.type)));
+  Node* key = node->InputAt(1);
+  Node* index = ComputeIndex(access, key);
+  if (access.bounds_check == kNoBoundsCheck) {
+    node->set_op(op);
+    node->ReplaceInput(1, index);
+    node->RemoveInput(2);
+  } else {
+    DCHECK_EQ(kTypedArrayBoundsCheck, access.bounds_check);
+
+    Node* base = node->InputAt(0);
+    Node* length = node->InputAt(2);
+    Node* value = node->InputAt(3);
+    Node* effect = node->InputAt(4);
+    Node* control = node->InputAt(5);
+
+    Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
+    Node* branch = graph()->NewNode(common()->Branch(), check, control);
+
+    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+    Node* store = graph()->NewNode(op, base, index, value, effect, if_true);
+
+    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+
+    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+
+    node->set_op(common()->EffectPhi(2));
+    node->ReplaceInput(0, store);
+    node->ReplaceInput(1, effect);
+    node->ReplaceInput(2, merge);
+    node->TrimInputCount(3);
+  }
 }
 
 
index 24d8bc5..422e64f 100644 (file)
@@ -119,43 +119,44 @@ INSTANTIATE_TEST_CASE_P(SimplifiedOperatorTest, SimplifiedPureOperatorTest,
 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}};
+    {kNoBoundsCheck, kTaggedBase, FixedArray::kHeaderSize, Type::Any(),
+     kMachAnyTagged},
+    {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+     Type::Any(), kMachInt8},
+    {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+     Type::Any(), kMachInt16},
+    {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+     Type::Any(), kMachInt32},
+    {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+     Type::Any(), kMachUint8},
+    {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+     Type::Any(), kMachUint16},
+    {kNoBoundsCheck, kUntaggedBase, kNonHeapObjectHeaderSize - kHeapObjectTag,
+     Type::Any(), kMachUint32},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Signed32(), kMachInt8},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Unsigned32(), kMachUint8},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Signed32(), kMachInt16},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Unsigned32(), kMachUint16},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Signed32(), kMachInt32},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Unsigned32(), kMachUint32},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Number(), kRepFloat32},
+    {kTypedArrayBoundsCheck, kUntaggedBase, 0, Type::Number(), kRepFloat64},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Signed32(), kMachInt8},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Unsigned32(), kMachUint8},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Signed32(), kMachInt16},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Unsigned32(), kMachUint16},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Signed32(), kMachInt32},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Unsigned32(), kMachUint32},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Number(), kRepFloat32},
+    {kTypedArrayBoundsCheck, kTaggedBase, FixedTypedArrayBase::kDataOffset,
+     Type::Number(), kRepFloat64}};
 
 }  // namespace
 
index 30b9784..bb2e76b 100644 (file)
@@ -4,6 +4,8 @@
 
 #include "src/compiler/simplified-operator.h"
 
+#include <ostream>  // NOLINT(readability/streams)
+
 #include "src/base/lazy-instance.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
@@ -25,6 +27,18 @@ std::ostream& operator<<(std::ostream& os, BaseTaggedness base_taggedness) {
 }
 
 
+std::ostream& operator<<(std::ostream& os, BoundsCheckMode bounds_check_mode) {
+  switch (bounds_check_mode) {
+    case kNoBoundsCheck:
+      return os << "no bounds check";
+    case kTypedArrayBoundsCheck:
+      return os << "ignore out of bounds";
+  }
+  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 &&
@@ -40,7 +54,7 @@ bool operator!=(ElementAccess const& lhs, ElementAccess const& rhs) {
 std::ostream& operator<<(std::ostream& os, ElementAccess const& access) {
   os << "[" << access.base_is_tagged << ", " << access.header_size << ", ";
   access.type->PrintTo(os);
-  os << ", " << access.machine_type << "]";
+  os << ", " << access.machine_type << ", " << access.bounds_check << "]";
   return os;
 }
 
index 2329b4b..b05cb20 100644 (file)
@@ -5,6 +5,8 @@
 #ifndef V8_COMPILER_SIMPLIFIED_OPERATOR_H_
 #define V8_COMPILER_SIMPLIFIED_OPERATOR_H_
 
+#include <iosfwd>
+
 #include "src/compiler/machine-type.h"
 #include "src/handles.h"
 
@@ -44,11 +46,17 @@ struct FieldAccess {
 };
 
 
+enum BoundsCheckMode { kNoBoundsCheck, kTypedArrayBoundsCheck };
+
+std::ostream& operator<<(std::ostream&, BoundsCheckMode);
+
+
 // An access descriptor for loads/stores of indexed structures like characters
 // in strings or off-heap backing stores. Accesses from either tagged or
 // untagged base pointers are supported; untagging is done automatically during
 // lowering.
 struct ElementAccess {
+  BoundsCheckMode bounds_check;   // specifies the bounds checking mode.
   BaseTaggedness base_is_tagged;  // specifies if the base pointer is tagged.
   int header_size;                // size of the header, without tag.
   Type* type;                     // type of the element.
index bafa2d8..e403436 100644 (file)
@@ -325,8 +325,8 @@ TEST(RunLoadElementFromUntaggedBase) {
   for (size_t i = 0; i < arraysize(smis); i++) {    // for header sizes
     for (size_t j = 0; (i + j) < arraysize(smis); j++) {  // for element index
       int offset = static_cast<int>(i * sizeof(Smi*));
-      ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
-                              kMachAnyTagged};
+      ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset,
+                              Type::Integral32(), kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t;
       Node* load = t.LoadElement(
@@ -354,8 +354,8 @@ TEST(RunStoreElementFromUntaggedBase) {
   for (size_t i = 0; i < arraysize(smis); i++) {    // for header sizes
     for (size_t j = 0; (i + j) < arraysize(smis); j++) {  // for element index
       int offset = static_cast<int>(i * sizeof(Smi*));
-      ElementAccess access = {kUntaggedBase, offset, Type::Integral32(),
-                              kMachAnyTagged};
+      ElementAccess access = {kNoBoundsCheck, kUntaggedBase, offset,
+                              Type::Integral32(), kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
       Node* p0 = t.Parameter(0);
@@ -517,9 +517,9 @@ class AccessTester : public HandleAndZoneScope {
 
  private:
   ElementAccess GetElementAccess() {
-    ElementAccess access = {tagged ? kTaggedBase : kUntaggedBase,
-                            tagged ? FixedArrayBase::kHeaderSize : 0,
-                            Type::Any(), rep};
+    ElementAccess access = {
+        kNoBoundsCheck, tagged ? kTaggedBase : kUntaggedBase,
+        tagged ? FixedArrayBase::kHeaderSize : 0, Type::Any(), rep};
     return access;
   }
 
@@ -1349,8 +1349,9 @@ TEST(LowerLoadElement_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
   for (size_t i = 0; i < arraysize(machine_reps); i++) {
-    ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+    ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                            FixedArrayBase::kHeaderSize, Type::Any(),
+                            machine_reps[i]};
 
     Node* load =
         t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
@@ -1372,8 +1373,9 @@ TEST(LowerStoreElement_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
   for (size_t i = 0; i < arraysize(machine_reps); i++) {
-    ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+    ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                            FixedArrayBase::kHeaderSize, Type::Any(),
+                            machine_reps[i]};
 
     Node* val = t.ExampleWithOutput(machine_reps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
@@ -1398,7 +1400,8 @@ TEST(InsertChangeForLoadElementIndex) {
   // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
@@ -1417,7 +1420,8 @@ TEST(InsertChangeForStoreElementIndex) {
   // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* store =
@@ -1436,7 +1440,8 @@ TEST(InsertChangeForStoreElementIndex) {
 TEST(InsertChangeForLoadElement) {
   // TODO(titzer): test all load/store representation change insertions.
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
@@ -1468,7 +1473,8 @@ TEST(InsertChangeForLoadField) {
 TEST(InsertChangeForStoreElement) {
   // TODO(titzer): test all load/store representation change insertions.
   TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
-  ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
+  ElementAccess access = {kNoBoundsCheck, kTaggedBase,
+                          FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
   Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,