summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/bytecode-graph-builder.cc
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/bytecode-graph-builder.cc')
-rw-r--r--deps/v8/src/compiler/bytecode-graph-builder.cc518
1 files changed, 403 insertions, 115 deletions
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc
index 2249cbcb3f..a17947a246 100644
--- a/deps/v8/src/compiler/bytecode-graph-builder.cc
+++ b/deps/v8/src/compiler/bytecode-graph-builder.cc
@@ -60,6 +60,9 @@ class BytecodeGraphBuilder::Environment : public ZoneObject {
Environment* CopyForConditional() const;
Environment* CopyForLoop();
void Merge(Environment* other);
+ void PrepareForOsr();
+
+ void PrepareForLoopExit(Node* loop);
private:
explicit Environment(const Environment* copy);
@@ -109,6 +112,11 @@ class BytecodeGraphBuilder::FrameStateBeforeAndAfter {
id_before, OutputFrameStateCombine::Ignore());
id_after_ = BailoutId(id_before.ToInt() +
builder->bytecode_iterator().current_bytecode_size());
+ // Create an explicit checkpoint node for before the operation.
+ Node* node = builder_->NewNode(builder_->common()->Checkpoint());
+ DCHECK_EQ(IrOpcode::kDead,
+ NodeProperties::GetFrameStateInput(node)->opcode());
+ NodeProperties::ReplaceFrameStateInput(node, frame_state_before_);
}
~FrameStateBeforeAndAfter() {
@@ -123,29 +131,21 @@ class BytecodeGraphBuilder::FrameStateBeforeAndAfter {
void AddToNode(Node* node, OutputFrameStateCombine combine) {
DCHECK(!added_to_node_);
- int count = OperatorProperties::GetFrameStateInputCount(node->op());
- DCHECK_LE(count, 2);
- if (count >= 1) {
+ bool has_frame_state = OperatorProperties::HasFrameStateInput(node->op());
+ if (has_frame_state) {
// Add the frame state for after the operation.
DCHECK_EQ(IrOpcode::kDead,
- NodeProperties::GetFrameStateInput(node, 0)->opcode());
+ NodeProperties::GetFrameStateInput(node)->opcode());
Node* frame_state_after =
builder_->environment()->Checkpoint(id_after_, combine);
- 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_);
+ NodeProperties::ReplaceFrameStateInput(node, frame_state_after);
}
if (!combine.IsOutputIgnored()) {
output_poke_offset_ = static_cast<int>(combine.GetOffsetToPokeAt());
output_poke_count_ = node->op()->ValueOutputCount();
}
- frame_states_unused_ = count == 0;
+ frame_states_unused_ = !has_frame_state;
added_to_node_ = true;
}
@@ -352,12 +352,39 @@ void BytecodeGraphBuilder::Environment::PrepareForLoop() {
builder()->exit_controls_.push_back(terminate);
}
+void BytecodeGraphBuilder::Environment::PrepareForOsr() {
+ DCHECK_EQ(IrOpcode::kLoop, GetControlDependency()->opcode());
+ DCHECK_EQ(1, GetControlDependency()->InputCount());
+ Node* start = graph()->start();
+
+ // Create a control node for the OSR entry point and merge it into the loop
+ // header. Update the current environment's control dependency accordingly.
+ Node* entry = graph()->NewNode(common()->OsrLoopEntry(), start, start);
+ Node* control = builder()->MergeControl(GetControlDependency(), entry);
+ UpdateControlDependency(control);
+
+ // Create a merge of the effect from the OSR entry and the existing effect
+ // dependency. Update the current environment's effect dependency accordingly.
+ Node* effect = builder()->MergeEffect(GetEffectDependency(), entry, control);
+ UpdateEffectDependency(effect);
+
+ // Rename all values in the environment which will extend or introduce Phi
+ // nodes to contain the OSR values available at the entry point.
+ Node* osr_context = graph()->NewNode(
+ common()->OsrValue(Linkage::kOsrContextSpillSlotIndex), entry);
+ context_ = builder()->MergeValue(context_, osr_context, control);
+ int size = static_cast<int>(values()->size());
+ for (int i = 0; i < size; i++) {
+ int idx = i; // Indexing scheme follows {StandardFrame}, adapt accordingly.
+ if (i >= register_base()) idx += InterpreterFrameConstants::kExtraSlotCount;
+ if (i >= accumulator_base()) idx = Linkage::kOsrAccumulatorRegisterIndex;
+ Node* osr_value = graph()->NewNode(common()->OsrValue(idx), entry);
+ values_[i] = builder()->MergeValue(values_[i], osr_value, control);
+ }
+}
bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
Node** state_values, int offset, int count) {
- if (!builder()->deoptimization_enabled_) {
- return false;
- }
if (*state_values == nullptr) {
return true;
}
@@ -372,6 +399,31 @@ bool BytecodeGraphBuilder::Environment::StateValuesRequireUpdate(
return false;
}
+void BytecodeGraphBuilder::Environment::PrepareForLoopExit(Node* loop) {
+ DCHECK_EQ(loop->opcode(), IrOpcode::kLoop);
+
+ Node* control = GetControlDependency();
+
+ // Create the loop exit node.
+ Node* loop_exit = graph()->NewNode(common()->LoopExit(), control, loop);
+ UpdateControlDependency(loop_exit);
+
+ // Rename the effect.
+ Node* effect_rename = graph()->NewNode(common()->LoopExitEffect(),
+ GetEffectDependency(), loop_exit);
+ UpdateEffectDependency(effect_rename);
+
+ // TODO(jarin) We should also rename context here. However, uncoditional
+ // renaming confuses global object and native context specialization.
+ // We should only rename if the context is assigned in the loop.
+
+ // Rename the environmnent values.
+ for (size_t i = 0; i < values_.size(); i++) {
+ Node* rename =
+ graph()->NewNode(common()->LoopExitValue(), values_[i], loop_exit);
+ values_[i] = rename;
+ }
+}
void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values,
int offset,
@@ -385,10 +437,6 @@ void BytecodeGraphBuilder::Environment::UpdateStateValues(Node** state_values,
Node* BytecodeGraphBuilder::Environment::Checkpoint(
BailoutId bailout_id, OutputFrameStateCombine combine) {
- if (!builder()->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(),
@@ -423,7 +471,6 @@ bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate(
bool BytecodeGraphBuilder::Environment::StateValuesAreUpToDate(
int output_poke_offset, int output_poke_count) {
- if (!builder()->deoptimization_enabled_) return true;
// Poke offset is relative to the top of the stack (i.e., the accumulator).
int output_poke_start = accumulator_base() - output_poke_offset;
int output_poke_end = output_poke_start + output_poke_count;
@@ -444,12 +491,12 @@ BytecodeGraphBuilder::BytecodeGraphBuilder(Zone* local_zone,
bytecode_array_(handle(info->shared_info()->bytecode_array())),
exception_handler_table_(
handle(HandlerTable::cast(bytecode_array()->handler_table()))),
- feedback_vector_(handle(info->shared_info()->feedback_vector())),
+ feedback_vector_(handle(info->closure()->feedback_vector())),
frame_state_function_info_(common()->CreateFrameStateFunctionInfo(
FrameStateType::kInterpretedFunction,
bytecode_array()->parameter_count(),
bytecode_array()->register_count(), info->shared_info())),
- deoptimization_enabled_(info->is_deoptimization_enabled()),
+ osr_ast_id_(info->osr_ast_id()),
merge_environments_(local_zone),
exception_handlers_(local_zone),
current_exception_handler_(0),
@@ -524,6 +571,10 @@ bool BytecodeGraphBuilder::CreateGraph() {
GetFunctionContext());
set_environment(&env);
+ // For OSR add an {OsrNormalEntry} as the start of the top-level environment.
+ // It will be replaced with {Dead} after typing and optimizations.
+ if (!osr_ast_id_.IsNone()) NewNode(common()->OsrNormalEntry());
+
VisitBytecodes();
// Finish the basic structure of the graph.
@@ -538,8 +589,11 @@ bool BytecodeGraphBuilder::CreateGraph() {
void BytecodeGraphBuilder::VisitBytecodes() {
BytecodeBranchAnalysis analysis(bytecode_array(), local_zone());
+ BytecodeLoopAnalysis loop_analysis(bytecode_array(), &analysis, local_zone());
analysis.Analyze();
+ loop_analysis.Analyze();
set_branch_analysis(&analysis);
+ set_loop_analysis(&loop_analysis);
interpreter::BytecodeArrayIterator iterator(bytecode_array());
set_bytecode_iterator(&iterator);
while (!iterator.done()) {
@@ -586,6 +640,11 @@ void BytecodeGraphBuilder::VisitLdaUndefined() {
environment()->BindAccumulator(node);
}
+void BytecodeGraphBuilder::VisitLdrUndefined() {
+ Node* node = jsgraph()->UndefinedConstant();
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), node);
+}
+
void BytecodeGraphBuilder::VisitLdaNull() {
Node* node = jsgraph()->NullConstant();
environment()->BindAccumulator(node);
@@ -623,25 +682,33 @@ void BytecodeGraphBuilder::VisitMov() {
environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), value);
}
-void BytecodeGraphBuilder::BuildLoadGlobal(
- TypeofMode typeof_mode) {
- FrameStateBeforeAndAfter states(this);
- Handle<Name> name =
- Handle<Name>::cast(bytecode_iterator().GetConstantForIndexOperand(0));
+Node* BytecodeGraphBuilder::BuildLoadGlobal(TypeofMode typeof_mode) {
VectorSlotPair feedback =
- CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
-
+ CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(0));
+ DCHECK_EQ(FeedbackVectorSlotKind::LOAD_GLOBAL_IC,
+ feedback_vector()->GetKind(feedback.slot()));
+ Handle<Name> name(feedback_vector()->GetName(feedback.slot()));
const Operator* op = javascript()->LoadGlobal(name, feedback, typeof_mode);
- Node* node = NewNode(op, GetFunctionClosure());
- environment()->BindAccumulator(node, &states);
+ return NewNode(op, GetFunctionClosure());
}
void BytecodeGraphBuilder::VisitLdaGlobal() {
- BuildLoadGlobal(TypeofMode::NOT_INSIDE_TYPEOF);
+ FrameStateBeforeAndAfter states(this);
+ Node* node = BuildLoadGlobal(TypeofMode::NOT_INSIDE_TYPEOF);
+ environment()->BindAccumulator(node, &states);
+}
+
+void BytecodeGraphBuilder::VisitLdrGlobal() {
+ FrameStateBeforeAndAfter states(this);
+ Node* node = BuildLoadGlobal(TypeofMode::NOT_INSIDE_TYPEOF);
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(1), node,
+ &states);
}
void BytecodeGraphBuilder::VisitLdaGlobalInsideTypeof() {
- BuildLoadGlobal(TypeofMode::INSIDE_TYPEOF);
+ FrameStateBeforeAndAfter states(this);
+ Node* node = BuildLoadGlobal(TypeofMode::INSIDE_TYPEOF);
+ environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::BuildStoreGlobal(LanguageMode language_mode) {
@@ -665,7 +732,7 @@ void BytecodeGraphBuilder::VisitStaGlobalStrict() {
BuildStoreGlobal(LanguageMode::STRICT);
}
-void BytecodeGraphBuilder::VisitLdaContextSlot() {
+Node* BytecodeGraphBuilder::BuildLoadContextSlot() {
// TODO(mythria): LoadContextSlots are unrolled by the required depth when
// generating bytecode. Hence the value of depth is always 0. Update this
// code, when the implementation changes.
@@ -676,10 +743,19 @@ void BytecodeGraphBuilder::VisitLdaContextSlot() {
0, bytecode_iterator().GetIndexOperand(1), false);
Node* context =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
- Node* node = NewNode(op, context);
+ return NewNode(op, context);
+}
+
+void BytecodeGraphBuilder::VisitLdaContextSlot() {
+ Node* node = BuildLoadContextSlot();
environment()->BindAccumulator(node);
}
+void BytecodeGraphBuilder::VisitLdrContextSlot() {
+ Node* node = BuildLoadContextSlot();
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(2), node);
+}
+
void BytecodeGraphBuilder::VisitStaContextSlot() {
// TODO(mythria): LoadContextSlots are unrolled by the required depth when
// generating bytecode. Hence the value of depth is always 0. Update this
@@ -732,8 +808,7 @@ void BytecodeGraphBuilder::VisitStaLookupSlotStrict() {
BuildStaLookupSlot(LanguageMode::STRICT);
}
-void BytecodeGraphBuilder::BuildNamedLoad() {
- FrameStateBeforeAndAfter states(this);
+Node* BytecodeGraphBuilder::BuildNamedLoad() {
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Handle<Name> name =
@@ -742,14 +817,23 @@ void BytecodeGraphBuilder::BuildNamedLoad() {
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(2));
const Operator* op = javascript()->LoadNamed(name, feedback);
- Node* node = NewNode(op, object, GetFunctionClosure());
- environment()->BindAccumulator(node, &states);
+ return NewNode(op, object, GetFunctionClosure());
}
-void BytecodeGraphBuilder::VisitLoadIC() { BuildNamedLoad(); }
+void BytecodeGraphBuilder::VisitLdaNamedProperty() {
+ FrameStateBeforeAndAfter states(this);
+ Node* node = BuildNamedLoad();
+ environment()->BindAccumulator(node, &states);
+}
-void BytecodeGraphBuilder::BuildKeyedLoad() {
+void BytecodeGraphBuilder::VisitLdrNamedProperty() {
FrameStateBeforeAndAfter states(this);
+ Node* node = BuildNamedLoad();
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(3), node,
+ &states);
+}
+
+Node* BytecodeGraphBuilder::BuildKeyedLoad() {
Node* key = environment()->LookupAccumulator();
Node* object =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
@@ -757,11 +841,21 @@ void BytecodeGraphBuilder::BuildKeyedLoad() {
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(1));
const Operator* op = javascript()->LoadProperty(feedback);
- Node* node = NewNode(op, object, key, GetFunctionClosure());
+ return NewNode(op, object, key, GetFunctionClosure());
+}
+
+void BytecodeGraphBuilder::VisitLdaKeyedProperty() {
+ FrameStateBeforeAndAfter states(this);
+ Node* node = BuildKeyedLoad();
environment()->BindAccumulator(node, &states);
}
-void BytecodeGraphBuilder::VisitKeyedLoadIC() { BuildKeyedLoad(); }
+void BytecodeGraphBuilder::VisitLdrKeyedProperty() {
+ FrameStateBeforeAndAfter states(this);
+ Node* node = BuildKeyedLoad();
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(2), node,
+ &states);
+}
void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) {
FrameStateBeforeAndAfter states(this);
@@ -778,11 +872,11 @@ void BytecodeGraphBuilder::BuildNamedStore(LanguageMode language_mode) {
environment()->RecordAfterState(node, &states);
}
-void BytecodeGraphBuilder::VisitStoreICSloppy() {
+void BytecodeGraphBuilder::VisitStaNamedPropertySloppy() {
BuildNamedStore(LanguageMode::SLOPPY);
}
-void BytecodeGraphBuilder::VisitStoreICStrict() {
+void BytecodeGraphBuilder::VisitStaNamedPropertyStrict() {
BuildNamedStore(LanguageMode::STRICT);
}
@@ -801,11 +895,11 @@ void BytecodeGraphBuilder::BuildKeyedStore(LanguageMode language_mode) {
environment()->RecordAfterState(node, &states);
}
-void BytecodeGraphBuilder::VisitKeyedStoreICSloppy() {
+void BytecodeGraphBuilder::VisitStaKeyedPropertySloppy() {
BuildKeyedStore(LanguageMode::SLOPPY);
}
-void BytecodeGraphBuilder::VisitKeyedStoreICStrict() {
+void BytecodeGraphBuilder::VisitStaKeyedPropertyStrict() {
BuildKeyedStore(LanguageMode::STRICT);
}
@@ -832,6 +926,43 @@ void BytecodeGraphBuilder::VisitCreateClosure() {
environment()->BindAccumulator(closure);
}
+void BytecodeGraphBuilder::VisitCreateBlockContext() {
+ Handle<ScopeInfo> scope_info = Handle<ScopeInfo>::cast(
+ bytecode_iterator().GetConstantForIndexOperand(0));
+
+ const Operator* op = javascript()->CreateBlockContext(scope_info);
+ Node* context = NewNode(op, environment()->LookupAccumulator());
+ environment()->BindAccumulator(context);
+}
+
+void BytecodeGraphBuilder::VisitCreateFunctionContext() {
+ uint32_t slots = bytecode_iterator().GetIndexOperand(0);
+ const Operator* op = javascript()->CreateFunctionContext(slots);
+ Node* context = NewNode(op, GetFunctionClosure());
+ environment()->BindAccumulator(context);
+}
+
+void BytecodeGraphBuilder::VisitCreateCatchContext() {
+ interpreter::Register reg = bytecode_iterator().GetRegisterOperand(0);
+ Node* exception = environment()->LookupRegister(reg);
+ Handle<String> name =
+ Handle<String>::cast(bytecode_iterator().GetConstantForIndexOperand(1));
+ Node* closure = environment()->LookupAccumulator();
+
+ const Operator* op = javascript()->CreateCatchContext(name);
+ Node* context = NewNode(op, exception, closure);
+ environment()->BindAccumulator(context);
+}
+
+void BytecodeGraphBuilder::VisitCreateWithContext() {
+ Node* object =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
+
+ const Operator* op = javascript()->CreateWithContext();
+ Node* context = NewNode(op, object, environment()->LookupAccumulator());
+ environment()->BindAccumulator(context);
+}
+
void BytecodeGraphBuilder::BuildCreateArguments(CreateArgumentsType type) {
FrameStateBeforeAndAfter states(this);
const Operator* op = javascript()->CreateArguments(type);
@@ -879,15 +1010,21 @@ void BytecodeGraphBuilder::VisitCreateArrayLiteral() {
}
void BytecodeGraphBuilder::VisitCreateObjectLiteral() {
+ FrameStateBeforeAndAfter states(this);
Handle<FixedArray> constant_properties = Handle<FixedArray>::cast(
bytecode_iterator().GetConstantForIndexOperand(0));
int literal_index = bytecode_iterator().GetIndexOperand(1);
- int literal_flags = bytecode_iterator().GetFlagOperand(2);
+ int bytecode_flags = bytecode_iterator().GetFlagOperand(2);
+ int literal_flags =
+ interpreter::CreateObjectLiteralFlags::FlagsBits::decode(bytecode_flags);
// TODO(mstarzinger): Thread through number of properties.
int number_of_properties = constant_properties->length() / 2;
- const Operator* op = javascript()->CreateLiteralObject(
- constant_properties, literal_flags, literal_index, number_of_properties);
- BuildCreateLiteral(op);
+ Node* literal = NewNode(
+ javascript()->CreateLiteralObject(constant_properties, literal_flags,
+ literal_index, number_of_properties),
+ GetFunctionClosure());
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(3),
+ literal, &states);
}
Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
@@ -908,14 +1045,15 @@ Node* BytecodeGraphBuilder::ProcessCallArguments(const Operator* call_op,
void BytecodeGraphBuilder::BuildCall(TailCallMode tail_call_mode) {
FrameStateBeforeAndAfter states(this);
- // 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.
ConvertReceiverMode receiver_hint = ConvertReceiverMode::kAny;
Node* callee =
environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
interpreter::Register receiver = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
+
+ // Slot index of 0 is used indicate no feedback slot is available. Assert
+ // the assumption that slot index 0 is never a valid feedback slot.
+ STATIC_ASSERT(TypeFeedbackVector::kReservedIndexCount > 0);
VectorSlotPair feedback =
CreateVectorSlotPair(bytecode_iterator().GetIndexOperand(3));
@@ -963,8 +1101,7 @@ Node* BytecodeGraphBuilder::ProcessCallRuntimeArguments(
void BytecodeGraphBuilder::VisitCallRuntime() {
FrameStateBeforeAndAfter states(this);
- Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>(
- bytecode_iterator().GetRuntimeIdOperand(0));
+ Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
@@ -976,8 +1113,7 @@ void BytecodeGraphBuilder::VisitCallRuntime() {
void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
FrameStateBeforeAndAfter states(this);
- Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>(
- bytecode_iterator().GetRuntimeIdOperand(0));
+ Runtime::FunctionId functionId = bytecode_iterator().GetRuntimeIdOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
interpreter::Register first_return =
@@ -991,8 +1127,7 @@ void BytecodeGraphBuilder::VisitCallRuntimeForPair() {
void BytecodeGraphBuilder::VisitInvokeIntrinsic() {
FrameStateBeforeAndAfter states(this);
- Runtime::FunctionId functionId = static_cast<Runtime::FunctionId>(
- bytecode_iterator().GetRuntimeIdOperand(0));
+ Runtime::FunctionId functionId = bytecode_iterator().GetIntrinsicIdOperand(0);
interpreter::Register first_arg = bytecode_iterator().GetRegisterOperand(1);
size_t arg_count = bytecode_iterator().GetRegisterCountOperand(2);
@@ -1042,6 +1177,7 @@ void BytecodeGraphBuilder::BuildThrow() {
}
void BytecodeGraphBuilder::VisitThrow() {
+ BuildLoopExitsForFunctionExit();
BuildThrow();
Node* call = environment()->LookupAccumulator();
Node* control = NewNode(common()->Throw(), call);
@@ -1049,6 +1185,7 @@ void BytecodeGraphBuilder::VisitThrow() {
}
void BytecodeGraphBuilder::VisitReThrow() {
+ BuildLoopExitsForFunctionExit();
Node* value = environment()->LookupAccumulator();
Node* call = NewNode(javascript()->CallRuntime(Runtime::kReThrow), value);
Node* control = NewNode(common()->Throw(), call);
@@ -1064,78 +1201,143 @@ void BytecodeGraphBuilder::BuildBinaryOp(const Operator* js_op) {
environment()->BindAccumulator(node, &states);
}
+// Helper function to create binary operation hint from the recorded type
+// feedback.
+BinaryOperationHint BytecodeGraphBuilder::GetBinaryOperationHint(
+ int operand_index) {
+ FeedbackVectorSlot slot = feedback_vector()->ToSlot(
+ bytecode_iterator().GetIndexOperand(operand_index));
+ DCHECK_EQ(FeedbackVectorSlotKind::GENERAL, feedback_vector()->GetKind(slot));
+ Object* feedback = feedback_vector()->Get(slot);
+ BinaryOperationHint hint = BinaryOperationHint::kAny;
+ if (feedback->IsSmi()) {
+ hint = BinaryOperationHintFromFeedback((Smi::cast(feedback))->value());
+ }
+ return hint;
+}
+
void BytecodeGraphBuilder::VisitAdd() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->Add(hints));
+ BuildBinaryOp(
+ javascript()->Add(GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitSub() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->Subtract(hints));
+ BuildBinaryOp(javascript()->Subtract(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitMul() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->Multiply(hints));
+ BuildBinaryOp(javascript()->Multiply(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitDiv() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->Divide(hints));
+ BuildBinaryOp(
+ javascript()->Divide(GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitMod() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->Modulus(hints));
+ BuildBinaryOp(
+ javascript()->Modulus(GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitBitwiseOr() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->BitwiseOr(hints));
+ BuildBinaryOp(javascript()->BitwiseOr(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitBitwiseXor() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->BitwiseXor(hints));
+ BuildBinaryOp(javascript()->BitwiseXor(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitBitwiseAnd() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->BitwiseAnd(hints));
+ BuildBinaryOp(javascript()->BitwiseAnd(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitShiftLeft() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->ShiftLeft(hints));
+ BuildBinaryOp(javascript()->ShiftLeft(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitShiftRight() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->ShiftRight(hints));
+ BuildBinaryOp(javascript()->ShiftRight(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
}
void BytecodeGraphBuilder::VisitShiftRightLogical() {
- BinaryOperationHints hints = BinaryOperationHints::Any();
- BuildBinaryOp(javascript()->ShiftRightLogical(hints));
+ BuildBinaryOp(javascript()->ShiftRightLogical(
+ GetBinaryOperationHint(kBinaryOperationHintIndex)));
+}
+
+void BytecodeGraphBuilder::BuildBinaryOpWithImmediate(const Operator* js_op) {
+ FrameStateBeforeAndAfter states(this);
+ Node* left =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(1));
+ Node* right = jsgraph()->Constant(bytecode_iterator().GetImmediateOperand(0));
+ Node* node = NewNode(js_op, left, right);
+ environment()->BindAccumulator(node, &states);
+}
+
+void BytecodeGraphBuilder::VisitAddSmi() {
+ BuildBinaryOpWithImmediate(
+ javascript()->Add(GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+}
+
+void BytecodeGraphBuilder::VisitSubSmi() {
+ BuildBinaryOpWithImmediate(javascript()->Subtract(
+ GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+}
+
+void BytecodeGraphBuilder::VisitBitwiseOrSmi() {
+ BuildBinaryOpWithImmediate(javascript()->BitwiseOr(
+ GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+}
+
+void BytecodeGraphBuilder::VisitBitwiseAndSmi() {
+ BuildBinaryOpWithImmediate(javascript()->BitwiseAnd(
+ GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+}
+
+void BytecodeGraphBuilder::VisitShiftLeftSmi() {
+ BuildBinaryOpWithImmediate(javascript()->ShiftLeft(
+ GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
+}
+
+void BytecodeGraphBuilder::VisitShiftRightSmi() {
+ BuildBinaryOpWithImmediate(javascript()->ShiftRight(
+ GetBinaryOperationHint(kBinaryOperationSmiHintIndex)));
}
void BytecodeGraphBuilder::VisitInc() {
FrameStateBeforeAndAfter states(this);
- const Operator* js_op = javascript()->Add(BinaryOperationHints::Any());
+ // Note: Use subtract -1 here instead of add 1 to ensure we always convert to
+ // a number, not a string.
+ const Operator* js_op =
+ javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex));
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
- jsgraph()->OneConstant());
+ jsgraph()->Constant(-1));
environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitDec() {
FrameStateBeforeAndAfter states(this);
- const Operator* js_op = javascript()->Subtract(BinaryOperationHints::Any());
+ const Operator* js_op =
+ javascript()->Subtract(GetBinaryOperationHint(kCountOperationHintIndex));
Node* node = NewNode(js_op, environment()->LookupAccumulator(),
jsgraph()->OneConstant());
environment()->BindAccumulator(node, &states);
}
void BytecodeGraphBuilder::VisitLogicalNot() {
+ Node* value = environment()->LookupAccumulator();
+ Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value,
+ jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
+ environment()->BindAccumulator(node);
+}
+
+void BytecodeGraphBuilder::VisitToBooleanLogicalNot() {
Node* value = NewNode(javascript()->ToBoolean(ToBooleanHint::kAny),
environment()->LookupAccumulator());
Node* node = NewNode(common()->Select(MachineRepresentation::kTagged), value,
@@ -1177,31 +1379,38 @@ void BytecodeGraphBuilder::BuildCompareOp(const Operator* js_op) {
}
void BytecodeGraphBuilder::VisitTestEqual() {
- BuildCompareOp(javascript()->Equal());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->Equal(hint));
}
void BytecodeGraphBuilder::VisitTestNotEqual() {
- BuildCompareOp(javascript()->NotEqual());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->NotEqual(hint));
}
void BytecodeGraphBuilder::VisitTestEqualStrict() {
- BuildCompareOp(javascript()->StrictEqual());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->StrictEqual(hint));
}
void BytecodeGraphBuilder::VisitTestLessThan() {
- BuildCompareOp(javascript()->LessThan());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->LessThan(hint));
}
void BytecodeGraphBuilder::VisitTestGreaterThan() {
- BuildCompareOp(javascript()->GreaterThan());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->GreaterThan(hint));
}
void BytecodeGraphBuilder::VisitTestLessThanOrEqual() {
- BuildCompareOp(javascript()->LessThanOrEqual());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->LessThanOrEqual(hint));
}
void BytecodeGraphBuilder::VisitTestGreaterThanOrEqual() {
- BuildCompareOp(javascript()->GreaterThanOrEqual());
+ CompareOperationHint hint = CompareOperationHint::kAny;
+ BuildCompareOp(javascript()->GreaterThanOrEqual(hint));
}
void BytecodeGraphBuilder::VisitTestIn() {
@@ -1209,14 +1418,14 @@ void BytecodeGraphBuilder::VisitTestIn() {
}
void BytecodeGraphBuilder::VisitTestInstanceOf() {
- DCHECK(!FLAG_harmony_instanceof);
BuildCompareOp(javascript()->InstanceOf());
}
void BytecodeGraphBuilder::BuildCastOperator(const Operator* js_op) {
FrameStateBeforeAndAfter states(this);
- Node* node = NewNode(js_op, environment()->LookupAccumulator());
- environment()->BindAccumulator(node, &states);
+ Node* value = NewNode(js_op, environment()->LookupAccumulator());
+ environment()->BindRegister(bytecode_iterator().GetRegisterOperand(0), value,
+ &states);
}
void BytecodeGraphBuilder::VisitToName() {
@@ -1296,7 +1505,17 @@ void BytecodeGraphBuilder::VisitStackCheck() {
environment()->RecordAfterState(node, &states);
}
+void BytecodeGraphBuilder::VisitOsrPoll() {
+ // TODO(4764): This should be moved into the {VisitBytecodes} once we merge
+ // the polling with existing bytecode. This will also guarantee that we are
+ // not missing the OSR entry point, which we wouldn't catch right now.
+ if (osr_ast_id_.ToInt() == bytecode_iterator().current_offset()) {
+ environment()->PrepareForOsr();
+ }
+}
+
void BytecodeGraphBuilder::VisitReturn() {
+ BuildLoopExitsForFunctionExit();
Node* control =
NewNode(common()->Return(), environment()->LookupAccumulator());
MergeControlToLeaveFunction(control);
@@ -1317,10 +1536,11 @@ DEBUG_BREAK_BYTECODE_LIST(DEBUG_BREAK);
void BytecodeGraphBuilder::BuildForInPrepare() {
FrameStateBeforeAndAfter states(this);
- Node* receiver = environment()->LookupAccumulator();
+ Node* receiver =
+ environment()->LookupRegister(bytecode_iterator().GetRegisterOperand(0));
Node* prepare = NewNode(javascript()->ForInPrepare(), receiver);
environment()->BindRegistersToProjections(
- bytecode_iterator().GetRegisterOperand(0), prepare, &states);
+ bytecode_iterator().GetRegisterOperand(1), prepare, &states);
}
void BytecodeGraphBuilder::VisitForInPrepare() { BuildForInPrepare(); }
@@ -1362,6 +1582,51 @@ void BytecodeGraphBuilder::VisitForInStep() {
environment()->BindAccumulator(index, &states);
}
+void BytecodeGraphBuilder::VisitSuspendGenerator() {
+ Node* state = environment()->LookupAccumulator();
+ Node* generator = environment()->LookupRegister(
+ bytecode_iterator().GetRegisterOperand(0));
+ // The offsets used by the bytecode iterator are relative to a different base
+ // than what is used in the interpreter, hence the addition.
+ Node* offset =
+ jsgraph()->Constant(bytecode_iterator().current_offset() +
+ (BytecodeArray::kHeaderSize - kHeapObjectTag));
+
+ int register_count = environment()->register_count();
+ int value_input_count = 3 + register_count;
+
+ Node** value_inputs = local_zone()->NewArray<Node*>(value_input_count);
+ value_inputs[0] = generator;
+ value_inputs[1] = state;
+ value_inputs[2] = offset;
+ for (int i = 0; i < register_count; ++i) {
+ value_inputs[3 + i] =
+ environment()->LookupRegister(interpreter::Register(i));
+ }
+
+ MakeNode(javascript()->GeneratorStore(register_count), value_input_count,
+ value_inputs, false);
+}
+
+void BytecodeGraphBuilder::VisitResumeGenerator() {
+ FrameStateBeforeAndAfter states(this);
+
+ Node* generator = environment()->LookupRegister(
+ bytecode_iterator().GetRegisterOperand(0));
+
+ // Bijection between registers and array indices must match that used in
+ // InterpreterAssembler::ExportRegisterFile.
+ for (int i = 0; i < environment()->register_count(); ++i) {
+ Node* value = NewNode(javascript()->GeneratorRestoreRegister(i), generator);
+ environment()->BindRegister(interpreter::Register(i), value);
+ }
+
+ Node* state =
+ NewNode(javascript()->GeneratorRestoreContinuation(), generator);
+
+ environment()->BindAccumulator(state, &states);
+}
+
void BytecodeGraphBuilder::VisitWide() {
// Consumed by the BytecodeArrayIterator.
UNREACHABLE();
@@ -1373,10 +1638,12 @@ void BytecodeGraphBuilder::VisitExtraWide() {
}
void BytecodeGraphBuilder::VisitIllegal() {
- // Never present in valid bytecode.
+ // Not emitted in valid bytecode.
UNREACHABLE();
}
+void BytecodeGraphBuilder::VisitNop() {}
+
void BytecodeGraphBuilder::SwitchToMergeEnvironment(int current_offset) {
if (merge_environments_[current_offset] != nullptr) {
if (environment() != nullptr) {
@@ -1395,6 +1662,7 @@ void BytecodeGraphBuilder::BuildLoopHeaderEnvironment(int current_offset) {
}
void BytecodeGraphBuilder::MergeIntoSuccessorEnvironment(int target_offset) {
+ BuildLoopExitsForBranch(target_offset);
if (merge_environments_[target_offset] == nullptr) {
// Append merge nodes to the environment. We may merge here with another
// environment. So add a place holder for merge nodes. We may add redundant
@@ -1413,6 +1681,28 @@ void BytecodeGraphBuilder::MergeControlToLeaveFunction(Node* exit) {
set_environment(nullptr);
}
+void BytecodeGraphBuilder::BuildLoopExitsForBranch(int target_offset) {
+ int origin_offset = bytecode_iterator().current_offset();
+ // Only build loop exits for forward edges.
+ if (target_offset > origin_offset) {
+ BuildLoopExitsUntilLoop(loop_analysis()->GetLoopOffsetFor(target_offset));
+ }
+}
+
+void BytecodeGraphBuilder::BuildLoopExitsUntilLoop(int loop_offset) {
+ int origin_offset = bytecode_iterator().current_offset();
+ int current_loop = loop_analysis()->GetLoopOffsetFor(origin_offset);
+ while (loop_offset < current_loop) {
+ Node* loop_node = merge_environments_[current_loop]->GetControlDependency();
+ environment()->PrepareForLoopExit(loop_node);
+ current_loop = loop_analysis()->GetParentLoopFor(current_loop);
+ }
+}
+
+void BytecodeGraphBuilder::BuildLoopExitsForFunctionExit() {
+ BuildLoopExitsUntilLoop(-1);
+}
+
void BytecodeGraphBuilder::BuildJump() {
MergeIntoSuccessorEnvironment(bytecode_iterator().GetJumpTargetOffset());
}
@@ -1431,7 +1721,8 @@ void BytecodeGraphBuilder::BuildConditionalJump(Node* condition) {
void BytecodeGraphBuilder::BuildJumpIfEqual(Node* comperand) {
Node* accumulator = environment()->LookupAccumulator();
Node* condition =
- NewNode(javascript()->StrictEqual(), accumulator, comperand);
+ NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
+ accumulator, comperand);
BuildConditionalJump(condition);
}
@@ -1440,14 +1731,17 @@ void BytecodeGraphBuilder::BuildJumpIfToBooleanEqual(Node* comperand) {
Node* accumulator = environment()->LookupAccumulator();
Node* to_boolean =
NewNode(javascript()->ToBoolean(ToBooleanHint::kAny), accumulator);
- Node* condition = NewNode(javascript()->StrictEqual(), to_boolean, comperand);
+ Node* condition =
+ NewNode(javascript()->StrictEqual(CompareOperationHint::kAny), to_boolean,
+ comperand);
BuildConditionalJump(condition);
}
void BytecodeGraphBuilder::BuildJumpIfNotHole() {
Node* accumulator = environment()->LookupAccumulator();
- Node* condition = NewNode(javascript()->StrictEqual(), accumulator,
- jsgraph()->TheHoleConstant());
+ Node* condition =
+ NewNode(javascript()->StrictEqual(CompareOperationHint::kAny),
+ accumulator, jsgraph()->TheHoleConstant());
Node* node =
NewNode(common()->Select(MachineRepresentation::kTagged), condition,
jsgraph()->FalseConstant(), jsgraph()->TrueConstant());
@@ -1481,10 +1775,8 @@ void BytecodeGraphBuilder::EnterAndExitExceptionHandlers(int current_offset) {
int next_end = table->GetRangeEnd(current_exception_handler_);
int next_handler = table->GetRangeHandler(current_exception_handler_);
int context_register = table->GetRangeData(current_exception_handler_);
- CatchPrediction pred =
- table->GetRangePrediction(current_exception_handler_);
exception_handlers_.push(
- {next_start, next_end, next_handler, context_register, pred});
+ {next_start, next_end, next_handler, context_register});
current_exception_handler_++;
}
}
@@ -1494,7 +1786,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
DCHECK_EQ(op->ValueInputCount(), value_input_count);
bool has_context = OperatorProperties::HasContextInput(op);
- int frame_state_count = OperatorProperties::GetFrameStateInputCount(op);
+ bool has_frame_state = OperatorProperties::HasFrameStateInput(op);
bool has_control = op->ControlInputCount() == 1;
bool has_effect = op->EffectInputCount() == 1;
@@ -1502,13 +1794,13 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
DCHECK_LT(op->EffectInputCount(), 2);
Node* result = nullptr;
- if (!has_context && frame_state_count == 0 && !has_control && !has_effect) {
+ if (!has_context && !has_frame_state && !has_control && !has_effect) {
result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
} else {
bool inside_handler = !exception_handlers_.empty();
int input_count_with_deps = value_input_count;
if (has_context) ++input_count_with_deps;
- input_count_with_deps += frame_state_count;
+ if (has_frame_state) ++input_count_with_deps;
if (has_control) ++input_count_with_deps;
if (has_effect) ++input_count_with_deps;
Node** buffer = EnsureInputBufferSize(input_count_with_deps);
@@ -1517,7 +1809,7 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
if (has_context) {
*current_input++ = environment()->Context();
}
- for (int i = 0; i < frame_state_count; i++) {
+ if (has_frame_state) {
// The frame state will be inserted later. Here we misuse
// the {Dead} node as a sentinel to be later overwritten
// with the real frame state.
@@ -1542,13 +1834,9 @@ Node* BytecodeGraphBuilder::MakeNode(const Operator* op, int value_input_count,
if (!result->op()->HasProperty(Operator::kNoThrow) && inside_handler) {
int handler_offset = exception_handlers_.top().handler_offset_;
int context_index = exception_handlers_.top().context_register_;
- CatchPrediction prediction = exception_handlers_.top().pred_;
interpreter::Register context_register(context_index);
- IfExceptionHint hint = prediction == CatchPrediction::CAUGHT
- ? IfExceptionHint::kLocallyCaught
- : IfExceptionHint::kLocallyUncaught;
Environment* success_env = environment()->CopyForConditional();
- const Operator* op = common()->IfException(hint);
+ const Operator* op = common()->IfException();
Node* effect = environment()->GetEffectDependency();
Node* on_exception = graph()->NewNode(op, effect, result);
Node* context = environment()->LookupRegister(context_register);