Commit 22372f5a authored by Michael Starzinger's avatar Michael Starzinger Committed by Commit Bot

[turbofan] Prototype of property access early lowering.

This is a first stab at extending the existing early lowering approach
to property access operations. Currently we only handle the case where
named property loads are lowered to a soft deoptimize operation, due to
insufficient type feedback.

R=jarin@chromium.org

Change-Id: I779ffb99978023237da5ad9eaf0241fe74243882
Reviewed-on: https://chromium-review.googlesource.com/456316
Commit-Queue: Michael Starzinger <mstarzinger@chromium.org>
Reviewed-by: 's avatarJaroslav Sevcik <jarin@chromium.org>
Cr-Commit-Position: refs/heads/master@{#43899}
parent 76abde14
......@@ -6,10 +6,8 @@
#include "src/ast/ast.h"
#include "src/ast/scopes.h"
#include "src/compilation-info.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/js-type-hint-lowering.h"
#include "src/compiler/linkage.h"
#include "src/compiler/operator-properties.h"
#include "src/compiler/simplified-operator.h"
......@@ -466,7 +464,8 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
Zone* local_zone, Handle<SharedFunctionInfo> shared_info,
Handle<FeedbackVector> feedback_vector, BailoutId osr_ast_id,
JSGraph* jsgraph, float invocation_frequency,
SourcePositionTable* source_positions, int inlining_id)
SourcePositionTable* source_positions, int inlining_id,
JSTypeHintLowering::Flags flags)
: local_zone_(local_zone),
jsgraph_(jsgraph),
invocation_frequency_(invocation_frequency),
......@@ -474,6 +473,7 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(
exception_handler_table_(
handle(HandlerTable::cast(bytecode_array()->handler_table()))),
feedback_vector_(feedback_vector),
type_hint_lowering_(jsgraph, feedback_vector, flags),
frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
FrameStateType::kInterpretedFunction,
bytecode_array()->parameter_count(),
......@@ -1064,8 +1064,15 @@ void BytecodeGraphBuilder::VisitLdaNamedProperty() {
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
const Operator* op = javascript()->LoadNamed(name, feedback);
Node* node = NewNode(op, object);
Node* node = nullptr;
if (Node* simplified = TryBuildSimplifiedLoadNamed(feedback.slot())) {
if (environment() == nullptr) return;
node = simplified;
} else {
const Operator* op = javascript()->LoadNamed(name, feedback);
node = NewNode(op, object);
}
environment()->BindAccumulator(node, Environment::kAttachFrameState);
}
......@@ -1621,24 +1628,6 @@ void BytecodeGraphBuilder::VisitReThrow() {
MergeControlToLeaveFunction(control);
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op,
Node* left, Node* right,
FeedbackSlot slot) {
Node* effect = environment()->GetEffectDependency();
Node* control = environment()->GetControlDependency();
JSTypeHintLowering type_hint_lowering(jsgraph(), feedback_vector());
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);
}
return node;
}
return nullptr;
}
void BytecodeGraphBuilder::BuildBinaryOp(const Operator* op) {
PrepareEagerCheckpoint();
Node* left =
......@@ -2392,6 +2381,48 @@ void BytecodeGraphBuilder::BuildJumpIfJSReceiver() {
BuildJumpIf(condition);
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedBinaryOp(const Operator* op,
Node* left, Node* right,
FeedbackSlot slot) {
Node* effect = environment()->GetEffectDependency();
Node* control = environment()->GetControlDependency();
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;
}
return nullptr;
}
Node* BytecodeGraphBuilder::TryBuildSimplifiedLoadNamed(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);
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;
}
return nullptr;
}
Node** BytecodeGraphBuilder::EnsureInputBufferSize(int size) {
if (size > input_buffer_size_) {
size = size + kInputBufferSizeIncrement + input_buffer_size_;
......
......@@ -7,6 +7,7 @@
#include "src/compiler/bytecode-analysis.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/js-type-hint-lowering.h"
#include "src/compiler/liveness-analyzer.h"
#include "src/compiler/state-values-utils.h"
#include "src/interpreter/bytecode-array-iterator.h"
......@@ -24,12 +25,13 @@ class SourcePositionTable;
// interpreter bytecodes.
class BytecodeGraphBuilder {
public:
BytecodeGraphBuilder(Zone* local_zone, Handle<SharedFunctionInfo> shared,
Handle<FeedbackVector> feedback_vector,
BailoutId osr_ast_id, JSGraph* jsgraph,
float invocation_frequency,
SourcePositionTable* source_positions,
int inlining_id = SourcePosition::kNotInlined);
BytecodeGraphBuilder(
Zone* local_zone, Handle<SharedFunctionInfo> shared,
Handle<FeedbackVector> feedback_vector, BailoutId osr_ast_id,
JSGraph* jsgraph, float invocation_frequency,
SourcePositionTable* source_positions,
int inlining_id = SourcePosition::kNotInlined,
JSTypeHintLowering::Flags flags = JSTypeHintLowering::kNoFlags);
// Creates a graph by visiting bytecodes.
bool CreateGraph(bool stack_check = true);
......@@ -181,6 +183,7 @@ class BytecodeGraphBuilder {
// any other invocation of {NewNode} would do.
Node* TryBuildSimplifiedBinaryOp(const Operator* op, Node* left, Node* right,
FeedbackSlot slot);
Node* TryBuildSimplifiedLoadNamed(FeedbackSlot slot);
// Check the context chain for extensions, for lookup fast paths.
Environment* CheckContextExtensions(uint32_t depth);
......@@ -268,6 +271,9 @@ class BytecodeGraphBuilder {
const Handle<FeedbackVector>& feedback_vector() const {
return feedback_vector_;
}
const JSTypeHintLowering& type_hint_lowering() const {
return type_hint_lowering_;
}
const FrameStateFunctionInfo* frame_state_function_info() const {
return frame_state_function_info_;
}
......@@ -304,6 +310,7 @@ class BytecodeGraphBuilder {
Handle<BytecodeArray> bytecode_array_;
Handle<HandlerTable> exception_handler_table_;
Handle<FeedbackVector> feedback_vector_;
const JSTypeHintLowering type_hint_lowering_;
const FrameStateFunctionInfo* frame_state_function_info_;
const interpreter::BytecodeArrayIterator* bytecode_iterator_;
const BytecodeAnalysis* bytecode_analysis_;
......
......@@ -571,9 +571,13 @@ Reduction JSInliner::ReduceJSCall(Node* node) {
{
// Run the BytecodeGraphBuilder to create the subgraph.
Graph::SubgraphScope scope(graph());
JSTypeHintLowering::Flags flags = JSTypeHintLowering::kNoFlags;
if (info_->is_bailout_on_uninitialized()) {
flags |= JSTypeHintLowering::kBailoutOnUninitialized;
}
BytecodeGraphBuilder graph_builder(
parse_info.zone(), shared_info, feedback_vector, BailoutId::None(),
jsgraph(), call.frequency(), source_positions_, inlining_id);
jsgraph(), call.frequency(), source_positions_, inlining_id, flags);
graph_builder.CreateGraph(false);
// Extract the inlinee start/end nodes.
......
......@@ -16,9 +16,9 @@ namespace compiler {
class JSSpeculativeBinopBuilder final {
public:
JSSpeculativeBinopBuilder(JSTypeHintLowering* lowering, const Operator* op,
Node* left, Node* right, Node* effect,
Node* control, FeedbackSlot slot)
JSSpeculativeBinopBuilder(const JSTypeHintLowering* lowering,
const Operator* op, Node* left, Node* right,
Node* effect, Node* control, FeedbackSlot slot)
: lowering_(lowering),
op_(op),
left_(left),
......@@ -172,7 +172,7 @@ class JSSpeculativeBinopBuilder final {
}
private:
JSTypeHintLowering* lowering_;
const JSTypeHintLowering* lowering_;
const Operator* op_;
Node* left_;
Node* right_;
......@@ -182,13 +182,14 @@ class JSSpeculativeBinopBuilder final {
};
JSTypeHintLowering::JSTypeHintLowering(JSGraph* jsgraph,
Handle<FeedbackVector> feedback_vector)
: jsgraph_(jsgraph), feedback_vector_(feedback_vector) {}
Handle<FeedbackVector> feedback_vector,
Flags flags)
: jsgraph_(jsgraph), flags_(flags), feedback_vector_(feedback_vector) {}
Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
Node* left, Node* right,
Node* effect, Node* control,
FeedbackSlot slot) {
FeedbackSlot slot) const {
switch (op->opcode()) {
case IrOpcode::kJSStrictEqual:
break;
......@@ -227,6 +228,23 @@ Reduction JSTypeHintLowering::ReduceBinaryOperation(const Operator* op,
return Reduction();
}
Reduction JSTypeHintLowering::ReduceLoadNamedOperation(
Node* effect, Node* control, FeedbackSlot slot) const {
DCHECK(!slot.IsInvalid());
LoadICNexus nexus(feedback_vector(), slot);
if ((flags() & kBailoutOnUninitialized) && nexus.IsUninitialized()) {
Node* deoptimize = jsgraph()->graph()->NewNode(
jsgraph()->common()->Deoptimize(
DeoptimizeKind::kSoft,
DeoptimizeReason::kInsufficientTypeFeedbackForGenericNamedAccess),
jsgraph()->Dead(), effect, control);
Node* frame_state = NodeProperties::FindFrameStateBefore(deoptimize);
deoptimize->ReplaceInput(0, frame_state);
return Reduction(deoptimize);
}
return Reduction();
}
} // namespace compiler
} // namespace internal
} // namespace v8
......@@ -5,6 +5,7 @@
#ifndef V8_COMPILER_JS_TYPE_HINT_LOWERING_H_
#define V8_COMPILER_JS_TYPE_HINT_LOWERING_H_
#include "src/base/flags.h"
#include "src/compiler/graph-reducer.h"
#include "src/handles.h"
......@@ -21,9 +22,9 @@ class JSGraph;
class Node;
class Operator;
// The type-hint lowering consumes feedback about data operations (i.e. unary
// and binary operations) to emit nodes using speculative simplified operators
// in favor of the generic JavaScript operators.
// The type-hint lowering consumes feedback about high-level operations in order
// to potentially emit nodes using speculative simplified operators in favor of
// the generic JavaScript operators.
//
// This lowering is implemented as an early reduction and can be applied before
// nodes are placed into the initial graph. It provides the ability to shortcut
......@@ -32,23 +33,34 @@ class Operator;
// follow the interface of the reducer framework used after graph construction.
class JSTypeHintLowering {
public:
JSTypeHintLowering(JSGraph* jsgraph, Handle<FeedbackVector> feedback_vector);
// Flags that control the mode of operation.
enum Flag { kNoFlags = 0u, kBailoutOnUninitialized = 1u << 1 };
typedef base::Flags<Flag> Flags;
JSTypeHintLowering(JSGraph* jsgraph, Handle<FeedbackVector> feedback_vector,
Flags flags);
// Potential reduction of binary (arithmetic, logical, shift and relational
// comparison) operations.
Reduction ReduceBinaryOperation(const Operator* op, Node* left, Node* right,
Node* effect, Node* control,
FeedbackSlot slot);
FeedbackSlot slot) const;
// Potential reduction of property access operations.
Reduction ReduceLoadNamedOperation(Node* effect, Node* control,
FeedbackSlot slot) const;
private:
friend class JSSpeculativeBinopBuilder;
JSGraph* jsgraph() const { return jsgraph_; }
Flags flags() const { return flags_; }
const Handle<FeedbackVector>& feedback_vector() const {
return feedback_vector_;
}
JSGraph* jsgraph_;
Flags const flags_;
Handle<FeedbackVector> feedback_vector_;
DISALLOW_COPY_AND_ASSIGN(JSTypeHintLowering);
......
......@@ -778,6 +778,13 @@ class V8_EXPORT_PRIVATE IrOpcode {
return kIfTrue <= value && value <= kIfDefault;
}
// Returns true if opcode terminates control flow in a graph (i.e. respective
// nodes are expected to have control uses by the graphs {End} node only).
static bool IsGraphTerminator(Value value) {
return value == kDeoptimize || value == kReturn || value == kTailCall ||
value == kTerminate || value == kThrow;
}
// Returns true if opcode can be inlined.
static bool IsInlineeOpcode(Value value) {
return value == kJSConstruct || value == kJSCall;
......
......@@ -753,11 +753,15 @@ struct GraphBuilderPhase {
if (data->info()->is_optimizing_from_bytecode()) {
// Bytecode graph builder assumes deoptimziation is enabled.
DCHECK(data->info()->is_deoptimization_enabled());
JSTypeHintLowering::Flags flags = JSTypeHintLowering::kNoFlags;
if (data->info()->is_bailout_on_uninitialized()) {
flags |= JSTypeHintLowering::kBailoutOnUninitialized;
}
BytecodeGraphBuilder graph_builder(
temp_zone, data->info()->shared_info(),
handle(data->info()->closure()->feedback_vector()),
data->info()->osr_ast_id(), data->jsgraph(), 1.0f,
data->source_positions());
data->source_positions(), SourcePosition::kNotInlined, flags);
succeeded = graph_builder.CreateGraph();
} else {
AstGraphBuilderWithPositions graph_builder(
......
......@@ -208,6 +208,10 @@ void Verifier::Visitor::Check(Node* node) {
CHECK(node->op()->ValueOutputCount() == 0);
CHECK(node->op()->EffectOutputCount() == 0);
CHECK(node->op()->ControlOutputCount() == 0);
// All inputs are graph terminators.
for (const Node* input : node->inputs()) {
CHECK(IrOpcode::IsGraphTerminator(input->opcode()));
}
// Type is empty.
CheckNotTyped(node);
break;
......
......@@ -465,7 +465,7 @@ class WasmFunctionWrapper : private GraphAndBuilders {
common()->Return(), zero,
graph()->NewNode(common()->Int32Constant(WASM_WRAPPER_RETURN_VALUE)),
effect, graph()->start());
graph()->SetEnd(graph()->NewNode(common()->End(2), r, graph()->start()));
graph()->SetEnd(graph()->NewNode(common()->End(1), r));
}
template <typename ReturnType, typename... ParamTypes>
......
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