Line data Source code
1 : // Copyright 2013 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/crankshaft/hydrogen-removable-simulates.h"
6 :
7 : #include "src/crankshaft/hydrogen-flow-engine.h"
8 : #include "src/crankshaft/hydrogen-instructions.h"
9 : #include "src/objects-inl.h"
10 :
11 : namespace v8 {
12 : namespace internal {
13 :
14 : class State : public ZoneObject {
15 : public:
16 : explicit State(Zone* zone)
17 283730 : : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { }
18 :
19 23987620 : State* Process(HInstruction* instr, Zone* zone) {
20 23987620 : if (FLAG_trace_removable_simulates) {
21 : PrintF("[%s with state %p in B%d: #%d %s]\n",
22 0 : mode_ == NORMAL ? "processing" : "collecting",
23 : reinterpret_cast<void*>(this), instr->block()->block_id(),
24 0 : instr->id(), instr->Mnemonic());
25 : }
26 : // Forward-merge "trains" of simulates after an instruction with observable
27 : // side effects to keep live ranges short.
28 23987668 : if (mode_ == COLLECT_CONSECUTIVE_SIMULATES) {
29 1934946 : if (instr->IsSimulate()) {
30 62794 : HSimulate* current_simulate = HSimulate::cast(instr);
31 62794 : if (current_simulate->is_candidate_for_removal() &&
32 : !current_simulate->ast_id().IsNone()) {
33 : Remember(current_simulate);
34 2308 : return this;
35 : }
36 : }
37 965165 : FlushSimulates();
38 965164 : mode_ = NORMAL;
39 : }
40 : // Ensure there's a non-foldable HSimulate before an HEnterInlined to avoid
41 : // folding across HEnterInlined.
42 : DCHECK(!(instr->IsEnterInlined() &&
43 : HSimulate::cast(instr->previous())->is_candidate_for_removal()));
44 71684629 : if (instr->IsLeaveInlined() || instr->IsReturn()) {
45 : // Never fold simulates from inlined environments into simulates in the
46 : // outer environment. Simply remove all accumulated simulates without
47 : // merging. This is safe because simulates after instructions with side
48 : // effects are never added to the merge list. The same reasoning holds for
49 : // return instructions.
50 631380 : RemoveSimulates();
51 631380 : return this;
52 : }
53 23353991 : if (instr->IsControlInstruction()) {
54 : // Merge the accumulated simulates at the end of the block.
55 3113796 : FlushSimulates();
56 3113793 : return this;
57 : }
58 20240506 : if (instr->IsCapturedObject()) {
59 : // Do not merge simulates across captured objects - captured objects
60 : // change environments during environment replay, and such changes
61 : // would not be reflected in the simulate.
62 7768 : FlushSimulates();
63 7768 : return this;
64 : }
65 : // Skip the non-simulates and the first simulate.
66 20232725 : if (!instr->IsSimulate()) return this;
67 3975416 : if (first_) {
68 2526423 : first_ = false;
69 2526423 : return this;
70 : }
71 1448993 : HSimulate* current_simulate = HSimulate::cast(instr);
72 1448993 : if (!current_simulate->is_candidate_for_removal()) {
73 : Remember(current_simulate);
74 275377 : FlushSimulates();
75 1173617 : } else if (current_simulate->ast_id().IsNone()) {
76 : DCHECK(current_simulate->next()->IsEnterInlined());
77 0 : FlushSimulates();
78 2347234 : } else if (current_simulate->previous()->HasObservableSideEffects()) {
79 : Remember(current_simulate);
80 965165 : mode_ = COLLECT_CONSECUTIVE_SIMULATES;
81 : } else {
82 : Remember(current_simulate);
83 : }
84 :
85 : return this;
86 : }
87 :
88 3289206 : static State* Merge(State* succ_state,
89 : HBasicBlock* succ_block,
90 : State* pred_state,
91 : HBasicBlock* pred_block,
92 : Zone* zone) {
93 : return (succ_state == NULL)
94 : ? pred_state->Copy(succ_block, pred_block, zone)
95 6578418 : : succ_state->Merge(succ_block, pred_state, pred_block, zone);
96 : }
97 :
98 : static State* Finish(State* state, HBasicBlock* block, Zone* zone) {
99 4511617 : if (FLAG_trace_removable_simulates) {
100 : PrintF("[preparing state %p for B%d]\n", reinterpret_cast<void*>(state),
101 0 : block->block_id());
102 : }
103 : // For our current local analysis, we should not remember simulates across
104 : // block boundaries.
105 : DCHECK(!state->HasRememberedSimulates());
106 : // Nasty heuristic: Never remove the first simulate in a block. This
107 : // just so happens to have a beneficial effect on register allocation.
108 4511639 : state->first_ = true;
109 : return state;
110 : }
111 :
112 : private:
113 : explicit State(const State& other)
114 : : zone_(other.zone_),
115 : mergelist_(other.mergelist_, other.zone_),
116 : first_(other.first_),
117 2406543 : mode_(other.mode_) { }
118 :
119 : enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES };
120 :
121 5090658 : bool HasRememberedSimulates() const { return !mergelist_.is_empty(); }
122 :
123 : void Remember(HSimulate* sim) {
124 1451301 : mergelist_.Add(sim, zone_);
125 : }
126 :
127 4362096 : void FlushSimulates() {
128 4362096 : if (HasRememberedSimulates()) {
129 2554542 : mergelist_.RemoveLast()->MergeWith(&mergelist_);
130 : }
131 4362094 : }
132 :
133 631380 : void RemoveSimulates() {
134 1359942 : while (HasRememberedSimulates()) {
135 194364 : mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL);
136 : }
137 631380 : }
138 :
139 2406542 : State* Copy(HBasicBlock* succ_block, HBasicBlock* pred_block, Zone* zone) {
140 : State* copy = new(zone) State(*this);
141 2406551 : if (FLAG_trace_removable_simulates) {
142 : PrintF("[copy state %p from B%d to new state %p for B%d]\n",
143 : reinterpret_cast<void*>(this), pred_block->block_id(),
144 0 : reinterpret_cast<void*>(copy), succ_block->block_id());
145 : }
146 2406551 : return copy;
147 : }
148 :
149 0 : State* Merge(HBasicBlock* succ_block,
150 : State* pred_state,
151 0 : HBasicBlock* pred_block,
152 : Zone* zone) {
153 : // For our current local analysis, we should not remember simulates across
154 : // block boundaries.
155 : DCHECK(!pred_state->HasRememberedSimulates());
156 : DCHECK(!HasRememberedSimulates());
157 882664 : if (FLAG_trace_removable_simulates) {
158 : PrintF("[merge state %p from B%d into %p for B%d]\n",
159 : reinterpret_cast<void*>(pred_state), pred_block->block_id(),
160 0 : reinterpret_cast<void*>(this), succ_block->block_id());
161 : }
162 : return this;
163 : }
164 :
165 : Zone* zone_;
166 : ZoneList<HSimulate*> mergelist_;
167 : bool first_;
168 : Mode mode_;
169 : };
170 :
171 :
172 : // We don't use effects here.
173 : class Effects : public ZoneObject {
174 : public:
175 : explicit Effects(Zone* zone) { }
176 : bool Disabled() { return true; }
177 : void Process(HInstruction* instr, Zone* zone) { }
178 : void Apply(State* state) { }
179 : void Union(Effects* that, Zone* zone) { }
180 : };
181 :
182 :
183 283729 : void HMergeRemovableSimulatesPhase::Run() {
184 567458 : HFlowEngine<State, Effects> engine(graph(), zone());
185 : State* state = new(zone()) State(zone());
186 283729 : engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state);
187 283728 : }
188 :
189 : } // namespace internal
190 : } // namespace v8
|