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