Line data Source code
1 : // Copyright 2015 the V8 project authors. All rights reserved.
2 : // Use of this source code is governed by a BSD-style license that can be
3 : // found in the LICENSE file.
4 :
5 : #include "src/compiler/frame-elider.h"
6 :
7 : #include "src/base/adapters.h"
8 :
9 : namespace v8 {
10 : namespace internal {
11 : namespace compiler {
12 :
13 915865 : FrameElider::FrameElider(InstructionSequence* code) : code_(code) {}
14 :
15 915860 : void FrameElider::Run() {
16 915860 : MarkBlocks();
17 915885 : PropagateMarks();
18 915873 : MarkDeConstruction();
19 915838 : }
20 :
21 :
22 915960 : void FrameElider::MarkBlocks() {
23 52134671 : for (InstructionBlock* block : instruction_blocks()) {
24 11460756 : if (block->needs_frame()) continue;
25 58554134 : for (int i = block->code_start(); i < block->code_end(); ++i) {
26 21070061 : const Instruction* instr = InstructionAt(i);
27 40904179 : if (instr->IsCall() || instr->IsDeoptimizeCall() ||
28 40782398 : instr->arch_opcode() == ArchOpcode::kArchStackPointer ||
29 : instr->arch_opcode() == ArchOpcode::kArchFramePointer) {
30 : block->mark_needs_frame();
31 : break;
32 : }
33 : }
34 : }
35 915884 : }
36 :
37 :
38 915867 : void FrameElider::PropagateMarks() {
39 915867 : while (PropagateInOrder() || PropagateReversed()) {
40 : }
41 915872 : }
42 :
43 :
44 915877 : void FrameElider::MarkDeConstruction() {
45 14428178 : for (InstructionBlock* block : instruction_blocks()) {
46 11461247 : if (block->needs_frame()) {
47 : // Special case: The start block needs a frame.
48 9218194 : if (block->predecessors().empty()) {
49 : block->mark_must_construct_frame();
50 : }
51 : // Find "frame -> no frame" transitions, inserting frame
52 : // deconstructions.
53 30798323 : for (RpoNumber& succ : block->successors()) {
54 12361936 : if (!InstructionBlockAt(succ)->needs_frame()) {
55 : DCHECK_EQ(1U, block->SuccessorCount());
56 : const Instruction* last =
57 1135218 : InstructionAt(block->last_instruction_index());
58 3309915 : if (last->IsThrow() || last->IsTailCall() ||
59 : last->IsDeoptimizeCall()) {
60 : // We need to keep the frame if we exit the block through any
61 : // of these.
62 : continue;
63 : }
64 : // The only cases when we need to deconstruct are ret and jump.
65 : DCHECK(last->IsRet() || last->IsJump());
66 : block->mark_must_deconstruct_frame();
67 : }
68 : }
69 : } else {
70 : // Find "no frame -> frame" transitions, inserting frame constructions.
71 6356535 : for (RpoNumber& succ : block->successors()) {
72 1870423 : if (InstructionBlockAt(succ)->needs_frame()) {
73 : DCHECK_NE(1U, block->SuccessorCount());
74 : InstructionBlockAt(succ)->mark_must_construct_frame();
75 : }
76 : }
77 : }
78 : }
79 915836 : }
80 :
81 :
82 1455609 : bool FrameElider::PropagateInOrder() {
83 : bool changed = false;
84 24920480 : for (InstructionBlock* block : instruction_blocks()) {
85 22009333 : changed |= PropagateIntoBlock(block);
86 : }
87 1455538 : return changed;
88 : }
89 :
90 :
91 915890 : bool FrameElider::PropagateReversed() {
92 : bool changed = false;
93 23838476 : for (InstructionBlock* block : base::Reversed(instruction_blocks())) {
94 11461303 : changed |= PropagateIntoBlock(block);
95 : }
96 915870 : return changed;
97 : }
98 :
99 :
100 34985051 : bool FrameElider::PropagateIntoBlock(InstructionBlock* block) {
101 : // Already marked, nothing to do...
102 33470316 : if (block->needs_frame()) return false;
103 :
104 : // Never mark the dummy end node, otherwise we might incorrectly decide to
105 : // put frame deconstruction code there later,
106 11828161 : if (block->successors().empty()) return false;
107 :
108 : // Propagate towards the end ("downwards") if there is a predecessor needing
109 : // a frame, but don't "bleed" from deferred code to non-deferred code.
110 23257909 : for (RpoNumber& pred : block->predecessors()) {
111 26824217 : if (InstructionBlockAt(pred)->needs_frame() &&
112 7821095 : (!InstructionBlockAt(pred)->IsDeferred() || block->IsDeferred())) {
113 : block->mark_needs_frame();
114 : return true;
115 : }
116 : }
117 :
118 : // Propagate towards start ("upwards")
119 : bool need_frame_successors = false;
120 3536616 : if (block->SuccessorCount() == 1) {
121 : // For single successors, propagate the needs_frame information.
122 : need_frame_successors =
123 2160174 : InstructionBlockAt(block->successors()[0])->needs_frame();
124 : } else {
125 : // For multiple successors, each successor must only have a single
126 : // predecessor (because the graph is in edge-split form), so each successor
127 : // can independently create/dismantle a frame if needed. Given this
128 : // independent control, only propagate needs_frame if all non-deferred
129 : // blocks need a frame.
130 1634438 : for (RpoNumber& succ : block->successors()) {
131 2994884 : InstructionBlock* successor_block = InstructionBlockAt(succ);
132 : DCHECK_EQ(1, successor_block->PredecessorCount());
133 1615828 : if (!successor_block->IsDeferred()) {
134 1379056 : if (successor_block->needs_frame()) {
135 : need_frame_successors = true;
136 : } else {
137 : return false;
138 : }
139 : }
140 : }
141 : }
142 2178819 : if (need_frame_successors) {
143 : block->mark_needs_frame();
144 37404 : return true;
145 : } else {
146 : return false;
147 : }
148 : }
149 :
150 :
151 0 : const InstructionBlocks& FrameElider::instruction_blocks() const {
152 4203336 : return code_->instruction_blocks();
153 : }
154 :
155 :
156 0 : InstructionBlock* FrameElider::InstructionBlockAt(RpoNumber rpo_number) const {
157 34700191 : return code_->InstructionBlockAt(rpo_number);
158 : }
159 :
160 :
161 22205256 : Instruction* FrameElider::InstructionAt(int index) const {
162 44410503 : return code_->InstructionAt(index);
163 : }
164 :
165 : } // namespace compiler
166 : } // namespace internal
167 : } // namespace v8
|