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