• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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:
State(Zone * zone)16   explicit State(Zone* zone)
17       : zone_(zone), mergelist_(2, zone), first_(true), mode_(NORMAL) { }
18 
Process(HInstruction * instr,Zone * zone)19   State* Process(HInstruction* instr, Zone* zone) {
20     if (FLAG_trace_removable_simulates) {
21       PrintF("[%s with state %p in B%d: #%d %s]\n",
22              mode_ == NORMAL ? "processing" : "collecting",
23              reinterpret_cast<void*>(this), instr->block()->block_id(),
24              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     if (mode_ == COLLECT_CONSECUTIVE_SIMULATES) {
29       if (instr->IsSimulate()) {
30         HSimulate* current_simulate = HSimulate::cast(instr);
31         if (current_simulate->is_candidate_for_removal() &&
32             !current_simulate->ast_id().IsNone()) {
33           Remember(current_simulate);
34           return this;
35         }
36       }
37       FlushSimulates();
38       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     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       RemoveSimulates();
51       return this;
52     }
53     if (instr->IsControlInstruction()) {
54       // Merge the accumulated simulates at the end of the block.
55       FlushSimulates();
56       return this;
57     }
58     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       FlushSimulates();
63       return this;
64     }
65     // Skip the non-simulates and the first simulate.
66     if (!instr->IsSimulate()) return this;
67     if (first_) {
68       first_ = false;
69       return this;
70     }
71     HSimulate* current_simulate = HSimulate::cast(instr);
72     if (!current_simulate->is_candidate_for_removal()) {
73       Remember(current_simulate);
74       FlushSimulates();
75     } else if (current_simulate->ast_id().IsNone()) {
76       DCHECK(current_simulate->next()->IsEnterInlined());
77       FlushSimulates();
78     } else if (current_simulate->previous()->HasObservableSideEffects()) {
79       Remember(current_simulate);
80       mode_ = COLLECT_CONSECUTIVE_SIMULATES;
81     } else {
82       Remember(current_simulate);
83     }
84 
85     return this;
86   }
87 
Merge(State * succ_state,HBasicBlock * succ_block,State * pred_state,HBasicBlock * pred_block,Zone * zone)88   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         : succ_state->Merge(succ_block, pred_state, pred_block, zone);
96   }
97 
Finish(State * state,HBasicBlock * block,Zone * zone)98   static State* Finish(State* state, HBasicBlock* block, Zone* zone) {
99     if (FLAG_trace_removable_simulates) {
100       PrintF("[preparing state %p for B%d]\n", reinterpret_cast<void*>(state),
101              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     state->first_ = true;
109     return state;
110   }
111 
112  private:
State(const State & other)113   explicit State(const State& other)
114       : zone_(other.zone_),
115         mergelist_(other.mergelist_, other.zone_),
116         first_(other.first_),
117         mode_(other.mode_) { }
118 
119   enum Mode { NORMAL, COLLECT_CONSECUTIVE_SIMULATES };
120 
HasRememberedSimulates() const121   bool HasRememberedSimulates() const { return !mergelist_.is_empty(); }
122 
Remember(HSimulate * sim)123   void Remember(HSimulate* sim) {
124     mergelist_.Add(sim, zone_);
125   }
126 
FlushSimulates()127   void FlushSimulates() {
128     if (HasRememberedSimulates()) {
129       mergelist_.RemoveLast()->MergeWith(&mergelist_);
130     }
131   }
132 
RemoveSimulates()133   void RemoveSimulates() {
134     while (HasRememberedSimulates()) {
135       mergelist_.RemoveLast()->DeleteAndReplaceWith(NULL);
136     }
137   }
138 
Copy(HBasicBlock * succ_block,HBasicBlock * pred_block,Zone * zone)139   State* Copy(HBasicBlock* succ_block, HBasicBlock* pred_block, Zone* zone) {
140     State* copy = new(zone) State(*this);
141     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              reinterpret_cast<void*>(copy), succ_block->block_id());
145     }
146     return copy;
147   }
148 
Merge(HBasicBlock * succ_block,State * pred_state,HBasicBlock * pred_block,Zone * zone)149   State* Merge(HBasicBlock* succ_block,
150                State* pred_state,
151                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     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              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:
Effects(Zone * zone)175   explicit Effects(Zone* zone) { }
Disabled()176   bool Disabled() { return true; }
Process(HInstruction * instr,Zone * zone)177   void Process(HInstruction* instr, Zone* zone) { }
Apply(State * state)178   void Apply(State* state) { }
Union(Effects * that,Zone * zone)179   void Union(Effects* that, Zone* zone) { }
180 };
181 
182 
Run()183 void HMergeRemovableSimulatesPhase::Run() {
184   HFlowEngine<State, Effects> engine(graph(), zone());
185   State* state = new(zone()) State(zone());
186   engine.AnalyzeDominatedBlocks(graph()->blocks()->at(0), state);
187 }
188 
189 }  // namespace internal
190 }  // namespace v8
191