V8 Project
hydrogen-environment-liveness.cc
Go to the documentation of this file.
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 
7 
8 
9 namespace v8 {
10 namespace internal {
11 
12 
14  HGraph* graph)
15  : HPhase("H_Environment liveness analysis", graph),
16  block_count_(graph->blocks()->length()),
17  maximum_environment_size_(graph->maximum_environment_size()),
18  live_at_block_start_(block_count_, zone()),
19  first_simulate_(block_count_, zone()),
20  first_simulate_invalid_for_index_(block_count_, zone()),
21  markers_(maximum_environment_size_, zone()),
22  collect_markers_(true),
23  last_simulate_(NULL),
24  went_live_since_last_simulate_(maximum_environment_size_, zone()) {
26  for (int i = 0; i < block_count_; ++i) {
28  new(zone()) BitVector(maximum_environment_size_, zone()), zone());
29  first_simulate_.Add(NULL, zone());
31  new(zone()) BitVector(maximum_environment_size_, zone()), zone());
32  }
33 }
34 
35 
37  int index, HSimulate* simulate) {
38  int operand_index = simulate->ToOperandIndex(index);
39  if (operand_index == -1) {
40  simulate->AddAssignedValue(index, graph()->GetConstantUndefined());
41  } else {
42  simulate->SetOperandAt(operand_index, graph()->GetConstantUndefined());
43  }
44 }
45 
46 
48  HBasicBlock* block, BitVector* live) {
49  // When a value is live in successor A but dead in B, we must
50  // explicitly zap it in B.
51  for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
52  HBasicBlock* successor = it.Current();
53  int successor_id = successor->block_id();
54  BitVector* live_in_successor = live_at_block_start_[successor_id];
55  if (live_in_successor->Equals(*live)) continue;
56  for (int i = 0; i < live->length(); ++i) {
57  if (!live->Contains(i)) continue;
58  if (live_in_successor->Contains(i)) continue;
59  if (first_simulate_invalid_for_index_.at(successor_id)->Contains(i)) {
60  continue;
61  }
62  HSimulate* simulate = first_simulate_.at(successor_id);
63  if (simulate == NULL) continue;
64  DCHECK(VerifyClosures(simulate->closure(),
65  block->last_environment()->closure()));
66  ZapEnvironmentSlot(i, simulate);
67  }
68  }
69 }
70 
71 
73  HEnvironmentMarker* marker) {
74  if (!marker->CheckFlag(HValue::kEndsLiveRange)) return;
75  HSimulate* simulate = marker->next_simulate();
76  if (simulate != NULL) {
77  DCHECK(VerifyClosures(simulate->closure(), marker->closure()));
78  ZapEnvironmentSlot(marker->index(), simulate);
79  }
80 }
81 
82 
84  HBasicBlock* block,
85  BitVector* live) {
86  // Liveness at the end of each block: union of liveness in successors.
87  live->Clear();
88  for (HSuccessorIterator it(block->end()); !it.Done(); it.Advance()) {
89  live->Union(*live_at_block_start_[it.Current()->block_id()]);
90  }
91 }
92 
93 
95  HInstruction* instr,
96  BitVector* live) {
97  switch (instr->opcode()) {
98  case HValue::kEnvironmentMarker: {
99  HEnvironmentMarker* marker = HEnvironmentMarker::cast(instr);
100  int index = marker->index();
101  if (!live->Contains(index)) {
102  marker->SetFlag(HValue::kEndsLiveRange);
103  } else {
104  marker->ClearFlag(HValue::kEndsLiveRange);
105  }
107  marker->set_next_simulate(last_simulate_);
108  }
109  if (marker->kind() == HEnvironmentMarker::LOOKUP) {
110  live->Add(index);
111  } else {
112  DCHECK(marker->kind() == HEnvironmentMarker::BIND);
113  live->Remove(index);
115  }
116  if (collect_markers_) {
117  // Populate |markers_| list during the first pass.
118  markers_.Add(marker, zone());
119  }
120  break;
121  }
122  case HValue::kLeaveInlined:
123  // No environment values are live at the end of an inlined section.
124  live->Clear();
126 
127  // The following DCHECKs guard the assumption used in case
128  // kEnterInlined below:
129  DCHECK(instr->next()->IsSimulate());
130  DCHECK(instr->next()->next()->IsGoto());
131 
132  break;
133  case HValue::kEnterInlined: {
134  // Those environment values are live that are live at any return
135  // target block. Here we make use of the fact that the end of an
136  // inline sequence always looks like this: HLeaveInlined, HSimulate,
137  // HGoto (to return_target block), with no environment lookups in
138  // between (see DCHECKs above).
139  HEnterInlined* enter = HEnterInlined::cast(instr);
140  live->Clear();
141  for (int i = 0; i < enter->return_targets()->length(); ++i) {
142  int return_id = enter->return_targets()->at(i)->block_id();
143  live->Union(*live_at_block_start_[return_id]);
144  }
146  break;
147  }
148  case HValue::kSimulate:
149  last_simulate_ = HSimulate::cast(instr);
151  break;
152  default:
153  break;
154  }
155 }
156 
157 
160 
161  // Main iteration. Compute liveness of environment slots, and store it
162  // for each block until it doesn't change any more. For efficiency, visit
163  // blocks in reverse order and walk backwards through each block. We
164  // need several iterations to propagate liveness through nested loops.
165  BitVector live(maximum_environment_size_, zone());
166  BitVector worklist(block_count_, zone());
167  for (int i = 0; i < block_count_; ++i) {
168  worklist.Add(i);
169  }
170  while (!worklist.IsEmpty()) {
171  for (int block_id = block_count_ - 1; block_id >= 0; --block_id) {
172  if (!worklist.Contains(block_id)) {
173  continue;
174  }
175  worklist.Remove(block_id);
177 
178  HBasicBlock* block = graph()->blocks()->at(block_id);
179  UpdateLivenessAtBlockEnd(block, &live);
180 
181  for (HInstruction* instr = block->end(); instr != NULL;
182  instr = instr->previous()) {
183  UpdateLivenessAtInstruction(instr, &live);
184  }
185 
186  // Reached the start of the block, do necessary bookkeeping:
187  // store computed information for this block and add predecessors
188  // to the work list as necessary.
190  first_simulate_invalid_for_index_[block_id]->CopyFrom(
192  if (live_at_block_start_[block_id]->UnionIsChanged(live)) {
193  for (int i = 0; i < block->predecessors()->length(); ++i) {
194  worklist.Add(block->predecessors()->at(i)->block_id());
195  }
196  if (block->IsInlineReturnTarget()) {
197  worklist.Add(block->inlined_entry_block()->block_id());
198  }
199  }
200  }
201  // Only collect bind/lookup instructions during the first pass.
202  collect_markers_ = false;
203  }
204 
205  // Analysis finished. Zap dead environment slots.
206  for (int i = 0; i < markers_.length(); ++i) {
208  }
209  for (int block_id = block_count_ - 1; block_id >= 0; --block_id) {
210  HBasicBlock* block = graph()->blocks()->at(block_id);
211  UpdateLivenessAtBlockEnd(block, &live);
212  ZapEnvironmentSlotsInSuccessors(block, &live);
213  }
214 
215  // Finally, remove the HEnvironment{Bind,Lookup} markers.
216  for (int i = 0; i < markers_.length(); ++i) {
217  markers_[i]->DeleteAndReplaceWith(NULL);
218  }
219 }
220 
221 
222 #ifdef DEBUG
223 bool HEnvironmentLivenessAnalysisPhase::VerifyClosures(
225  Heap::RelocationLock for_heap_access(isolate()->heap());
226  AllowHandleDereference for_verification;
227  return a.is_identical_to(b);
228 }
229 #endif
230 
231 } } // namespace v8::internal
bool Contains(int i) const
Definition: data-flow.h:99
void Union(const BitVector &other)
Definition: data-flow.h:115
bool IsEmpty() const
Definition: data-flow.h:164
bool Equals(const BitVector &other)
Definition: data-flow.h:171
void UpdateLivenessAtInstruction(HInstruction *instr, BitVector *live)
void UpdateLivenessAtBlockEnd(HBasicBlock *block, BitVector *live)
void ZapEnvironmentSlotsInSuccessors(HBasicBlock *block, BitVector *live)
void ZapEnvironmentSlotsForInstruction(HEnvironmentMarker *marker)
HGraph * graph() const
Definition: hydrogen.h:2802
virtual Opcode opcode() const =0
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Definition: list-inl.h:17
void Set(int index, const T &element)
Definition: list-inl.h:85
T & at(int i) const
Definition: list.h:69
enable harmony numeric enable harmony object literal extensions true
enable harmony numeric enable harmony object literal extensions Optimize object Array DOM strings and string trace pretenuring decisions of HAllocate instructions Enables optimizations which favor memory size over execution speed maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining trace the tracking of allocation sites deoptimize every n garbage collections perform array bounds checks elimination analyze liveness of environment slots and zap dead values flushes the cache of optimized code for closures on every GC allow uint32 values on optimize frames if they are used only in safe operations track concurrent recompilation artificial compilation delay in ms do not emit check maps for constant values that have a leaf deoptimize the optimized code if the layout of the maps changes enable context specialization in TurboFan execution budget before interrupt is triggered max percentage of megamorphic generic ICs to allow optimization enable use of SAHF instruction if enable use of VFP3 instructions if available enable use of NEON instructions if enable use of SDIV and UDIV instructions if enable use of MLS instructions if enable loading bit constant by means of movw movt instruction enable unaligned accesses for enable use of d16 d31 registers on ARM this requires VFP3 force all emitted branches to be in long enable alignment of csp to bytes on platforms which prefer the register to always be NULL
#define DCHECK(condition)
Definition: logging.h:205
Debugger support for the V8 JavaScript engine.
Definition: accessors.cc:20