[turbofan] Allow array grow to disable speculation
Add feedback to GrowFastElements operator and thread it through to the deoptimize node it the lowering. The CL uses the feedback to allow Array.push to disable speculation if the grow operation deopts. Bug: v8:7127, v8:7204 Change-Id: Ib5850a93759b9194c0fc2f191f6adf5d49cb7f55 Reviewed-on: https://chromium-review.googlesource.com/827128 Reviewed-by: Benedikt Meurer <bmeurer@chromium.org> Commit-Queue: Sigurd Schneider <sigurds@chromium.org> Cr-Commit-Position: refs/heads/master@{#50145}
This commit is contained in:
parent
fb8efb12fa
commit
ffe7919f12
@ -3229,7 +3229,7 @@ Node* EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node) {
|
||||
|
||||
Node* EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node,
|
||||
Node* frame_state) {
|
||||
GrowFastElementsMode mode = GrowFastElementsModeOf(node->op());
|
||||
GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op());
|
||||
Node* object = node->InputAt(0);
|
||||
Node* elements = node->InputAt(1);
|
||||
Node* index = node->InputAt(2);
|
||||
@ -3248,7 +3248,7 @@ Node* EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node,
|
||||
// We need to grow the {elements} for {object}.
|
||||
Operator::Properties properties = Operator::kEliminatable;
|
||||
Callable callable =
|
||||
(mode == GrowFastElementsMode::kDoubleElements)
|
||||
(params.mode() == GrowFastElementsMode::kDoubleElements)
|
||||
? Builtins::CallableFor(isolate(), Builtins::kGrowFastDoubleElements)
|
||||
: Builtins::CallableFor(isolate(),
|
||||
Builtins::kGrowFastSmiOrObjectElements);
|
||||
@ -3262,7 +3262,7 @@ Node* EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node,
|
||||
// Ensure that we were able to grow the {elements}.
|
||||
// TODO(turbofan): We use kSmi as reason here similar to Crankshaft,
|
||||
// but maybe we should just introduce a reason that makes sense.
|
||||
__ DeoptimizeIf(DeoptimizeReason::kSmi, VectorSlotPair(),
|
||||
__ DeoptimizeIf(DeoptimizeReason::kSmi, params.feedback(),
|
||||
ObjectIsSmi(new_elements), frame_state);
|
||||
__ Goto(&done, new_elements);
|
||||
|
||||
|
@ -1085,7 +1085,8 @@ Reduction JSBuiltinReducer::ReduceArrayPush(Node* node) {
|
||||
? GrowFastElementsMode::kDoubleElements
|
||||
: GrowFastElementsMode::kSmiOrObjectElements;
|
||||
elements = effect = graph()->NewNode(
|
||||
simplified()->MaybeGrowFastElements(mode), receiver, elements,
|
||||
simplified()->MaybeGrowFastElements(mode, p.feedback()), receiver,
|
||||
elements,
|
||||
graph()->NewNode(simplified()->NumberAdd(), length,
|
||||
jsgraph()->Constant(num_values - 1)),
|
||||
elements_length, effect, control);
|
||||
|
@ -1636,9 +1636,9 @@ Node* JSCallReducer::DoFilterPostCallbackWork(ElementsKind kind, Node** control,
|
||||
GrowFastElementsMode mode =
|
||||
IsDoubleElementsKind(kind) ? GrowFastElementsMode::kDoubleElements
|
||||
: GrowFastElementsMode::kSmiOrObjectElements;
|
||||
elements = etrue =
|
||||
graph()->NewNode(simplified()->MaybeGrowFastElements(mode), a, elements,
|
||||
checked_to, elements_length, etrue, if_true);
|
||||
elements = etrue = graph()->NewNode(
|
||||
simplified()->MaybeGrowFastElements(mode, VectorSlotPair()), a,
|
||||
elements, checked_to, elements_length, etrue, if_true);
|
||||
|
||||
// Update the length of {a}.
|
||||
Node* new_length_a = graph()->NewNode(simplified()->NumberAdd(), checked_to,
|
||||
|
@ -2444,8 +2444,8 @@ JSNativeContextSpecialization::BuildElementAccess(
|
||||
? GrowFastElementsMode::kDoubleElements
|
||||
: GrowFastElementsMode::kSmiOrObjectElements;
|
||||
elements = effect = graph()->NewNode(
|
||||
simplified()->MaybeGrowFastElements(mode), receiver, elements,
|
||||
index, elements_length, effect, control);
|
||||
simplified()->MaybeGrowFastElements(mode, VectorSlotPair()),
|
||||
receiver, elements, index, elements_length, effect, control);
|
||||
|
||||
// Also update the "length" property if {receiver} is a JSArray.
|
||||
if (receiver_is_jsarray) {
|
||||
|
@ -811,12 +811,12 @@ Reduction LoadElimination::ReduceEnsureWritableFastElements(Node* node) {
|
||||
}
|
||||
|
||||
Reduction LoadElimination::ReduceMaybeGrowFastElements(Node* node) {
|
||||
GrowFastElementsMode mode = GrowFastElementsModeOf(node->op());
|
||||
GrowFastElementsParameters params = GrowFastElementsParametersOf(node->op());
|
||||
Node* const object = NodeProperties::GetValueInput(node, 0);
|
||||
Node* const effect = NodeProperties::GetEffectInput(node);
|
||||
AbstractState const* state = node_states_.Get(effect);
|
||||
if (state == nullptr) return NoChange();
|
||||
if (mode == GrowFastElementsMode::kDoubleElements) {
|
||||
if (params.mode() == GrowFastElementsMode::kDoubleElements) {
|
||||
// We know that the resulting elements have the fixed double array map.
|
||||
state = state->SetMaps(
|
||||
node, ZoneHandleSet<Map>(factory()->fixed_double_array_map()), zone());
|
||||
|
@ -292,9 +292,28 @@ std::ostream& operator<<(std::ostream& os, GrowFastElementsMode mode) {
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
||||
GrowFastElementsMode GrowFastElementsModeOf(const Operator* op) {
|
||||
bool operator==(const GrowFastElementsParameters& lhs,
|
||||
const GrowFastElementsParameters& rhs) {
|
||||
return lhs.mode() == rhs.mode() && lhs.feedback() == rhs.feedback();
|
||||
}
|
||||
|
||||
inline size_t hash_value(const GrowFastElementsParameters& params) {
|
||||
return base::hash_combine(params.mode(), params.feedback());
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream& os,
|
||||
const GrowFastElementsParameters& params) {
|
||||
os << params.mode();
|
||||
if (params.feedback().IsValid()) {
|
||||
os << params.feedback();
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
const GrowFastElementsParameters& GrowFastElementsParametersOf(
|
||||
const Operator* op) {
|
||||
DCHECK_EQ(IrOpcode::kMaybeGrowFastElements, op->opcode());
|
||||
return OpParameter<GrowFastElementsMode>(op);
|
||||
return OpParameter<GrowFastElementsParameters>(op);
|
||||
}
|
||||
|
||||
bool operator==(ElementsTransition const& lhs, ElementsTransition const& rhs) {
|
||||
@ -903,6 +922,20 @@ struct SimplifiedOperatorGlobalCache final {
|
||||
};
|
||||
EnsureWritableFastElementsOperator kEnsureWritableFastElements;
|
||||
|
||||
template <GrowFastElementsMode kMode>
|
||||
struct GrowFastElementsOperator final
|
||||
: public Operator1<GrowFastElementsParameters> {
|
||||
GrowFastElementsOperator()
|
||||
: Operator1(IrOpcode::kMaybeGrowFastElements, Operator::kNoThrow,
|
||||
"MaybeGrowFastElements", 4, 1, 1, 1, 1, 0,
|
||||
GrowFastElementsParameters(kMode, VectorSlotPair())) {}
|
||||
};
|
||||
|
||||
GrowFastElementsOperator<GrowFastElementsMode::kDoubleElements>
|
||||
kGrowFastElementsOperatorDoubleElements;
|
||||
GrowFastElementsOperator<GrowFastElementsMode::kSmiOrObjectElements>
|
||||
kGrowFastElementsOperatorSmiOrObjectElements;
|
||||
|
||||
struct LoadFieldByIndexOperator final : public Operator {
|
||||
LoadFieldByIndexOperator()
|
||||
: Operator( // --
|
||||
@ -1148,13 +1181,21 @@ const Operator* SimplifiedOperatorBuilder::EnsureWritableFastElements() {
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::MaybeGrowFastElements(
|
||||
GrowFastElementsMode mode) {
|
||||
return new (zone()) Operator1<GrowFastElementsMode>( // --
|
||||
IrOpcode::kMaybeGrowFastElements, // opcode
|
||||
Operator::kNoThrow, // flags
|
||||
"MaybeGrowFastElements", // name
|
||||
4, 1, 1, 1, 1, 0, // counts
|
||||
mode); // parameter
|
||||
GrowFastElementsMode mode, const VectorSlotPair& feedback) {
|
||||
if (!feedback.IsValid()) {
|
||||
switch (mode) {
|
||||
case GrowFastElementsMode::kDoubleElements:
|
||||
return &cache_.kGrowFastElementsOperatorDoubleElements;
|
||||
case GrowFastElementsMode::kSmiOrObjectElements:
|
||||
return &cache_.kGrowFastElementsOperatorSmiOrObjectElements;
|
||||
}
|
||||
}
|
||||
return new (zone()) Operator1<GrowFastElementsParameters>( // --
|
||||
IrOpcode::kMaybeGrowFastElements, // opcode
|
||||
Operator::kNoThrow, // flags
|
||||
"MaybeGrowFastElements", // name
|
||||
4, 1, 1, 1, 1, 0, // counts
|
||||
GrowFastElementsParameters(mode, feedback)); // parameter
|
||||
}
|
||||
|
||||
const Operator* SimplifiedOperatorBuilder::TransitionElementsKind(
|
||||
|
@ -225,7 +225,29 @@ inline size_t hash_value(GrowFastElementsMode mode) {
|
||||
|
||||
std::ostream& operator<<(std::ostream&, GrowFastElementsMode);
|
||||
|
||||
GrowFastElementsMode GrowFastElementsModeOf(const Operator*) WARN_UNUSED_RESULT;
|
||||
class GrowFastElementsParameters {
|
||||
public:
|
||||
GrowFastElementsParameters(GrowFastElementsMode mode,
|
||||
const VectorSlotPair& feedback)
|
||||
: mode_(mode), feedback_(feedback) {}
|
||||
|
||||
GrowFastElementsMode mode() const { return mode_; }
|
||||
const VectorSlotPair& feedback() const { return feedback_; }
|
||||
|
||||
private:
|
||||
GrowFastElementsMode mode_;
|
||||
VectorSlotPair feedback_;
|
||||
};
|
||||
|
||||
bool operator==(const GrowFastElementsParameters&,
|
||||
const GrowFastElementsParameters&);
|
||||
|
||||
inline size_t hash_value(const GrowFastElementsParameters&);
|
||||
|
||||
std::ostream& operator<<(std::ostream&, const GrowFastElementsParameters&);
|
||||
|
||||
const GrowFastElementsParameters& GrowFastElementsParametersOf(const Operator*)
|
||||
WARN_UNUSED_RESULT;
|
||||
|
||||
// A descriptor for elements kind transitions.
|
||||
class ElementsTransition final {
|
||||
@ -542,7 +564,8 @@ class V8_EXPORT_PRIVATE SimplifiedOperatorBuilder final
|
||||
const Operator* EnsureWritableFastElements();
|
||||
|
||||
// maybe-grow-fast-elements object, elements, index, length
|
||||
const Operator* MaybeGrowFastElements(GrowFastElementsMode mode);
|
||||
const Operator* MaybeGrowFastElements(GrowFastElementsMode mode,
|
||||
const VectorSlotPair& feedback);
|
||||
|
||||
// transition-elements-kind object, from-map, to-map
|
||||
const Operator* TransitionElementsKind(ElementsTransition transition);
|
||||
|
@ -41,3 +41,34 @@
|
||||
foo([0.34234]);
|
||||
assertOptimized(foo);
|
||||
})();
|
||||
|
||||
(function test() {
|
||||
const N = 128 * 1024;
|
||||
|
||||
function foo(a) { a.push(1); }
|
||||
|
||||
foo(new Array(N));
|
||||
foo(new Array(N));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(new Array(N));
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(new Array(N));
|
||||
assertOptimized(foo);
|
||||
})();
|
||||
|
||||
(function test() {
|
||||
function mkArray() {
|
||||
const N = 128 * 1024;
|
||||
let a = [0.1];
|
||||
a.length = N;
|
||||
return a;
|
||||
}
|
||||
function foo(a) { a.push(0.23441233123); }
|
||||
foo(mkArray());
|
||||
foo(mkArray());
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(mkArray());
|
||||
%OptimizeFunctionOnNextCall(foo);
|
||||
foo(mkArray());
|
||||
assertOptimized(foo);
|
||||
})();
|
||||
|
Loading…
Reference in New Issue
Block a user