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