usage-analyzer.cc revision a7e24c173cf37484693b9abb38e494fa7bd7baeb
1// Copyright 2006-2008 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
28#include "v8.h"
29
30#include "ast.h"
31#include "scopes.h"
32#include "usage-analyzer.h"
33
34namespace v8 {
35namespace internal {
36
37// Weight boundaries
38static const int MinWeight = 1;
39static const int MaxWeight = 1000000;
40static const int InitialWeight = 100;
41
42
43class UsageComputer: public AstVisitor {
44 public:
45  static bool Traverse(AstNode* node);
46
47  // AST node visit functions.
48#define DECLARE_VISIT(type) void Visit##type(type* node);
49  AST_NODE_LIST(DECLARE_VISIT)
50#undef DECLARE_VISIT
51
52  void VisitVariable(Variable* var);
53
54 private:
55  int weight_;
56  bool is_write_;
57
58  UsageComputer(int weight, bool is_write);
59  virtual ~UsageComputer();
60
61  // Helper functions
62  void RecordUses(UseCount* uses);
63  void Read(Expression* x);
64  void Write(Expression* x);
65  void ReadList(ZoneList<Expression*>* list);
66  void ReadList(ZoneList<ObjectLiteral::Property*>* list);
67
68  friend class WeightScaler;
69};
70
71
72class WeightScaler BASE_EMBEDDED {
73 public:
74  WeightScaler(UsageComputer* uc, float scale);
75  ~WeightScaler();
76
77 private:
78  UsageComputer* uc_;
79  int old_weight_;
80};
81
82
83// ----------------------------------------------------------------------------
84// Implementation of UsageComputer
85
86bool UsageComputer::Traverse(AstNode* node) {
87  UsageComputer uc(InitialWeight, false);
88  uc.Visit(node);
89  return !uc.HasStackOverflow();
90}
91
92
93void UsageComputer::VisitBlock(Block* node) {
94  VisitStatements(node->statements());
95}
96
97
98void UsageComputer::VisitDeclaration(Declaration* node) {
99  Write(node->proxy());
100  if (node->fun() != NULL)
101    VisitFunctionLiteral(node->fun());
102}
103
104
105void UsageComputer::VisitExpressionStatement(ExpressionStatement* node) {
106  Visit(node->expression());
107}
108
109
110void UsageComputer::VisitEmptyStatement(EmptyStatement* node) {
111  // nothing to do
112}
113
114
115void UsageComputer::VisitIfStatement(IfStatement* node) {
116  Read(node->condition());
117  { WeightScaler ws(this, 0.5);  // executed 50% of the time
118    Visit(node->then_statement());
119    Visit(node->else_statement());
120  }
121}
122
123
124void UsageComputer::VisitContinueStatement(ContinueStatement* node) {
125  // nothing to do
126}
127
128
129void UsageComputer::VisitBreakStatement(BreakStatement* node) {
130  // nothing to do
131}
132
133
134void UsageComputer::VisitReturnStatement(ReturnStatement* node) {
135  Read(node->expression());
136}
137
138
139void UsageComputer::VisitWithEnterStatement(WithEnterStatement* node) {
140  Read(node->expression());
141}
142
143
144void UsageComputer::VisitWithExitStatement(WithExitStatement* node) {
145  // nothing to do
146}
147
148
149void UsageComputer::VisitSwitchStatement(SwitchStatement* node) {
150  Read(node->tag());
151  ZoneList<CaseClause*>* cases = node->cases();
152  for (int i = cases->length(); i-- > 0;) {
153    WeightScaler ws(this, static_cast<float>(1.0 / cases->length()));
154    CaseClause* clause = cases->at(i);
155    if (!clause->is_default())
156      Read(clause->label());
157    VisitStatements(clause->statements());
158  }
159}
160
161
162void UsageComputer::VisitLoopStatement(LoopStatement* node) {
163  if (node->init() != NULL)
164    Visit(node->init());
165  { WeightScaler ws(this, 10.0);  // executed in each iteration
166    if (node->cond() != NULL)
167      Read(node->cond());
168    if (node->next() != NULL)
169      Visit(node->next());
170    Visit(node->body());
171  }
172}
173
174
175void UsageComputer::VisitForInStatement(ForInStatement* node) {
176  WeightScaler ws(this, 10.0);
177  Write(node->each());
178  Read(node->enumerable());
179  Visit(node->body());
180}
181
182
183void UsageComputer::VisitTryCatch(TryCatch* node) {
184  Visit(node->try_block());
185  { WeightScaler ws(this, 0.25);
186    Write(node->catch_var());
187    Visit(node->catch_block());
188  }
189}
190
191
192void UsageComputer::VisitTryFinally(TryFinally* node) {
193  Visit(node->try_block());
194  Visit(node->finally_block());
195}
196
197
198void UsageComputer::VisitDebuggerStatement(DebuggerStatement* node) {
199}
200
201
202void UsageComputer::VisitFunctionLiteral(FunctionLiteral* node) {
203  ZoneList<Declaration*>* decls = node->scope()->declarations();
204  for (int i = 0; i < decls->length(); i++) VisitDeclaration(decls->at(i));
205  VisitStatements(node->body());
206}
207
208
209void UsageComputer::VisitFunctionBoilerplateLiteral(
210    FunctionBoilerplateLiteral* node) {
211  // Do nothing.
212}
213
214
215void UsageComputer::VisitConditional(Conditional* node) {
216  Read(node->condition());
217  { WeightScaler ws(this, 0.5);
218    Read(node->then_expression());
219    Read(node->else_expression());
220  }
221}
222
223
224void UsageComputer::VisitSlot(Slot* node) {
225  UNREACHABLE();
226}
227
228
229void UsageComputer::VisitVariable(Variable* node) {
230  RecordUses(node->var_uses());
231}
232
233
234void UsageComputer::VisitVariableProxy(VariableProxy* node) {
235  // The proxy may refer to a variable in which case it was bound via
236  // VariableProxy::BindTo.
237  RecordUses(node->var_uses());
238}
239
240
241void UsageComputer::VisitLiteral(Literal* node) {
242  // nothing to do
243}
244
245void UsageComputer::VisitRegExpLiteral(RegExpLiteral* node) {
246  // nothing to do
247}
248
249
250void UsageComputer::VisitObjectLiteral(ObjectLiteral* node) {
251  ReadList(node->properties());
252}
253
254
255void UsageComputer::VisitArrayLiteral(ArrayLiteral* node) {
256  ReadList(node->values());
257}
258
259
260void UsageComputer::VisitCatchExtensionObject(CatchExtensionObject* node) {
261  Read(node->value());
262}
263
264
265void UsageComputer::VisitAssignment(Assignment* node) {
266  if (node->op() != Token::ASSIGN)
267    Read(node->target());
268  Write(node->target());
269  Read(node->value());
270}
271
272
273void UsageComputer::VisitThrow(Throw* node) {
274  Read(node->exception());
275}
276
277
278void UsageComputer::VisitProperty(Property* node) {
279  // In any case (read or write) we read both the
280  // node's object and the key.
281  Read(node->obj());
282  Read(node->key());
283  // If the node's object is a variable proxy,
284  // we have a 'simple' object property access. We count
285  // the access via the variable or proxy's object uses.
286  VariableProxy* proxy = node->obj()->AsVariableProxy();
287  if (proxy != NULL) {
288    RecordUses(proxy->obj_uses());
289  }
290}
291
292
293void UsageComputer::VisitCall(Call* node) {
294  Read(node->expression());
295  ReadList(node->arguments());
296}
297
298
299void UsageComputer::VisitCallNew(CallNew* node) {
300  Read(node->expression());
301  ReadList(node->arguments());
302}
303
304
305void UsageComputer::VisitCallRuntime(CallRuntime* node) {
306  ReadList(node->arguments());
307}
308
309
310void UsageComputer::VisitUnaryOperation(UnaryOperation* node) {
311  Read(node->expression());
312}
313
314
315void UsageComputer::VisitCountOperation(CountOperation* node) {
316  Read(node->expression());
317  Write(node->expression());
318}
319
320
321void UsageComputer::VisitBinaryOperation(BinaryOperation* node) {
322  Read(node->left());
323  Read(node->right());
324}
325
326
327void UsageComputer::VisitCompareOperation(CompareOperation* node) {
328  Read(node->left());
329  Read(node->right());
330}
331
332
333void UsageComputer::VisitThisFunction(ThisFunction* node) {
334}
335
336
337UsageComputer::UsageComputer(int weight, bool is_write) {
338  weight_ = weight;
339  is_write_ = is_write;
340}
341
342
343UsageComputer::~UsageComputer() {
344  // nothing to do
345}
346
347
348void UsageComputer::RecordUses(UseCount* uses) {
349  if (is_write_)
350    uses->RecordWrite(weight_);
351  else
352    uses->RecordRead(weight_);
353}
354
355
356void UsageComputer::Read(Expression* x) {
357  if (is_write_) {
358    UsageComputer uc(weight_, false);
359    uc.Visit(x);
360  } else {
361    Visit(x);
362  }
363}
364
365
366void UsageComputer::Write(Expression* x) {
367  if (!is_write_) {
368    UsageComputer uc(weight_, true);
369    uc.Visit(x);
370  } else {
371    Visit(x);
372  }
373}
374
375
376void UsageComputer::ReadList(ZoneList<Expression*>* list) {
377  for (int i = list->length(); i-- > 0; )
378    Read(list->at(i));
379}
380
381
382void UsageComputer::ReadList(ZoneList<ObjectLiteral::Property*>* list) {
383  for (int i = list->length(); i-- > 0; )
384    Read(list->at(i)->value());
385}
386
387
388// ----------------------------------------------------------------------------
389// Implementation of WeightScaler
390
391WeightScaler::WeightScaler(UsageComputer* uc, float scale) {
392  uc_ = uc;
393  old_weight_ = uc->weight_;
394  int new_weight = static_cast<int>(uc->weight_ * scale);
395  if (new_weight <= 0) new_weight = MinWeight;
396  else if (new_weight > MaxWeight) new_weight = MaxWeight;
397  uc->weight_ = new_weight;
398}
399
400
401WeightScaler::~WeightScaler() {
402  uc_->weight_ = old_weight_;
403}
404
405
406// ----------------------------------------------------------------------------
407// Interface to variable usage analysis
408
409bool AnalyzeVariableUsage(FunctionLiteral* lit) {
410  if (!FLAG_usage_computation) return true;
411  HistogramTimerScope timer(&Counters::usage_analysis);
412  return UsageComputer::Traverse(lit);
413}
414
415} }  // namespace v8::internal
416