diff options
Diffstat (limited to 'deps/v8/src/compiler/bytecode-graph-builder.cc')
-rw-r--r-- | deps/v8/src/compiler/bytecode-graph-builder.cc | 70 |
1 files changed, 45 insertions, 25 deletions
diff --git a/deps/v8/src/compiler/bytecode-graph-builder.cc b/deps/v8/src/compiler/bytecode-graph-builder.cc index 064d7ee7e4..b59b5a1b84 100644 --- a/deps/v8/src/compiler/bytecode-graph-builder.cc +++ b/deps/v8/src/compiler/bytecode-graph-builder.cc @@ -164,6 +164,8 @@ class BytecodeGraphBuilder { // to the given node and the output value produced by the node is combined. // Conceptually this frame state is "after" a given operation. void PrepareFrameState(Node* node, OutputFrameStateCombine combine); + void PrepareFrameState(Node* node, OutputFrameStateCombine combine, + BailoutId bailout_id); void BuildCreateArguments(CreateArgumentsType type); Node* BuildLoadGlobal(NameRef name, uint32_t feedback_slot_index, @@ -261,6 +263,11 @@ class BytecodeGraphBuilder { // feedback. Returns kDisallowSpeculation if feedback is insufficient. SpeculationMode GetSpeculationMode(int slot_id) const; + // Helpers for building the implicit FunctionEntry and IterationBody + // StackChecks. + void BuildFunctionEntryStackCheck(); + void BuildIterationBodyStackCheck(); + // Control flow plumbing. void BuildJump(); void BuildJumpIf(Node* condition); @@ -355,8 +362,6 @@ class BytecodeGraphBuilder { currently_peeled_loop_offset_ = offset; } bool skip_first_stack_check() const { return skip_first_stack_check_; } - bool visited_first_stack_check() const { return visited_first_stack_check_; } - void set_visited_first_stack_check() { visited_first_stack_check_ = true; } int current_exception_handler() const { return current_exception_handler_; } void set_current_exception_handler(int index) { current_exception_handler_ = index; @@ -395,7 +400,6 @@ class BytecodeGraphBuilder { int currently_peeled_loop_offset_; const bool skip_first_stack_check_; - bool visited_first_stack_check_ = false; // Merge environments are snapshots of the environment at points where the // control flow merges. This models a forward data flow propagation of all @@ -1086,16 +1090,30 @@ void BytecodeGraphBuilder::PrepareEagerCheckpoint() { void BytecodeGraphBuilder::PrepareFrameState(Node* node, OutputFrameStateCombine combine) { if (OperatorProperties::HasFrameStateInput(node->op())) { + PrepareFrameState(node, combine, + BailoutId(bytecode_iterator().current_offset())); + } +} + +void BytecodeGraphBuilder::PrepareFrameState(Node* node, + OutputFrameStateCombine combine, + BailoutId bailout_id) { + if (OperatorProperties::HasFrameStateInput(node->op())) { // Add the frame state for after the operation. The node in question has // already been created and had a {Dead} frame state input up until now. DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op())); DCHECK_EQ(IrOpcode::kDead, NodeProperties::GetFrameStateInput(node)->opcode()); - BailoutId bailout_id(bytecode_iterator().current_offset()); + DCHECK_IMPLIES(bailout_id.ToInt() == kFunctionEntryBytecodeOffset, + bytecode_iterator().current_offset() == 0); + // If we have kFunctionEntryBytecodeOffset as the bailout_id, we want to get + // the liveness at the moment of function entry. This is the same as the IN + // liveness of the first actual bytecode. const BytecodeLivenessState* liveness_after = - bytecode_analysis().GetOutLivenessFor( - bytecode_iterator().current_offset()); + bailout_id.ToInt() == kFunctionEntryBytecodeOffset + ? bytecode_analysis().GetInLivenessFor(0) + : bytecode_analysis().GetOutLivenessFor(bailout_id.ToInt()); Node* frame_state_after = environment()->Checkpoint(bailout_id, combine, liveness_after); @@ -1204,6 +1222,21 @@ void BytecodeGraphBuilder::RemoveMergeEnvironmentsBeforeOffset( } } +void BytecodeGraphBuilder::BuildFunctionEntryStackCheck() { + if (!skip_first_stack_check()) { + Node* node = + NewNode(javascript()->StackCheck(StackCheckKind::kJSFunctionEntry)); + PrepareFrameState(node, OutputFrameStateCombine::Ignore(), + BailoutId(kFunctionEntryBytecodeOffset)); + } +} + +void BytecodeGraphBuilder::BuildIterationBodyStackCheck() { + Node* node = + NewNode(javascript()->StackCheck(StackCheckKind::kJSIterationBody)); + environment()->RecordAfterState(node, Environment::kAttachFrameState); +} + // We will iterate through the OSR loop, then its parent, and so on // until we have reached the outmost loop containing the OSR loop. We do // not generate nodes for anything before the outermost loop. @@ -1307,6 +1340,8 @@ void BytecodeGraphBuilder::VisitBytecodes() { // the last copies of the loops it contains) to be generated by the normal // bytecode iteration below. AdvanceToOsrEntryAndPeelLoops(); + } else { + BuildFunctionEntryStackCheck(); } bool has_one_shot_bytecode = false; @@ -3229,7 +3264,10 @@ void BytecodeGraphBuilder::VisitJumpIfUndefinedOrNullConstant() { BuildJumpIfEqual(jsgraph()->NullConstant()); } -void BytecodeGraphBuilder::VisitJumpLoop() { BuildJump(); } +void BytecodeGraphBuilder::VisitJumpLoop() { + BuildIterationBodyStackCheck(); + BuildJump(); +} void BytecodeGraphBuilder::BuildSwitchOnSmi(Node* condition) { interpreter::JumpTableTargetOffsets offsets = @@ -3252,24 +3290,6 @@ void BytecodeGraphBuilder::VisitSwitchOnSmiNoFeedback() { BuildSwitchOnSmi(acc_smi); } -void BytecodeGraphBuilder::VisitStackCheck() { - // Note: The stack check kind is determined heuristically: we simply assume - // that the first seen stack check is at function-entry, and all other stack - // checks are at iteration-body. An alternative precise solution would be to - // parameterize the StackCheck bytecode; but this has the caveat of increased - // code size. - StackCheckKind kind = StackCheckKind::kJSIterationBody; - if (!visited_first_stack_check()) { - set_visited_first_stack_check(); - kind = StackCheckKind::kJSFunctionEntry; - if (skip_first_stack_check()) return; - } - - PrepareEagerCheckpoint(); - Node* node = NewNode(javascript()->StackCheck(kind)); - environment()->RecordAfterState(node, Environment::kAttachFrameState); -} - void BytecodeGraphBuilder::VisitSetPendingMessage() { Node* previous_message = NewNode(javascript()->LoadMessage()); NewNode(javascript()->StoreMessage(), environment()->LookupAccumulator()); |