Merged: Squashed multiple commits.

Merged: [compiler] Introduce a new node for array index masking.
Revision: eab08dae955af01ca75d6a65b836d402c04848e6

Merged: [compiler] array index masking on --future
Revision: c6c422965e0a022a334422d5ab0c9b11db557bb7

NOTRY=true
NOPRESUBMIT=true
NOTREECHECKS=true
R=bmeurer@chromium.org

Bug: 
Change-Id: Ibc5e2d29eaae1f036fc6a1c22724f1f28846a2dd
Reviewed-on: https://chromium-review.googlesource.com/848919
Reviewed-by: Benedikt Meurer <bmeurer@chromium.org>
Cr-Commit-Position: refs/branch-heads/6.4@{#28}
Cr-Branched-From: 0407506af3d9d7e2718be1d8759296165b218fcf-refs/heads/6.4.388@{#1}
Cr-Branched-From: a5fc4e085ee543cb608eb11034bc8f147ba388e1-refs/heads/master@{#49724}
diff --git a/src/compiler/effect-control-linearizer.cc b/src/compiler/effect-control-linearizer.cc
index 5e986b4..2372a0f 100644
--- a/src/compiler/effect-control-linearizer.cc
+++ b/src/compiler/effect-control-linearizer.cc
@@ -21,10 +21,12 @@
 
 EffectControlLinearizer::EffectControlLinearizer(
     JSGraph* js_graph, Schedule* schedule, Zone* temp_zone,
-    SourcePositionTable* source_positions)
+    SourcePositionTable* source_positions,
+    MaskArrayIndexEnable mask_array_index)
     : js_graph_(js_graph),
       schedule_(schedule),
       temp_zone_(temp_zone),
+      mask_array_index_(mask_array_index),
       source_positions_(source_positions),
       graph_assembler_(js_graph, nullptr, nullptr, temp_zone),
       frame_state_zapper_(nullptr) {}
@@ -690,6 +692,9 @@
     case IrOpcode::kCheckBounds:
       result = LowerCheckBounds(node, frame_state);
       break;
+    case IrOpcode::kMaskIndexWithBound:
+      result = LowerMaskIndexWithBound(node);
+      break;
     case IrOpcode::kCheckMaps:
       LowerCheckMaps(node, frame_state);
       break;
@@ -1295,6 +1300,19 @@
   return index;
 }
 
+Node* EffectControlLinearizer::LowerMaskIndexWithBound(Node* node) {
+  Node* index = node->InputAt(0);
+  if (mask_array_index_ == kMaskArrayIndex) {
+    Node* limit = node->InputAt(1);
+
+    Node* mask = __ Word32Sar(__ Word32Or(__ Int32Sub(limit, index), index),
+                              __ Int32Constant(31));
+    mask = __ Word32Xor(mask, __ Int32Constant(-1));
+    index = __ Word32And(index, mask);
+  }
+  return index;
+}
+
 void EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state) {
   CheckMapsParameters const& p = CheckMapsParametersOf(node->op());
   Node* value = node->InputAt(0);
diff --git a/src/compiler/effect-control-linearizer.h b/src/compiler/effect-control-linearizer.h
index dc75c2a..7cf6910 100644
--- a/src/compiler/effect-control-linearizer.h
+++ b/src/compiler/effect-control-linearizer.h
@@ -30,8 +30,11 @@
 
 class V8_EXPORT_PRIVATE EffectControlLinearizer {
  public:
+  enum MaskArrayIndexEnable { kDoNotMaskArrayIndex, kMaskArrayIndex };
+
   EffectControlLinearizer(JSGraph* graph, Schedule* schedule, Zone* temp_zone,
-                          SourcePositionTable* source_positions);
+                          SourcePositionTable* source_positions,
+                          MaskArrayIndexEnable mask_array_index);
 
   void Run();
 
@@ -53,6 +56,7 @@
   Node* LowerChangeTaggedToUint32(Node* node);
   Node* LowerChangeTaggedToTaggedSigned(Node* node);
   Node* LowerCheckBounds(Node* node, Node* frame_state);
+  Node* LowerMaskIndexWithBound(Node* node);
   Node* LowerCheckInternalizedString(Node* node, Node* frame_state);
   void LowerCheckMaps(Node* node, Node* frame_state);
   Node* LowerCompareMaps(Node* node);
@@ -190,6 +194,7 @@
   JSGraph* js_graph_;
   Schedule* schedule_;
   Zone* temp_zone_;
+  MaskArrayIndexEnable mask_array_index_;
   RegionObservability region_observability_ = RegionObservability::kObservable;
   SourcePositionTable* source_positions_;
   GraphAssembler graph_assembler_;
diff --git a/src/compiler/graph-assembler.h b/src/compiler/graph-assembler.h
index f6d882a..3d3c2ed 100644
--- a/src/compiler/graph-assembler.h
+++ b/src/compiler/graph-assembler.h
@@ -40,6 +40,7 @@
   V(Word32Xor)                            \
   V(Word32Shr)                            \
   V(Word32Shl)                            \
+  V(Word32Sar)                            \
   V(IntAdd)                               \
   V(IntSub)                               \
   V(IntMul)                               \
diff --git a/src/compiler/js-builtin-reducer.cc b/src/compiler/js-builtin-reducer.cc
index 264c415..df6fdba 100644
--- a/src/compiler/js-builtin-reducer.cc
+++ b/src/compiler/js-builtin-reducer.cc
@@ -2402,8 +2402,12 @@
 
         // Return the character from the {receiver} as single character string.
         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+
+        Node* masked_index = graph()->NewNode(
+            simplified()->MaskIndexWithBound(), index, receiver_length);
+
         Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
-                                       index, if_true);
+                                       masked_index, if_true);
 
         // Return the empty string otherwise.
         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
@@ -2456,8 +2460,12 @@
 
         // Load the character from the {receiver}.
         Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+
+        Node* masked_index = graph()->NewNode(
+            simplified()->MaskIndexWithBound(), index, receiver_length);
+
         Node* vtrue = graph()->NewNode(simplified()->StringCharCodeAt(),
-                                       receiver, index, if_true);
+                                       receiver, masked_index, if_true);
 
         // Return NaN otherwise.
         Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
diff --git a/src/compiler/js-call-reducer.cc b/src/compiler/js-call-reducer.cc
index a7702d8..c595b36 100644
--- a/src/compiler/js-call-reducer.cc
+++ b/src/compiler/js-call-reducer.cc
@@ -1505,9 +1505,12 @@
       simplified()->LoadField(AccessBuilder::ForJSObjectElements()), receiver,
       *effect, control);
 
+  Node* masked_index =
+      graph()->NewNode(simplified()->MaskIndexWithBound(), *k, length);
+
   Node* element = *effect = graph()->NewNode(
       simplified()->LoadElement(AccessBuilder::ForFixedArrayElement(kind)),
-      elements, *k, *effect, control);
+      elements, masked_index, *effect, control);
   return element;
 }
 
diff --git a/src/compiler/js-native-context-specialization.cc b/src/compiler/js-native-context-specialization.cc
index 94b02d6..a6786da 100644
--- a/src/compiler/js-native-context-specialization.cc
+++ b/src/compiler/js-native-context-specialization.cc
@@ -2152,10 +2152,13 @@
           Node* etrue = effect;
           Node* vtrue;
           {
+            Node* masked_index = graph()->NewNode(
+                simplified()->MaskIndexWithBound(), index, length);
+
             // Perform the actual load
             vtrue = etrue = graph()->NewNode(
                 simplified()->LoadTypedElement(external_array_type), buffer,
-                base_pointer, external_pointer, index, etrue, if_true);
+                base_pointer, external_pointer, masked_index, etrue, if_true);
           }
 
           Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
@@ -2173,10 +2176,13 @@
               graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                                vtrue, vfalse, control);
         } else {
+          Node* masked_index = graph()->NewNode(
+              simplified()->MaskIndexWithBound(), index, length);
+
           // Perform the actual load.
           value = effect = graph()->NewNode(
               simplified()->LoadTypedElement(external_array_type), buffer,
-              base_pointer, external_pointer, index, effect, control);
+              base_pointer, external_pointer, masked_index, effect, control);
         }
         break;
       }
@@ -2321,10 +2327,13 @@
         Node* etrue = effect;
         Node* vtrue;
         {
+          Node* masked_index = graph()->NewNode(
+              simplified()->MaskIndexWithBound(), index, length);
+
           // Perform the actual load
           vtrue = etrue =
               graph()->NewNode(simplified()->LoadElement(element_access),
-                               elements, index, etrue, if_true);
+                               elements, masked_index, etrue, if_true);
 
           // Handle loading from holey backing stores correctly, by either
           // mapping the hole to undefined if possible, or deoptimizing
@@ -2359,10 +2368,13 @@
             graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                              vtrue, vfalse, control);
       } else {
+        Node* masked_index =
+            graph()->NewNode(simplified()->MaskIndexWithBound(), index, length);
+
         // Perform the actual load.
         value = effect =
             graph()->NewNode(simplified()->LoadElement(element_access),
-                             elements, index, effect, control);
+                             elements, masked_index, effect, control);
 
         // Handle loading from holey backing stores correctly, by either mapping
         // the hole to undefined if possible, or deoptimizing otherwise.
@@ -2504,9 +2516,12 @@
     Node* branch =
         graph()->NewNode(common()->Branch(BranchHint::kTrue), check, *control);
 
+    Node* masked_index =
+        graph()->NewNode(simplified()->MaskIndexWithBound(), index, length);
+
     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     Node* vtrue = graph()->NewNode(simplified()->StringCharAt(), receiver,
-                                   index, if_true);
+                                   masked_index, if_true);
 
     Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
     Node* vfalse = jsgraph()->UndefinedConstant();
@@ -2519,9 +2534,12 @@
     index = *effect = graph()->NewNode(simplified()->CheckBounds(), index,
                                        length, *effect, *control);
 
+    Node* masked_index =
+        graph()->NewNode(simplified()->MaskIndexWithBound(), index, length);
+
     // Return the character from the {receiver} as single character string.
-    return graph()->NewNode(simplified()->StringCharAt(), receiver, index,
-                            *control);
+    return graph()->NewNode(simplified()->StringCharAt(), receiver,
+                            masked_index, *control);
   }
 }
 
diff --git a/src/compiler/opcodes.h b/src/compiler/opcodes.h
index 886ea6f..3c3650b 100644
--- a/src/compiler/opcodes.h
+++ b/src/compiler/opcodes.h
@@ -396,6 +396,7 @@
   V(TransitionElementsKind)             \
   V(FindOrderedHashMapEntry)            \
   V(FindOrderedHashMapEntryForInt32Key) \
+  V(MaskIndexWithBound)                 \
   V(RuntimeAbort)
 
 #define SIMPLIFIED_OP_LIST(V)                 \
diff --git a/src/compiler/pipeline.cc b/src/compiler/pipeline.cc
index a47a124..288b2dc 100644
--- a/src/compiler/pipeline.cc
+++ b/src/compiler/pipeline.cc
@@ -1371,8 +1371,12 @@
       //   chains and lower them,
       // - get rid of the region markers,
       // - introduce effect phis and rewire effects to get SSA again.
+      EffectControlLinearizer::MaskArrayIndexEnable mask_array_index =
+          FLAG_mask_array_index ? EffectControlLinearizer::kMaskArrayIndex
+                                : EffectControlLinearizer::kDoNotMaskArrayIndex;
       EffectControlLinearizer linearizer(data->jsgraph(), schedule, temp_zone,
-                                         data->source_positions());
+                                         data->source_positions(),
+                                         mask_array_index);
       linearizer.Run();
     }
     {
diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
index 4699033..9bdb7cf 100644
--- a/src/compiler/simplified-lowering.cc
+++ b/src/compiler/simplified-lowering.cc
@@ -2439,6 +2439,11 @@
         }
         return;
       }
+      case IrOpcode::kMaskIndexWithBound: {
+        VisitBinop(node, UseInfo::TruncatingWord32(),
+                   MachineRepresentation::kWord32);
+        return;
+      }
       case IrOpcode::kCheckHeapObject: {
         if (InputCannotBe(node, Type::SignedSmall())) {
           VisitUnop(node, UseInfo::AnyTagged(),
diff --git a/src/compiler/simplified-operator.cc b/src/compiler/simplified-operator.cc
index f6f889b..04bbc7b 100644
--- a/src/compiler/simplified-operator.cc
+++ b/src/compiler/simplified-operator.cc
@@ -632,7 +632,8 @@
   V(StringEqual, Operator::kCommutative, 2, 0)                   \
   V(StringLessThan, Operator::kNoProperties, 2, 0)               \
   V(StringLessThanOrEqual, Operator::kNoProperties, 2, 0)        \
-  V(ToBoolean, Operator::kNoProperties, 1, 0)
+  V(ToBoolean, Operator::kNoProperties, 1, 0)                    \
+  V(MaskIndexWithBound, Operator::kNoProperties, 2, 0)
 
 #define SPECULATIVE_NUMBER_BINOP_LIST(V)      \
   SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(V) \
diff --git a/src/compiler/simplified-operator.h b/src/compiler/simplified-operator.h
index e394741..0ed46b0 100644
--- a/src/compiler/simplified-operator.h
+++ b/src/compiler/simplified-operator.h
@@ -438,6 +438,7 @@
   const Operator* CheckIf(DeoptimizeReason deoptimize_reason);
   const Operator* CheckBounds();
   const Operator* CheckMaps(CheckMapsFlags, ZoneHandleSet<Map>);
+  const Operator* MaskIndexWithBound();
   const Operator* CompareMaps(ZoneHandleSet<Map>);
   const Operator* MapGuard(ZoneHandleSet<Map> maps);
 
diff --git a/src/compiler/typer.cc b/src/compiler/typer.cc
index 5bd507e..605a96c 100644
--- a/src/compiler/typer.cc
+++ b/src/compiler/typer.cc
@@ -1978,6 +1978,10 @@
 
 Type* Typer::Visitor::TypeStringIndexOf(Node* node) { UNREACHABLE(); }
 
+Type* Typer::Visitor::TypeMaskIndexWithBound(Node* node) {
+  return Type::Union(Operand(node, 0), typer_->cache_.kSingletonZero, zone());
+}
+
 Type* Typer::Visitor::TypeCheckBounds(Node* node) {
   Type* index = Operand(node, 0);
   Type* length = Operand(node, 1);
diff --git a/src/compiler/verifier.cc b/src/compiler/verifier.cc
index bfacb87..e0c40df 100644
--- a/src/compiler/verifier.cc
+++ b/src/compiler/verifier.cc
@@ -1267,6 +1267,11 @@
       CheckValueInputIs(node, 1, Type::Unsigned31());
       CheckTypeIs(node, Type::Unsigned31());
       break;
+    case IrOpcode::kMaskIndexWithBound:
+      CheckValueInputIs(node, 0, Type::Unsigned32());
+      CheckValueInputIs(node, 1, Type::Unsigned31());
+      CheckTypeIs(node, Type::Unsigned32());
+      break;
     case IrOpcode::kCheckHeapObject:
       CheckValueInputIs(node, 0, Type::Any());
       break;
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index 96a1c96..761ba04 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -460,6 +460,10 @@
             "enable crashing features, for testing purposes only")
 DEFINE_BOOL(turbo_rewrite_far_jumps, true,
             "rewrite far to near jumps (ia32,x64)")
+DEFINE_BOOL(extra_masking, false, "Extra mask for memory accesses")
+DEFINE_BOOL(mask_array_index, false, "Mask array index with bound")
+DEFINE_IMPLICATION(future, extra_masking)
+DEFINE_IMPLICATION(extra_masking, mask_array_index)
 
 // Flags to help platform porters
 DEFINE_BOOL(minimal, false,
diff --git a/test/unittests/compiler/effect-control-linearizer-unittest.cc b/test/unittests/compiler/effect-control-linearizer-unittest.cc
index 78a038d..5c6de21 100644
--- a/test/unittests/compiler/effect-control-linearizer-unittest.cc
+++ b/test/unittests/compiler/effect-control-linearizer-unittest.cc
@@ -81,8 +81,9 @@
   schedule.AddReturn(start, ret);
 
   // Run the state effect introducer.
-  EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
-                                     source_positions());
+  EffectControlLinearizer introducer(
+      jsgraph(), &schedule, zone(), source_positions(),
+      EffectControlLinearizer::kDoNotMaskArrayIndex);
   introducer.Run();
 
   EXPECT_THAT(load,
@@ -143,8 +144,9 @@
   schedule.AddReturn(mblock, ret);
 
   // Run the state effect introducer.
-  EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
-                                     source_positions());
+  EffectControlLinearizer introducer(
+      jsgraph(), &schedule, zone(), source_positions(),
+      EffectControlLinearizer::kDoNotMaskArrayIndex);
   introducer.Run();
 
   // The effect input to the return should be an effect phi with the
@@ -210,8 +212,9 @@
   schedule.AddReturn(rblock, ret);
 
   // Run the state effect introducer.
-  EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
-                                     source_positions());
+  EffectControlLinearizer introducer(
+      jsgraph(), &schedule, zone(), source_positions(),
+      EffectControlLinearizer::kDoNotMaskArrayIndex);
   introducer.Run();
 
   ASSERT_THAT(ret, IsReturn(load, load, if_true));
@@ -273,8 +276,9 @@
   schedule.AddNode(mblock, merge);
   schedule.AddNode(mblock, graph()->end());
 
-  EffectControlLinearizer introducer(jsgraph(), &schedule, zone(),
-                                     source_positions());
+  EffectControlLinearizer introducer(
+      jsgraph(), &schedule, zone(), source_positions(),
+      EffectControlLinearizer::kDoNotMaskArrayIndex);
   introducer.Run();
 
   Capture<Node *> branch1_capture, branch2_capture;