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
......@@ -13,8 +13,55 @@ namespace v8 {
namespace internal {
namespace compiler {
// Helper for generating frame states for before and after a bytecode.
class BytecodeGraphBuilder::FrameStateBeforeAndAfter {
public:
FrameStateBeforeAndAfter(BytecodeGraphBuilder* builder,
const interpreter::BytecodeArrayIterator& iterator)
: builder_(builder), id_after_(BailoutId::None()) {
BailoutId id_before(iterator.current_offset());
frame_state_before_ = builder_->environment()->Checkpoint(
id_before, AccumulatorUpdateMode::kOutputIgnored);
id_after_ = BailoutId(id_before.ToInt() + iterator.current_bytecode_size());
}
~FrameStateBeforeAndAfter() {
DCHECK(builder_->environment()->StateValuesAreUpToDate(
accumulator_update_mode_));
}
private:
friend class Environment;
void AddToNode(Node* node, AccumulatorUpdateMode update_mode) {
int count = OperatorProperties::GetFrameStateInputCount(node->op());
DCHECK_LE(count, 2);
if (count >= 1) {
// Add the frame state for after the operation.
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node, 0)->opcode());
Node* frame_state_after =
builder_->environment()->Checkpoint(id_after_, update_mode);
NodeProperties::ReplaceFrameStateInput(node, 0, frame_state_after);
}
if (count >= 2) {
// Add the frame state for before the operation.
DCHECK_EQ(IrOpcode::kDead,
NodeProperties::GetFrameStateInput(node, 1)->opcode());
NodeProperties::ReplaceFrameStateInput(node, 1, frame_state_before_);
}
accumulator_update_mode_ = update_mode;
}
BytecodeGraphBuilder* builder_;
Node* frame_state_before_;
BailoutId id_after_;
AccumulatorUpdateMode accumulator_update_mode_;
};
// Issues:
// - Need to deal with FrameState / FrameStateBeforeAndAfter / StateValue.
// - Scopes - intimately tied to AST. Need to eval what is needed.
// - Need to resolve closure parameter treatment.
BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
......@@ -28,10 +75,13 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
context_(context),
control_dependency_(control_dependency),
effect_dependency_(control_dependency),
values_(builder->local_zone()) {
values_(builder->local_zone()),
parameters_state_values_(nullptr),
registers_state_values_(nullptr),
accumulator_state_values_(nullptr) {
// The layout of values_ is:
//
// [receiver] [parameters] [registers]
// [receiver] [parameters] [registers] [accumulator]
//
// parameter[0] is the receiver (this), parameters 1..N are the
// parameters supplied to the method (arg0..argN-1). The accumulator
......@@ -51,7 +101,8 @@ BytecodeGraphBuilder::Environment::Environment(BytecodeGraphBuilder* builder,
values()->insert(values()->end(), register_count, undefined_constant);
// Accumulator
accumulator_ = undefined_constant;
accumulator_base_ = static_cast<int>(values()->size());
values()->push_back(undefined_constant);
}
......@@ -60,12 +111,15 @@ BytecodeGraphBuilder::Environment::Environment(
: builder_(other->builder_),
register_count_(other->register_count_),
parameter_count_(other->parameter_count_),
accumulator_(other->accumulator_),
context_(other->context_),
control_dependency_(other->control_dependency_),
effect_dependency_(other->effect_dependency_),
values_(other->zone()),
register_base_(other->register_base_) {
parameters_state_values_(nullptr),
registers_state_values_(nullptr),
accumulator_state_values_(nullptr),
register_base_(other->register_base_),
accumulator_base_(other->accumulator_base_) {
values_ = other->values_;
}
......@@ -102,13 +156,22 @@ Node* BytecodeGraphBuilder::Environment::LookupRegister(
}
void BytecodeGraphBuilder::Environment::BindAccumulator(Node* node) {
accumulator_ = node;
void BytecodeGraphBuilder::Environment::BindAccumulator(
Node* node, FrameStateBeforeAndAfter* states) {
if (states) {
states->AddToNode(node, AccumulatorUpdateMode::kOutputInAccumulator);
}
values()->at(accumulator_base_) = node;
}
void BytecodeGraphBuilder::Environment::RecordAfterState(
Node* node, FrameStateBeforeAndAfter* states) {
states->AddToNode(node, AccumulatorUpdateMode::kOutputIgnored);
}
Node* BytecodeGraphBuilder::Environment::LookupAccumulator() const {
return accumulator_;
return values()->at(accumulator_base_);
}
......@@ -156,8 +219,6 @@ void BytecodeGraphBuilder::Environment::Merge(
// Introduce Phi nodes for values that have differing input at merge points,
// potentially extending an existing Phi node if possible.
accumulator_ =
builder()->MergeValue(accumulator_, other->accumulator_, control);
context_ = builder()->MergeValue(context_, other->context_, control);
for (size_t i = 0; i < values_.size(); i++) {
values_[i] = builder()->MergeValue(values_[i], other->values_[i], control);
......@@ -174,7 +235,6 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() {
UpdateEffectDependency(effect);
// Assume everything in the loop is updated.
accumulator_ = builder()->NewPhi(1, accumulator_, control);
context_ = builder()->NewPhi(1, context_, control);
int size = static_cast<int>(values()->size());
for (int i = 0; i < size; i++) {
......@@ -188,19 +248,91 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() {
}
bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
Node** state_values, int offset, int count) {
Node** env_values = (count == 0) ? nullptr : &values()->at(offset);
if (*state_values == nullptr) {
return true;
} else {
DCHECK_EQ((*state_values)->InputCount(), count);
DCHECK_LE(static_cast<size_t>(offset + count), values()->size());
for (int i = 0; i < count; i++) {
if ((*state_values)->InputAt(i) != env_values[i]) {
return true;
}
}
}
return false;
}
void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values,
int offset,
int count) {
if (StateValuesRequireUpdate(state_values, offset, count)) {
const Operator* op = common()->StateValues(count);
(*state_values) = graph()->NewNode(op, count, &values()->at(offset));
}
}
Node* BytecodeGraphBuilder::Environment::Checkpoint(
BailoutId bailout_id, AccumulatorUpdateMode update_mode) {
if (!builder()->info()->is_deoptimization_enabled()) {
return builder()->jsgraph()->EmptyFrameState();
}
// TODO(rmcilroy): Consider using StateValuesCache for some state values.
UpdateStateValues(&parameters_state_values_, 0, parameter_count());
UpdateStateValues(&registers_state_values_, register_base(),
register_count());
UpdateStateValues(&accumulator_state_values_, accumulator_base(), 1);
OutputFrameStateCombine combine =
update_mode == AccumulatorUpdateMode::kOutputIgnored
? OutputFrameStateCombine::Ignore()
: OutputFrameStateCombine::PokeAt(0);
const Operator* op = common()->FrameState(
bailout_id, combine, builder()->frame_state_function_info());
Node* result = graph()->NewNode(
op, parameters_state_values_, registers_state_values_,
accumulator_state_values_, Context(), builder()->GetFunctionClosure(),
builder()->graph()->start());
return result;
}
bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate(
AccumulatorUpdateMode update_mode) {
return !StateValuesRequireUpdate(&parameters_state_values_, 0,
parameter_count()) &&
!StateValuesRequireUpdate(&registers_state_values_, register_base(),
register_count()) &&
(update_mode == AccumulatorUpdateMode::kOutputInAccumulator ||
!StateValuesRequireUpdate(&accumulator_state_values_,
accumulator_base(), 1));
}
BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
CompilationInfo* compilation_info,
JSGraph* jsgraph)
: local_zone_(local_zone),
info_(compilation_info),
jsgraph_(jsgraph),
bytecode_array_(handle(info()->shared_info()->bytecode_array())),
frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
FrameStateType::kInterpretedFunction,
bytecode_array()->parameter_count(),
bytecode_array()->register_count(), info()->shared_info(),
CALL_MAINTAINS_NATIVE_CONTEXT)),
merge_environments_(local_zone),
loop_header_environments_(local_zone),
input_buffer_size_(0),
input_buffer_(nullptr),
exit_controls_(local_zone) {
bytecode_array_ = handle(info()->shared_info()->bytecode_array());
}
exit_controls_(local_zone) {}
Node* BytecodeGraphBuilder::GetNewTarget() {
......@@ -281,18 +413,6 @@ VectorSlotPair BytecodeGraphBuilder::CreateVectorSlotPair(int slot_id) {
}
// TODO(mythria): Replace this function with one which adds real frame state.
// Also add before and after frame states and checkpointing if required.
void BytecodeGraphBuilder::AddEmptyFrameStateInputs(Node* node) {
int frame_state_count =
OperatorProperties::GetFrameStateInputCount(node->op());
for (int i = 0; i < frame_state_count; i++) {
NodeProperties::ReplaceFrameStateInput(node, i,
jsgraph()->EmptyFrameState());
}
}
bool BytecodeGraphBuilder::CreateGraph(bool stack_check) {
// Set up the basic structure of the graph. Outputs for {Start} are
// the formal parameters (including the receiver) plus context and
......@@ -444,14 +564,14 @@ void BytecodeGraphBuilder::VisitMov(
void BytecodeGraphBuilder::BuildLoadGlobal(
const interpreter::BytecodeArrayIterator& iterator,
TypeofMode typeof_mode) {
FrameStateBeforeAndAfter states(this, iterator);
Handle<Name> name =
Handle<Name>::cast(iterator.GetConstantForIndexOperand(0));
VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1));
const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
Node* node = NewNode(op, BuildLoadFeedbackVector());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -513,6 +633,7 @@ void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeofStrictWide(
void BytecodeGraphBuilder::BuildStoreGlobal(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Handle<Name> name =
Handle<Name>::cast(iterator.GetConstantForIndexOperand(0));
VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1));
......@@ -521,7 +642,7 @@ void BytecodeGraphBuilder::BuildStoreGlobal(
const Operator* op =
javascript()->StoreGlobal(language_mode(), name, feedback);
Node* node = NewNode(op, value, BuildLoadFeedbackVector());
AddEmptyFrameStateInputs(node);
environment()->RecordAfterState(node, &states);
}
......@@ -577,9 +698,7 @@ void BytecodeGraphBuilder::VisitStaContextSlot(
javascript()->StoreContext(0, iterator.GetIndexOperand(1));
Node* context = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* value = environment()->LookupAccumulator();
Node* node = NewNode(op, context, value);
CHECK(node != nullptr);
environment()->BindAccumulator(value);
NewNode(op, context, value);
}
......@@ -609,6 +728,7 @@ void BytecodeGraphBuilder::VisitStaLookupSlotStrict(
void BytecodeGraphBuilder::BuildNamedLoad(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Handle<Name> name =
Handle<Name>::cast(iterator.GetConstantForIndexOperand(1));
......@@ -616,8 +736,7 @@ void BytecodeGraphBuilder::BuildNamedLoad(
const Operator* op = javascript()->LoadNamed(language_mode(), name, feedback);
Node* node = NewNode(op, object, BuildLoadFeedbackVector());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -651,14 +770,14 @@ void BytecodeGraphBuilder::VisitLoadICStrictWide(
void BytecodeGraphBuilder::BuildKeyedLoad(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* key = environment()->LookupAccumulator();
Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
VectorSlotPair feedback = CreateVectorSlotPair(iterator.GetIndexOperand(1));
const Operator* op = javascript()->LoadProperty(language_mode(), feedback);
Node* node = NewNode(op, object, key, BuildLoadFeedbackVector());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -692,6 +811,7 @@ void BytecodeGraphBuilder::VisitKeyedLoadICStrictWide(
void BytecodeGraphBuilder::BuildNamedStore(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* value = environment()->LookupAccumulator();
Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Handle<Name> name =
......@@ -701,8 +821,7 @@ void BytecodeGraphBuilder::BuildNamedStore(
const Operator* op =
javascript()->StoreNamed(language_mode(), name, feedback);
Node* node = NewNode(op, object, value, BuildLoadFeedbackVector());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(value);
environment()->RecordAfterState(node, &states);
}
......@@ -736,6 +855,7 @@ void BytecodeGraphBuilder::VisitStoreICStrictWide(
void BytecodeGraphBuilder::BuildKeyedStore(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* value = environment()->LookupAccumulator();
Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* key = environment()->LookupRegister(iterator.GetRegisterOperand(1));
......@@ -743,8 +863,7 @@ void BytecodeGraphBuilder::BuildKeyedStore(
const Operator* op = javascript()->StoreProperty(language_mode(), feedback);
Node* node = NewNode(op, object, key, value, BuildLoadFeedbackVector());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(value);
environment()->RecordAfterState(node, &states);
}
......@@ -799,7 +918,6 @@ void BytecodeGraphBuilder::VisitCreateClosure(
iterator.GetImmediateOperand(1) ? TENURED : NOT_TENURED;
const Operator* op = javascript()->CreateClosure(shared_info, tenured);
Node* closure = NewNode(op);
AddEmptyFrameStateInputs(closure);
environment()->BindAccumulator(closure);
}
......@@ -822,10 +940,11 @@ void BytecodeGraphBuilder::VisitCreateUnmappedArguments(
}
void BytecodeGraphBuilder::BuildCreateLiteral(const Operator* op) {
void BytecodeGraphBuilder::BuildCreateLiteral(
const Operator* op, const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* literal = NewNode(op, GetFunctionClosure());
AddEmptyFrameStateInputs(literal);
environment()->BindAccumulator(literal);
environment()->BindAccumulator(literal, &states);
}
......@@ -837,7 +956,7 @@ void BytecodeGraphBuilder::BuildCreateRegExpLiteral(
int literal_flags = iterator.GetImmediateOperand(2);
const Operator* op = javascript()->CreateLiteralRegExp(
constant_pattern, literal_flags, literal_index);
BuildCreateLiteral(op);
BuildCreateLiteral(op, iterator);
}
......@@ -861,7 +980,7 @@ void BytecodeGraphBuilder::BuildCreateArrayLiteral(
int literal_flags = iterator.GetImmediateOperand(2);
const Operator* op = javascript()->CreateLiteralArray(
constant_elements, literal_flags, literal_index);
BuildCreateLiteral(op);
BuildCreateLiteral(op, iterator);
}
......@@ -885,7 +1004,7 @@ void BytecodeGraphBuilder::BuildCreateObjectLiteral(
int literal_flags = iterator.GetImmediateOperand(2);
const Operator* op = javascript()->CreateLiteralObject(
constant_properties, literal_flags, literal_index);
BuildCreateLiteral(op);
BuildCreateLiteral(op, iterator);
}
......@@ -920,6 +1039,7 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
void BytecodeGraphBuilder::BuildCall(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
// TODO(rmcilroy): Set receiver_hint correctly based on whether the receiver
// register has been loaded with null / undefined explicitly or we are sure it
// is not null / undefined.
......@@ -932,8 +1052,7 @@ void BytecodeGraphBuilder::BuildCall(
const Operator* call = javascript()->CallFunction(
arg_count + 2, language_mode(), feedback, receiver_hint);
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 2);
AddEmptyFrameStateInputs(value);
environment()->BindAccumulator(value);
environment()->BindAccumulator(value, &states);
}
......@@ -951,6 +1070,7 @@ void BytecodeGraphBuilder::VisitCallWide(
void BytecodeGraphBuilder::VisitCallJSRuntime(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* callee = BuildLoadNativeContextField(iterator.GetIndexOperand(0));
interpreter::Register receiver = iterator.GetRegisterOperand(1);
size_t arg_count = iterator.GetCountOperand(2);
......@@ -959,8 +1079,7 @@ void BytecodeGraphBuilder::VisitCallJSRuntime(
const Operator* call =
javascript()->CallFunction(arg_count + 2, language_mode());
Node* value = ProcessCallArguments(call, callee, receiver, arg_count + 2);
AddEmptyFrameStateInputs(value);
environment()->BindAccumulator(value);
environment()->BindAccumulator(value, &states);
}
......@@ -980,6 +1099,7 @@ Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
void BytecodeGraphBuilder::VisitCallRuntime(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Runtime::FunctionId functionId =
static_cast<Runtime::FunctionId>(iterator.GetIndexOperand(0));
interpreter::Register first_arg = iterator.GetRegisterOperand(1);
......@@ -988,8 +1108,7 @@ void BytecodeGraphBuilder::VisitCallRuntime(
// Create node to perform the runtime call.
const Operator* call = javascript()->CallRuntime(functionId, arg_count);
Node* value = ProcessCallRuntimeArguments(call, first_arg, arg_count);
AddEmptyFrameStateInputs(value);
environment()->BindAccumulator(value);
environment()->BindAccumulator(value, &states);
}
......@@ -1012,6 +1131,7 @@ Node* BytecodeGraphBuilder::ProcessCallNewArguments(
void BytecodeGraphBuilder::VisitNew(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
interpreter::Register callee = iterator.GetRegisterOperand(0);
interpreter::Register first_arg = iterator.GetRegisterOperand(1);
size_t arg_count = iterator.GetCountOperand(2);
......@@ -1020,31 +1140,30 @@ void BytecodeGraphBuilder::VisitNew(
const Operator* call = javascript()->CallConstruct(
static_cast<int>(arg_count) + 2, VectorSlotPair());
Node* value = ProcessCallNewArguments(call, callee, first_arg, arg_count + 2);
AddEmptyFrameStateInputs(value);
environment()->BindAccumulator(value);
environment()->BindAccumulator(value, &states);
}
void BytecodeGraphBuilder::VisitThrow(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* value = environment()->LookupAccumulator();
// TODO(mythria): Change to Runtime::kThrow when we have deoptimization
// information support in the interpreter.
NewNode(javascript()->CallRuntime(Runtime::kReThrow, 1), value);
Node* control = NewNode(common()->Throw(), value);
environment()->RecordAfterState(control, &states);
UpdateControlDependencyToLeaveFunction(control);
environment()->BindAccumulator(value);
}
void BytecodeGraphBuilder::BuildBinaryOp(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator();
Node* node = NewNode(js_op, left, right);
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -1128,25 +1247,23 @@ void BytecodeGraphBuilder::VisitShiftRightLogical(
void BytecodeGraphBuilder::VisitInc(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
const Operator* js_op =
javascript()->Add(language_mode(), BinaryOperationHints::Any());
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
jsgraph()->OneConstant());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitDec(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
const Operator* js_op =
javascript()->Subtract(language_mode(), BinaryOperationHints::Any());
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
jsgraph()->OneConstant());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -1170,13 +1287,12 @@ void BytecodeGraphBuilder::VisitTypeOf(
void BytecodeGraphBuilder::BuildDelete(
const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* key = environment()->LookupAccumulator();
Node* object = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* node =
NewNode(javascript()->DeleteProperty(language_mode()), object, key);
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -1196,12 +1312,11 @@ void BytecodeGraphBuilder::VisitDeletePropertySloppy(
void BytecodeGraphBuilder::BuildCompareOp(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* left = environment()->LookupRegister(iterator.GetRegisterOperand(0));
Node* right = environment()->LookupAccumulator();
Node* node = NewNode(js_op, left, right);
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......@@ -1267,9 +1382,9 @@ void BytecodeGraphBuilder::VisitTestInstanceOf(
void BytecodeGraphBuilder::BuildCastOperator(
const Operator* js_op, const interpreter::BytecodeArrayIterator& iterator) {
FrameStateBeforeAndAfter states(this, iterator);
Node* node = NewNode(js_op, environment()->LookupAccumulator());
AddEmptyFrameStateInputs(node);
environment()->BindAccumulator(node);
environment()->BindAccumulator(node, &states);
}
......
......@@ -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;
......
......@@ -76,9 +76,10 @@ class OutputFrameStateCombine {
// The type of stack frame that a FrameState node represents.
enum class FrameStateType {
kJavaScriptFunction, // Represents an unoptimized JavaScriptFrame.
kArgumentsAdaptor, // Represents an ArgumentsAdaptorFrame.
kConstructStub // Represents a ConstructStubFrame.
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