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