v8  3.25.30(node0.11.13)
V8 is Google's open source JavaScript engine
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
hydrogen-range-analysis.cc
Go to the documentation of this file.
1 // Copyright 2013 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are
4 // met:
5 //
6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission.
15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 
29 
30 namespace v8 {
31 namespace internal {
32 
33 
34 class Pending {
35  public:
36  Pending(HBasicBlock* block, int last_changed_range)
37  : block_(block), last_changed_range_(last_changed_range) {}
38 
39  HBasicBlock* block() const { return block_; }
40  int last_changed_range() const { return last_changed_range_; }
41 
42  private:
43  HBasicBlock* block_;
44  int last_changed_range_;
45 };
46 
47 
48 void HRangeAnalysisPhase::TraceRange(const char* msg, ...) {
49  if (FLAG_trace_range) {
50  va_list arguments;
51  va_start(arguments, msg);
52  OS::VPrint(msg, arguments);
53  va_end(arguments);
54  }
55 }
56 
57 
59  HBasicBlock* block(graph()->entry_block());
60  ZoneList<Pending> stack(graph()->blocks()->length(), zone());
61  while (block != NULL) {
62  TraceRange("Analyzing block B%d\n", block->block_id());
63 
64  // Infer range based on control flow.
65  if (block->predecessors()->length() == 1) {
66  HBasicBlock* pred = block->predecessors()->first();
67  if (pred->end()->IsCompareNumericAndBranch()) {
68  InferControlFlowRange(HCompareNumericAndBranch::cast(pred->end()),
69  block);
70  }
71  }
72 
73  // Process phi instructions.
74  for (int i = 0; i < block->phis()->length(); ++i) {
75  HPhi* phi = block->phis()->at(i);
76  InferRange(phi);
77  }
78 
79  // Go through all instructions of the current block.
80  for (HInstructionIterator it(block); !it.Done(); it.Advance()) {
81  HValue* value = it.Current();
82  InferRange(value);
83 
84  // Compute the bailout-on-minus-zero flag.
85  if (value->IsChange()) {
86  HChange* instr = HChange::cast(value);
87  // Propagate flags for negative zero checks upwards from conversions
88  // int32-to-tagged and int32-to-double.
89  Representation from = instr->value()->representation();
90  ASSERT(from.Equals(instr->from()));
91  if (from.IsSmiOrInteger32()) {
92  ASSERT(instr->to().IsTagged() ||
93  instr->to().IsDouble() ||
94  instr->to().IsSmiOrInteger32());
95  PropagateMinusZeroChecks(instr->value());
96  }
97  } else if (value->IsCompareMinusZeroAndBranch()) {
98  HCompareMinusZeroAndBranch* instr =
99  HCompareMinusZeroAndBranch::cast(value);
100  if (instr->value()->representation().IsSmiOrInteger32()) {
101  PropagateMinusZeroChecks(instr->value());
102  }
103  }
104  }
105 
106  // Continue analysis in all dominated blocks.
107  const ZoneList<HBasicBlock*>* dominated_blocks(block->dominated_blocks());
108  if (!dominated_blocks->is_empty()) {
109  // Continue with first dominated block, and push the
110  // remaining blocks on the stack (in reverse order).
111  int last_changed_range = changed_ranges_.length();
112  for (int i = dominated_blocks->length() - 1; i > 0; --i) {
113  stack.Add(Pending(dominated_blocks->at(i), last_changed_range), zone());
114  }
115  block = dominated_blocks->at(0);
116  } else if (!stack.is_empty()) {
117  // Pop next pending block from stack.
118  Pending pending = stack.RemoveLast();
119  RollBackTo(pending.last_changed_range());
120  block = pending.block();
121  } else {
122  // All blocks done.
123  block = NULL;
124  }
125  }
126 }
127 
128 
129 void HRangeAnalysisPhase::InferControlFlowRange(HCompareNumericAndBranch* test,
130  HBasicBlock* dest) {
131  ASSERT((test->FirstSuccessor() == dest) == (test->SecondSuccessor() != dest));
132  if (test->representation().IsSmiOrInteger32()) {
133  Token::Value op = test->token();
134  if (test->SecondSuccessor() == dest) {
135  op = Token::NegateCompareOp(op);
136  }
137  Token::Value inverted_op = Token::ReverseCompareOp(op);
138  UpdateControlFlowRange(op, test->left(), test->right());
139  UpdateControlFlowRange(inverted_op, test->right(), test->left());
140  }
141 }
142 
143 
144 // We know that value [op] other. Use this information to update the range on
145 // value.
146 void HRangeAnalysisPhase::UpdateControlFlowRange(Token::Value op,
147  HValue* value,
148  HValue* other) {
149  Range temp_range;
150  Range* range = other->range() != NULL ? other->range() : &temp_range;
151  Range* new_range = NULL;
152 
153  TraceRange("Control flow range infer %d %s %d\n",
154  value->id(),
155  Token::Name(op),
156  other->id());
157 
158  if (op == Token::EQ || op == Token::EQ_STRICT) {
159  // The same range has to apply for value.
160  new_range = range->Copy(graph()->zone());
161  } else if (op == Token::LT || op == Token::LTE) {
162  new_range = range->CopyClearLower(graph()->zone());
163  if (op == Token::LT) {
164  new_range->AddConstant(-1);
165  }
166  } else if (op == Token::GT || op == Token::GTE) {
167  new_range = range->CopyClearUpper(graph()->zone());
168  if (op == Token::GT) {
169  new_range->AddConstant(1);
170  }
171  }
172 
173  if (new_range != NULL && !new_range->IsMostGeneric()) {
174  AddRange(value, new_range);
175  }
176 }
177 
178 
179 void HRangeAnalysisPhase::InferRange(HValue* value) {
180  ASSERT(!value->HasRange());
181  if (!value->representation().IsNone()) {
182  value->ComputeInitialRange(graph()->zone());
183  Range* range = value->range();
184  TraceRange("Initial inferred range of %d (%s) set to [%d,%d]\n",
185  value->id(),
186  value->Mnemonic(),
187  range->lower(),
188  range->upper());
189  }
190 }
191 
192 
193 void HRangeAnalysisPhase::RollBackTo(int index) {
194  ASSERT(index <= changed_ranges_.length());
195  for (int i = index; i < changed_ranges_.length(); ++i) {
196  changed_ranges_[i]->RemoveLastAddedRange();
197  }
198  changed_ranges_.Rewind(index);
199 }
200 
201 
202 void HRangeAnalysisPhase::AddRange(HValue* value, Range* range) {
203  Range* original_range = value->range();
204  value->AddNewRange(range, graph()->zone());
205  changed_ranges_.Add(value, zone());
206  Range* new_range = value->range();
207  TraceRange("Updated range of %d set to [%d,%d]\n",
208  value->id(),
209  new_range->lower(),
210  new_range->upper());
211  if (original_range != NULL) {
212  TraceRange("Original range was [%d,%d]\n",
213  original_range->lower(),
214  original_range->upper());
215  }
216  TraceRange("New information was [%d,%d]\n",
217  range->lower(),
218  range->upper());
219 }
220 
221 
222 void HRangeAnalysisPhase::PropagateMinusZeroChecks(HValue* value) {
223  ASSERT(worklist_.is_empty());
224  ASSERT(in_worklist_.IsEmpty());
225 
226  AddToWorklist(value);
227  while (!worklist_.is_empty()) {
228  value = worklist_.RemoveLast();
229 
230  if (value->IsPhi()) {
231  // For phis, we must propagate the check to all of its inputs.
232  HPhi* phi = HPhi::cast(value);
233  for (int i = 0; i < phi->OperandCount(); ++i) {
234  AddToWorklist(phi->OperandAt(i));
235  }
236  } else if (value->IsUnaryMathOperation()) {
237  HUnaryMathOperation* instr = HUnaryMathOperation::cast(value);
238  if (instr->representation().IsSmiOrInteger32() &&
239  !instr->value()->representation().Equals(instr->representation())) {
240  if (instr->value()->range() == NULL ||
241  instr->value()->range()->CanBeMinusZero()) {
242  instr->SetFlag(HValue::kBailoutOnMinusZero);
243  }
244  }
245  if (instr->RequiredInputRepresentation(0).IsSmiOrInteger32() &&
246  instr->representation().Equals(
247  instr->RequiredInputRepresentation(0))) {
248  AddToWorklist(instr->value());
249  }
250  } else if (value->IsChange()) {
251  HChange* instr = HChange::cast(value);
252  if (!instr->from().IsSmiOrInteger32() &&
253  !instr->CanTruncateToInt32() &&
254  (instr->value()->range() == NULL ||
255  instr->value()->range()->CanBeMinusZero())) {
256  instr->SetFlag(HValue::kBailoutOnMinusZero);
257  }
258  } else if (value->IsForceRepresentation()) {
259  HForceRepresentation* instr = HForceRepresentation::cast(value);
260  AddToWorklist(instr->value());
261  } else if (value->IsMod()) {
262  HMod* instr = HMod::cast(value);
263  if (instr->range() == NULL || instr->range()->CanBeMinusZero()) {
264  instr->SetFlag(HValue::kBailoutOnMinusZero);
265  AddToWorklist(instr->left());
266  }
267  } else if (value->IsDiv() || value->IsMul()) {
268  HBinaryOperation* instr = HBinaryOperation::cast(value);
269  if (instr->range() == NULL || instr->range()->CanBeMinusZero()) {
270  instr->SetFlag(HValue::kBailoutOnMinusZero);
271  }
272  AddToWorklist(instr->right());
273  AddToWorklist(instr->left());
274  } else if (value->IsMathFloorOfDiv()) {
275  HMathFloorOfDiv* instr = HMathFloorOfDiv::cast(value);
276  instr->SetFlag(HValue::kBailoutOnMinusZero);
277  } else if (value->IsAdd() || value->IsSub()) {
278  HBinaryOperation* instr = HBinaryOperation::cast(value);
279  if (instr->range() == NULL || instr->range()->CanBeMinusZero()) {
280  // Propagate to the left argument. If the left argument cannot be -0,
281  // then the result of the add/sub operation cannot be either.
282  AddToWorklist(instr->left());
283  }
284  } else if (value->IsMathMinMax()) {
285  HMathMinMax* instr = HMathMinMax::cast(value);
286  AddToWorklist(instr->right());
287  AddToWorklist(instr->left());
288  }
289  }
290 
291  in_worklist_.Clear();
292  ASSERT(in_worklist_.IsEmpty());
293  ASSERT(worklist_.is_empty());
294 }
295 
296 
297 } } // namespace v8::internal
enable upcoming ES6 features enable harmony block scoping enable harmony enable harmony proxies enable harmony generators enable harmony numeric enable harmony string enable harmony math functions harmony_scoping harmony_symbols harmony_collections harmony_iteration harmony_strings harmony_scoping harmony_maths tracks arrays with only smi values Optimize object Array DOM strings and string pretenure call new trace pretenuring decisions of HAllocate instructions track fields with only smi values track fields with heap values track_fields track_fields Enables optimizations which favor memory size over execution speed use string slices optimization filter maximum number of GVN fix point iterations use function inlining use allocation folding eliminate write barriers targeting allocations in optimized code maximum source size in bytes considered for a single inlining maximum cumulative number of AST nodes considered for inlining crankshaft harvests type feedback from stub cache trace check elimination phase hydrogen tracing filter NULL
Definition: flags.cc:269
static const char * Name(Value tok)
Definition: token.h:198
#define ASSERT(condition)
Definition: checks.h:329
HGraph * graph() const
Definition: hydrogen.h:2695
Representation representation() const
static Value ReverseCompareOp(Value op)
Definition: token.h:258
bool IsEmpty() const
Definition: data-flow.h:176
bool Equals(const Representation &other) const
static Value NegateCompareOp(Value op)
Definition: token.h:241
static void VPrint(const char *format, va_list args)
HBasicBlock * block() const
void Add(const T &element, AllocationPolicy allocator=AllocationPolicy())
Pending(HBasicBlock *block, int last_changed_range)
static HValue * cast(HValue *value)