Commit 32211800 authored by rmcilroy's avatar rmcilroy Committed by Commit bot

[Interpreter] Generate valid FrameStates in the Bytecode Graph Builder.

Adds FrameState nodes to graphs built by the Bytecode Graph Builder, in
preparation for adding deopt support. Also adds a new
FrameStateType::kInterpretedFunction to allow for specialized deopt
stack translation for interpreted frames. Finally adds support for
disabling typed lowering of binary ops, since the current approach
relies on a FrameState hack which does not apply to interpreted frames

BUG=v8:4280
LOG=N

Review URL: https://codereview.chromium.org/1514413002

Cr-Commit-Position: refs/heads/master@{#32964}
parent 6dd99f19
This diff is collapsed.
...@@ -28,7 +28,13 @@ class BytecodeGraphBuilder { ...@@ -28,7 +28,13 @@ class BytecodeGraphBuilder {
Graph* graph() const { return jsgraph_->graph(); } Graph* graph() const { return jsgraph_->graph(); }
private: private:
enum class AccumulatorUpdateMode {
kOutputIgnored,
kOutputInAccumulator,
};
class Environment; class Environment;
class FrameStateBeforeAndAfter;
void CreateGraphBody(bool stack_check); void CreateGraphBody(bool stack_check);
void VisitBytecodes(); void VisitBytecodes();
...@@ -58,9 +64,6 @@ class BytecodeGraphBuilder { ...@@ -58,9 +64,6 @@ class BytecodeGraphBuilder {
// a feedback slot. // a feedback slot.
VectorSlotPair CreateVectorSlotPair(int slot_id); VectorSlotPair CreateVectorSlotPair(int slot_id);
// Replaces the frame state inputs with empty frame states.
void AddEmptyFrameStateInputs(Node* node);
void set_environment(Environment* env) { environment_ = env; } void set_environment(Environment* env) { environment_ = env; }
const Environment* environment() const { return environment_; } const Environment* environment() const { return environment_; }
Environment* environment() { return environment_; } Environment* environment() { return environment_; }
...@@ -127,7 +130,8 @@ class BytecodeGraphBuilder { ...@@ -127,7 +130,8 @@ class BytecodeGraphBuilder {
interpreter::Register first_arg, interpreter::Register first_arg,
size_t arity); size_t arity);
void BuildCreateLiteral(const Operator* op); void BuildCreateLiteral(const Operator* op,
const interpreter::BytecodeArrayIterator& iterator);
void BuildCreateRegExpLiteral( void BuildCreateRegExpLiteral(
const interpreter::BytecodeArrayIterator& iterator); const interpreter::BytecodeArrayIterator& iterator);
void BuildCreateArrayLiteral( void BuildCreateArrayLiteral(
...@@ -179,6 +183,9 @@ class BytecodeGraphBuilder { ...@@ -179,6 +183,9 @@ class BytecodeGraphBuilder {
const Handle<BytecodeArray>& bytecode_array() const { const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_; return bytecode_array_;
} }
const FrameStateFunctionInfo* frame_state_function_info() const {
return frame_state_function_info_;
}
LanguageMode language_mode() const { LanguageMode language_mode() const {
// TODO(mythria): Don't rely on parse information to get language mode. // TODO(mythria): Don't rely on parse information to get language mode.
...@@ -211,10 +218,12 @@ class BytecodeGraphBuilder { ...@@ -211,10 +218,12 @@ class BytecodeGraphBuilder {
CompilationInfo* info_; CompilationInfo* info_;
JSGraph* jsgraph_; JSGraph* jsgraph_;
Handle<BytecodeArray> bytecode_array_; Handle<BytecodeArray> bytecode_array_;
const FrameStateFunctionInfo* frame_state_function_info_;
const interpreter::BytecodeArrayIterator* bytecode_iterator_; const interpreter::BytecodeArrayIterator* bytecode_iterator_;
const BytecodeBranchAnalysis* branch_analysis_; const BytecodeBranchAnalysis* branch_analysis_;
Environment* environment_; Environment* environment_;
// Merge environments are snapshots of the environment at a particular // Merge environments are snapshots of the environment at a particular
// bytecode offset to be merged into a later environment. // bytecode offset to be merged into a later environment.
ZoneMap<int, Environment*> merge_environments_; ZoneMap<int, Environment*> merge_environments_;
...@@ -253,9 +262,11 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { ...@@ -253,9 +262,11 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
void BindRegister(interpreter::Register the_register, Node* node); void BindRegister(interpreter::Register the_register, Node* node);
Node* LookupRegister(interpreter::Register the_register) const; Node* LookupRegister(interpreter::Register the_register) const;
void BindAccumulator(Node* node); void BindAccumulator(Node* node, FrameStateBeforeAndAfter* states = nullptr);
Node* LookupAccumulator() const; Node* LookupAccumulator() const;
void RecordAfterState(Node* node, FrameStateBeforeAndAfter* states);
bool IsMarkedAsUnreachable() const; bool IsMarkedAsUnreachable() const;
void MarkAsUnreachable(); void MarkAsUnreachable();
...@@ -265,6 +276,15 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { ...@@ -265,6 +276,15 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
effect_dependency_ = dependency; effect_dependency_ = dependency;
} }
// Preserve a checkpoint of the environment for the IR graph. Any
// further mutation of the environment will not affect checkpoints.
Node* Checkpoint(BailoutId ast_id, AccumulatorUpdateMode update_mode);
// Returns true if the state values are up to date with the current
// environment. If update_mode is AccumulatorUpdateMode::kOutputInAccumulator
// then accumulator state can be different from the environment.
bool StateValuesAreUpToDate(AccumulatorUpdateMode update_mode);
// Control dependency tracked by this environment. // Control dependency tracked by this environment.
Node* GetControlDependency() const { return control_dependency_; } Node* GetControlDependency() const { return control_dependency_; }
void UpdateControlDependency(Node* dependency) { void UpdateControlDependency(Node* dependency) {
...@@ -281,26 +301,32 @@ class BytecodeGraphBuilder::Environment : public ZoneObject { ...@@ -281,26 +301,32 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
private: private:
explicit Environment(const Environment* copy); explicit Environment(const Environment* copy);
void PrepareForLoop(); void PrepareForLoop();
bool StateValuesRequireUpdate(Node** state_values, int offset, int count);
void UpdateStateValues(Node** state_values, int offset, int count);
int RegisterToValuesIndex(interpreter::Register the_register) const; int RegisterToValuesIndex(interpreter::Register the_register) const;
Zone* zone() const { return builder_->local_zone(); } Zone* zone() const { return builder_->local_zone(); }
Graph* graph() const { return builder_->graph(); } Graph* graph() const { return builder_->graph(); }
CommonOperatorBuilder* common() const { return builder_->common(); } CommonOperatorBuilder* common() const { return builder_->common(); }
BytecodeGraphBuilder* builder() const { return builder_; } BytecodeGraphBuilder* builder() const { return builder_; }
const NodeVector* values() const { return &values_; } const NodeVector* values() const { return &values_; }
NodeVector* values() { return &values_; } NodeVector* values() { return &values_; }
Node* accumulator() { return accumulator_; }
int register_base() const { return register_base_; } int register_base() const { return register_base_; }
int accumulator_base() const { return accumulator_base_; }
BytecodeGraphBuilder* builder_; BytecodeGraphBuilder* builder_;
int register_count_; int register_count_;
int parameter_count_; int parameter_count_;
Node* accumulator_;
Node* context_; Node* context_;
Node* control_dependency_; Node* control_dependency_;
Node* effect_dependency_; Node* effect_dependency_;
NodeVector values_; NodeVector values_;
Node* parameters_state_values_;
Node* registers_state_values_;
Node* accumulator_state_values_;
int register_base_; int register_base_;
int accumulator_base_;
}; };
} // namespace compiler } // namespace compiler
......
...@@ -558,6 +558,9 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor( ...@@ -558,6 +558,9 @@ void CodeGenerator::BuildTranslationForFrameStateDescriptor(
static_cast<unsigned int>(descriptor->GetSize(state_combine) - static_cast<unsigned int>(descriptor->GetSize(state_combine) -
(1 + descriptor->parameters_count()))); (1 + descriptor->parameters_count())));
break; break;
case FrameStateType::kInterpretedFunction:
// TODO(rmcilroy): Implement interpreted function translation.
break;
case FrameStateType::kArgumentsAdaptor: case FrameStateType::kArgumentsAdaptor:
translation->BeginArgumentsAdaptorFrame( translation->BeginArgumentsAdaptorFrame(
shared_info_id, shared_info_id,
......
...@@ -51,6 +51,9 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) { ...@@ -51,6 +51,9 @@ std::ostream& operator<<(std::ostream& os, FrameStateType type) {
case FrameStateType::kJavaScriptFunction: case FrameStateType::kJavaScriptFunction:
os << "JS_FRAME"; os << "JS_FRAME";
break; break;
case FrameStateType::kInterpretedFunction:
os << "INTERPRETED_FRAME";
break;
case FrameStateType::kArgumentsAdaptor: case FrameStateType::kArgumentsAdaptor:
os << "ARGUMENTS_ADAPTOR"; os << "ARGUMENTS_ADAPTOR";
break; break;
......
...@@ -76,9 +76,10 @@ class OutputFrameStateCombine { ...@@ -76,9 +76,10 @@ class OutputFrameStateCombine {
// The type of stack frame that a FrameState node represents. // The type of stack frame that a FrameState node represents.
enum class FrameStateType { enum class FrameStateType {
kJavaScriptFunction, // Represents an unoptimized JavaScriptFrame. kJavaScriptFunction, // Represents an unoptimized JavaScriptFrame.
kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame. kInterpretedFunction, // Represents an InterpretedFrame.
kConstructStub // Represents a ConstructStubFrame. kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame.
kConstructStub // Represents a ConstructStubFrame.
}; };
...@@ -108,6 +109,11 @@ class FrameStateFunctionInfo { ...@@ -108,6 +109,11 @@ class FrameStateFunctionInfo {
return context_calling_mode_; return context_calling_mode_;
} }
static bool IsJSFunctionType(FrameStateType type) {
return type == FrameStateType::kJavaScriptFunction ||
type == FrameStateType::kInterpretedFunction;
}
private: private:
FrameStateType const type_; FrameStateType const type_;
int const parameter_count_; int const parameter_count_;
......
...@@ -867,7 +867,7 @@ size_t FrameStateDescriptor::GetJSFrameCount() const { ...@@ -867,7 +867,7 @@ size_t FrameStateDescriptor::GetJSFrameCount() const {
size_t count = 0; size_t count = 0;
for (const FrameStateDescriptor* iter = this; iter != NULL; for (const FrameStateDescriptor* iter = this; iter != NULL;
iter = iter->outer_state_) { iter = iter->outer_state_) {
if (iter->type_ == FrameStateType::kJavaScriptFunction) { if (FrameStateFunctionInfo::IsJSFunctionType(iter->type_)) {
++count; ++count;
} }
} }
......
...@@ -954,7 +954,7 @@ class FrameStateDescriptor : public ZoneObject { ...@@ -954,7 +954,7 @@ class FrameStateDescriptor : public ZoneObject {
MaybeHandle<SharedFunctionInfo> shared_info() const { return shared_info_; } MaybeHandle<SharedFunctionInfo> shared_info() const { return shared_info_; }
FrameStateDescriptor* outer_state() const { return outer_state_; } FrameStateDescriptor* outer_state() const { return outer_state_; }
bool HasContext() const { bool HasContext() const {
return type_ == FrameStateType::kJavaScriptFunction; return FrameStateFunctionInfo::IsJSFunctionType(type_);
} }
size_t GetSize(OutputFrameStateCombine combine = size_t GetSize(OutputFrameStateCombine combine =
......
...@@ -450,6 +450,8 @@ JSTypedLowering::JSTypedLowering(Editor* editor, ...@@ -450,6 +450,8 @@ JSTypedLowering::JSTypedLowering(Editor* editor,
Reduction JSTypedLowering::ReduceJSAdd(Node* node) { Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
// JSAdd(x:number, y:number) => NumberAdd(x, y) // JSAdd(x:number, y:number) => NumberAdd(x, y)
...@@ -480,6 +482,8 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) { ...@@ -480,6 +482,8 @@ Reduction JSTypedLowering::ReduceJSAdd(Node* node) {
Reduction JSTypedLowering::ReduceJSModulus(Node* node) { Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
// JSModulus(x:number, x:number) => NumberModulus(x, y) // JSModulus(x:number, x:number) => NumberModulus(x, y)
...@@ -492,6 +496,8 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) { ...@@ -492,6 +496,8 @@ Reduction JSTypedLowering::ReduceJSModulus(Node* node) {
Reduction JSTypedLowering::ReduceNumberBinop(Node* node, Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
const Operator* numberOp) { const Operator* numberOp) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.IsStrong() || numberOp == simplified()->NumberModulus()) { if (r.IsStrong() || numberOp == simplified()->NumberModulus()) {
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
...@@ -506,6 +512,8 @@ Reduction JSTypedLowering::ReduceNumberBinop(Node* node, ...@@ -506,6 +512,8 @@ Reduction JSTypedLowering::ReduceNumberBinop(Node* node,
Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.IsStrong()) { if (r.IsStrong()) {
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
...@@ -524,6 +532,8 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) { ...@@ -524,6 +532,8 @@ Reduction JSTypedLowering::ReduceInt32Binop(Node* node, const Operator* intOp) {
Reduction JSTypedLowering::ReduceUI32Shift(Node* node, Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
Signedness left_signedness, Signedness left_signedness,
const Operator* shift_op) { const Operator* shift_op) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.IsStrong()) { if (r.IsStrong()) {
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
...@@ -540,6 +550,8 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node, ...@@ -540,6 +550,8 @@ Reduction JSTypedLowering::ReduceUI32Shift(Node* node,
Reduction JSTypedLowering::ReduceJSComparison(Node* node) { Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::String())) { if (r.BothInputsAre(Type::String())) {
// If both inputs are definitely strings, perform a string comparison. // If both inputs are definitely strings, perform a string comparison.
...@@ -611,6 +623,8 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) { ...@@ -611,6 +623,8 @@ Reduction JSTypedLowering::ReduceJSComparison(Node* node) {
Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.BothInputsAre(Type::Number())) { if (r.BothInputsAre(Type::Number())) {
...@@ -652,6 +666,8 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) { ...@@ -652,6 +666,8 @@ Reduction JSTypedLowering::ReduceJSEqual(Node* node, bool invert) {
Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) { Reduction JSTypedLowering::ReduceJSStrictEqual(Node* node, bool invert) {
if (flags() & kDisableBinaryOpReduction) return NoChange();
JSBinopReduction r(this, node); JSBinopReduction r(this, node);
if (r.left() == r.right()) { if (r.left() == r.right()) {
// x === x is always true if x != NaN // x === x is always true if x != NaN
...@@ -1104,7 +1120,10 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) { ...@@ -1104,7 +1120,10 @@ Reduction JSTypedLowering::ReduceJSInstanceOf(Node* node) {
Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0); Node* const frame_state = NodeProperties::GetFrameStateInput(node, 0);
// If deoptimization is disabled, we cannot optimize. // If deoptimization is disabled, we cannot optimize.
if (!(flags() & kDeoptimizationEnabled)) return NoChange(); if (!(flags() & kDeoptimizationEnabled) ||
(flags() & kDisableBinaryOpReduction)) {
return NoChange();
}
// If we are in a try block, don't optimize since the runtime call // If we are in a try block, don't optimize since the runtime call
// in the proxy case can throw. // in the proxy case can throw.
......
...@@ -35,6 +35,7 @@ class JSTypedLowering final : public AdvancedReducer { ...@@ -35,6 +35,7 @@ class JSTypedLowering final : public AdvancedReducer {
enum Flag { enum Flag {
kNoFlags = 0u, kNoFlags = 0u,
kDeoptimizationEnabled = 1u << 0, kDeoptimizationEnabled = 1u << 0,
kDisableBinaryOpReduction = 1u << 1,
}; };
typedef base::Flags<Flag> Flags; typedef base::Flags<Flag> Flags;
......
...@@ -609,11 +609,16 @@ struct TypedLoweringPhase { ...@@ -609,11 +609,16 @@ struct TypedLoweringPhase {
data->common()); data->common());
LoadElimination load_elimination(&graph_reducer); LoadElimination load_elimination(&graph_reducer);
JSBuiltinReducer builtin_reducer(&graph_reducer, data->jsgraph()); JSBuiltinReducer builtin_reducer(&graph_reducer, data->jsgraph());
JSTypedLowering::Flags typed_lowering_flags = JSTypedLowering::kNoFlags;
if (data->info()->is_deoptimization_enabled()) {
typed_lowering_flags |= JSTypedLowering::kDeoptimizationEnabled;
}
if (data->info()->shared_info()->HasBytecodeArray()) {
typed_lowering_flags |= JSTypedLowering::kDisableBinaryOpReduction;
}
JSTypedLowering typed_lowering(&graph_reducer, data->info()->dependencies(), JSTypedLowering typed_lowering(&graph_reducer, data->info()->dependencies(),
data->info()->is_deoptimization_enabled() typed_lowering_flags, data->jsgraph(),
? JSTypedLowering::kDeoptimizationEnabled temp_zone);
: JSTypedLowering::kNoFlags,
data->jsgraph(), temp_zone);
JSIntrinsicLowering intrinsic_lowering( JSIntrinsicLowering intrinsic_lowering(
&graph_reducer, data->jsgraph(), &graph_reducer, data->jsgraph(),
data->info()->is_deoptimization_enabled() data->info()->is_deoptimization_enabled()
......
...@@ -32,6 +32,11 @@ Bytecode BytecodeArrayIterator::current_bytecode() const { ...@@ -32,6 +32,11 @@ Bytecode BytecodeArrayIterator::current_bytecode() const {
} }
int BytecodeArrayIterator::current_bytecode_size() const {
return Bytecodes::Size(current_bytecode());
}
uint32_t BytecodeArrayIterator::GetRawOperand(int operand_index, uint32_t BytecodeArrayIterator::GetRawOperand(int operand_index,
OperandType operand_type) const { OperandType operand_type) const {
DCHECK_GE(operand_index, 0); DCHECK_GE(operand_index, 0);
......
...@@ -20,6 +20,7 @@ class BytecodeArrayIterator { ...@@ -20,6 +20,7 @@ class BytecodeArrayIterator {
void Advance(); void Advance();
bool done() const; bool done() const;
Bytecode current_bytecode() const; Bytecode current_bytecode() const;
int current_bytecode_size() const;
int current_offset() const { return bytecode_offset_; } int current_offset() const { return bytecode_offset_; }
const Handle<BytecodeArray>& bytecode_array() const { const Handle<BytecodeArray>& bytecode_array() const {
return bytecode_array_; return bytecode_array_;
......
...@@ -122,6 +122,7 @@ class BytecodeGraphTester { ...@@ -122,6 +122,7 @@ class BytecodeGraphTester {
CompilationInfo compilation_info(&parse_info); CompilationInfo compilation_info(&parse_info);
compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>()); compilation_info.SetOptimizing(BailoutId::None(), Handle<Code>());
compilation_info.MarkAsDeoptimizationEnabled();
// TODO(mythria): Remove this step once parse_info is not needed. // TODO(mythria): Remove this step once parse_info is not needed.
CHECK(Compiler::ParseAndAnalyze(&parse_info)); CHECK(Compiler::ParseAndAnalyze(&parse_info));
compiler::Pipeline pipeline(&compilation_info); compiler::Pipeline pipeline(&compilation_info);
......
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