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;