Commit d7d7996f authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[turbofan] Extend early lowering to keyed loads.

This extends the existing insertion of soft deopts during early lowering
from named loads to keyed loads as well (i.e. from just {JSLoadName} to
{JSLoadProperty}). Stores will be handled in a follow-up change.

R=bmeurer@chromium.org

Change-Id: I6ad7d0a3561f9160e15e13c64ec5255b4f45e614
Reviewed-on: https://chromium-review.googlesource.com/459421Reviewed-by: 's avatarBenedikt Meurer <bmeurer@chromium.org>
Reviewed-by: 's avatarToon Verwaest <verwaest@chromium.org>
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Cr-Commit-Position: refs/heads/master@{#44187}
parent 6777eecf
......@@ -1061,13 +1061,14 @@ void BytecodeGraphBuilder::VisitLdaNamedProperty() {
Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(1));
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
const Operator* op = javascript()->LoadNamed(name, feedback);
Node* node = nullptr;
if (Node* simplified = TryBuildSimplifiedLoadNamed(feedback.slot())) {
if (Node* simplified =
TryBuildSimplifiedLoadNamed(op, object, feedback.slot())) {
if (environment() == nullptr) return;
node = simplified;
} else {
const Operator* op = javascript()->LoadNamed(name, feedback);
node = NewNode(op, object);
}
......@@ -1081,9 +1082,17 @@ void BytecodeGraphBuilder::VisitLdaKeyedProperty() {
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
const Operator* op = javascript()->LoadProperty(feedback);
Node* node = NewNode(op, object, key);
Node* node = nullptr;
if (Node* simplified =
TryBuildSimplifiedLoadKeyed(op, object, key, feedback.slot())) {
if (environment() == nullptr) return;
node = simplified;
} else {
node = NewNode(op, object, key);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
......@@ -2394,40 +2403,60 @@ Node* BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op,
Reduction early_reduction = type_hint_lowering().ReduceBinaryOperation(
op, left, right, effect, control, slot);
if (early_reduction.Changed()) {
Node* node = early_reduction.replacement();
if (node->op()->EffectOutputCount() > 0) {
environment()->UpdateEffectDependency(node);
}
if (IrOpcode::IsGraphTerminator(node->opcode())) {
MergeControlToLeaveFunction(node);
}
return node;
ApplyEarlyReduction(early_reduction);
return early_reduction.replacement();
}
return nullptr;
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedLoadNamed(FeedbackSlot slot) {
Node* BytecodeGraphBuilder::TryBuildSimplifiedLoadNamed(const Operator* op,
Node* receiver,
FeedbackSlot slot) {
// TODO(mstarzinger,6112): This is a workaround for OSR loop entries being
// pruned from the graph by a soft-deopt. It can happen that a LoadIC that
// control-dominates the OSR entry is still in "uninitialized" state.
if (!osr_ast_id_.IsNone()) return nullptr;
Node* effect = environment()->GetEffectDependency();
Node* control = environment()->GetControlDependency();
Reduction early_reduction =
type_hint_lowering().ReduceLoadNamedOperation(effect, control, slot);
Reduction early_reduction = type_hint_lowering().ReduceLoadNamedOperation(
op, receiver, effect, control, slot);
if (early_reduction.Changed()) {
Node* node = early_reduction.replacement();
if (node->op()->EffectOutputCount() > 0) {
environment()->UpdateEffectDependency(node);
}
if (IrOpcode::IsGraphTerminator(node->opcode())) {
MergeControlToLeaveFunction(node);
}
return node;
ApplyEarlyReduction(early_reduction);
return early_reduction.replacement();
}
return nullptr;
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedLoadKeyed(const Operator* op,
Node* receiver,
Node* key,
FeedbackSlot slot) {
// TODO(mstarzinger,6112): This is a workaround for OSR loop entries being
// pruned from the graph by a soft-deopt. It can happen that a LoadIC that
// control-dominates the OSR entry is still in "uninitialized" state.
if (!osr_ast_id_.IsNone()) return nullptr;
Node* effect = environment()->GetEffectDependency();
Node* control = environment()->GetControlDependency();
Reduction early_reduction = type_hint_lowering().ReduceLoadKeyedOperation(
op, receiver, key, effect, control, slot);
if (early_reduction.Changed()) {
ApplyEarlyReduction(early_reduction);
return early_reduction.replacement();
}
return nullptr;
}
void BytecodeGraphBuilder::ApplyEarlyReduction(Reduction reduction) {
Node* node = reduction.replacement();
DCHECK(node->op()->HasProperty(Operator::kNoWrite));
if (node->op()->EffectOutputCount() > 0) {
environment()->UpdateEffectDependency(node);
}
if (IrOpcode::IsGraphTerminator(node->opcode())) {
MergeControlToLeaveFunction(node);
}
}
Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
if (size > input_buffer_size_) {
size = size + kInputBufferSizeIncrement + input_buffer_size_;
......
......@@ -19,6 +19,7 @@ namespace v8 {
namespace internal {
namespace compiler {
class Reduction;
class SourcePositionTable;
// The BytecodeGraphBuilder produces a high-level IR graph based on
......@@ -179,7 +180,13 @@ class BytecodeGraphBuilder {
// any other invocation of {NewNode} would do.
Node* TryBuildSimplifiedBinaryOp(const Operator* op, Node* left, Node* right,
FeedbackSlot slot);
Node* TryBuildSimplifiedLoadNamed(FeedbackSlot slot);
Node* TryBuildSimplifiedLoadNamed(const Operator* op, Node* receiver,
FeedbackSlot slot);
Node* TryBuildSimplifiedLoadKeyed(const Operator* op, Node* receiver,
Node* key, FeedbackSlot slot);
// Applies the given early reduction onto the current environment.
void ApplyEarlyReduction(Reduction reduction);
// Check the context chain for extensions, for lookup fast paths.
Environment* CheckContextExtensions(uint32_t depth);
......
......@@ -229,20 +229,45 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
}
Reduction JSTypeHintLowering::ReduceLoadNamedOperation(
Node* effect, Node* control, FeedbackSlot slot) const {
const Operator* op, Node* obj, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK_EQ(IrOpcode::kJSLoadNamed, op->opcode());
DCHECK(!slot.IsInvalid());
LoadICNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess)) {
return Reduction(node);
}
return Reduction();
}
Reduction JSTypeHintLowering::ReduceLoadKeyedOperation(
const Operator* op, Node* obj, Node* key, Node* effect, Node* control,
FeedbackSlot slot) const {
DCHECK_EQ(IrOpcode::kJSLoadProperty, op->opcode());
DCHECK(!slot.IsInvalid());
KeyedLoadICNexus nexus(feedback_vector(), slot);
if (Node* node = TryBuildSoftDeopt(
nexus, effect, control,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericKeyedAccess)) {
return Reduction(node);
}
return Reduction();
}
Node* JSTypeHintLowering::TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect,
Node* control,
DeoptimizeReason reason) const {
if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(
DeoptimizeKind::kSoft,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess),
jsgraph()->common()->Deoptimize(DeoptimizeKind::kSoft, reason),
jsgraph()->Dead(), effect, control);
Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
deoptimize->ReplaceInput(0, frame_state);
return Reduction(deoptimize);
return deoptimize;
}
return Reduction();
return nullptr;
}
} // namespace compiler
......
......@@ -7,12 +7,14 @@
#include "src/base/flags.h"
#include "src/compiler/graph-reducer.h"
#include "src/deoptimize-reason.h"
#include "src/handles.h"
namespace v8 {
namespace internal {
// Forward declarations.
class FeedbackNexus;
class FeedbackSlot;
namespace compiler {
......@@ -31,6 +33,13 @@ class Operator;
// the JavaScript-level operators and directly emit simplified-level operators
// even during initial graph building. This is the reason this lowering doesn't
// follow the interface of the reducer framework used after graph construction.
//
// Also note that all reductions returned by this lowering will not produce any
// control-output, but might very well produce an effect-output. The one node
// returned as a replacement must fully describe the effect (i.e. produce the
// effect and carry {Operator::Property} for the entire lowering). Use-sites
// rely on this invariant, if it ever changes we need to switch the interface
// away from using the {Reduction} class.
class JSTypeHintLowering {
public:
// Flags that control the mode of operation.
......@@ -47,11 +56,17 @@ class JSTypeHintLowering {
FeedbackSlot slot) const;
// Potential reduction of property access operations.
Reduction ReduceLoadNamedOperation(Node* effect, Node* control,
Reduction ReduceLoadNamedOperation(const Operator* op, Node* obj,
Node* effect, Node* control,
FeedbackSlot slot) const;
Reduction ReduceLoadKeyedOperation(const Operator* op, Node* obj, Node* key,
Node* effect, Node* control,
FeedbackSlot slot) const;
private:
friend class JSSpeculativeBinopBuilder;
Node* TryBuildSoftDeopt(FeedbackNexus& nexus, Node* effect, Node* control,
DeoptimizeReason reson) const;
JSGraph* jsgraph() const { return jsgraph_; }
Flags flags() const { return flags_; }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment