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