| OLD | NEW |
| 1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
| 2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
| 3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
| 4 // met: | 4 // met: |
| 5 // | 5 // |
| 6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
| 7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
| 8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
| 9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
| 10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
| 11 // with the distribution. | 11 // with the distribution. |
| (...skipping 17 matching lines...) Expand all Loading... |
| 29 | 29 |
| 30 #include "rewriter.h" | 30 #include "rewriter.h" |
| 31 | 31 |
| 32 #include "ast.h" | 32 #include "ast.h" |
| 33 #include "compiler.h" | 33 #include "compiler.h" |
| 34 #include "scopes.h" | 34 #include "scopes.h" |
| 35 | 35 |
| 36 namespace v8 { | 36 namespace v8 { |
| 37 namespace internal { | 37 namespace internal { |
| 38 | 38 |
| 39 class AstOptimizer: public AstVisitor { | |
| 40 public: | |
| 41 explicit AstOptimizer() : has_function_literal_(false) {} | |
| 42 | |
| 43 void Optimize(ZoneList<Statement*>* statements); | |
| 44 | |
| 45 private: | |
| 46 // Used for loop condition analysis. Cleared before visiting a loop | |
| 47 // condition, set when a function literal is visited. | |
| 48 bool has_function_literal_; | |
| 49 | |
| 50 // Helpers | |
| 51 void OptimizeArguments(ZoneList<Expression*>* arguments); | |
| 52 | |
| 53 // Node visitors. | |
| 54 #define DEF_VISIT(type) \ | |
| 55 virtual void Visit##type(type* node); | |
| 56 AST_NODE_LIST(DEF_VISIT) | |
| 57 #undef DEF_VISIT | |
| 58 | |
| 59 DISALLOW_COPY_AND_ASSIGN(AstOptimizer); | |
| 60 }; | |
| 61 | |
| 62 | |
| 63 void AstOptimizer::Optimize(ZoneList<Statement*>* statements) { | |
| 64 int len = statements->length(); | |
| 65 for (int i = 0; i < len; i++) { | |
| 66 Visit(statements->at(i)); | |
| 67 } | |
| 68 } | |
| 69 | |
| 70 | |
| 71 void AstOptimizer::OptimizeArguments(ZoneList<Expression*>* arguments) { | |
| 72 for (int i = 0; i < arguments->length(); i++) { | |
| 73 Visit(arguments->at(i)); | |
| 74 } | |
| 75 } | |
| 76 | |
| 77 | |
| 78 void AstOptimizer::VisitBlock(Block* node) { | |
| 79 Optimize(node->statements()); | |
| 80 } | |
| 81 | |
| 82 | |
| 83 void AstOptimizer::VisitExpressionStatement(ExpressionStatement* node) { | |
| 84 node->expression()->set_no_negative_zero(true); | |
| 85 Visit(node->expression()); | |
| 86 } | |
| 87 | |
| 88 | |
| 89 void AstOptimizer::VisitIfStatement(IfStatement* node) { | |
| 90 node->condition()->set_no_negative_zero(true); | |
| 91 Visit(node->condition()); | |
| 92 Visit(node->then_statement()); | |
| 93 if (node->HasElseStatement()) { | |
| 94 Visit(node->else_statement()); | |
| 95 } | |
| 96 } | |
| 97 | |
| 98 | |
| 99 void AstOptimizer::VisitDoWhileStatement(DoWhileStatement* node) { | |
| 100 node->cond()->set_no_negative_zero(true); | |
| 101 Visit(node->cond()); | |
| 102 Visit(node->body()); | |
| 103 } | |
| 104 | |
| 105 | |
| 106 void AstOptimizer::VisitWhileStatement(WhileStatement* node) { | |
| 107 has_function_literal_ = false; | |
| 108 node->cond()->set_no_negative_zero(true); | |
| 109 Visit(node->cond()); | |
| 110 node->set_may_have_function_literal(has_function_literal_); | |
| 111 Visit(node->body()); | |
| 112 } | |
| 113 | |
| 114 | |
| 115 void AstOptimizer::VisitForStatement(ForStatement* node) { | |
| 116 if (node->init() != NULL) { | |
| 117 Visit(node->init()); | |
| 118 } | |
| 119 if (node->cond() != NULL) { | |
| 120 has_function_literal_ = false; | |
| 121 node->cond()->set_no_negative_zero(true); | |
| 122 Visit(node->cond()); | |
| 123 node->set_may_have_function_literal(has_function_literal_); | |
| 124 } | |
| 125 Visit(node->body()); | |
| 126 if (node->next() != NULL) { | |
| 127 Visit(node->next()); | |
| 128 } | |
| 129 } | |
| 130 | |
| 131 | |
| 132 void AstOptimizer::VisitForInStatement(ForInStatement* node) { | |
| 133 Visit(node->each()); | |
| 134 Visit(node->enumerable()); | |
| 135 Visit(node->body()); | |
| 136 } | |
| 137 | |
| 138 | |
| 139 void AstOptimizer::VisitTryCatchStatement(TryCatchStatement* node) { | |
| 140 Visit(node->try_block()); | |
| 141 Visit(node->catch_var()); | |
| 142 Visit(node->catch_block()); | |
| 143 } | |
| 144 | |
| 145 | |
| 146 void AstOptimizer::VisitTryFinallyStatement(TryFinallyStatement* node) { | |
| 147 Visit(node->try_block()); | |
| 148 Visit(node->finally_block()); | |
| 149 } | |
| 150 | |
| 151 | |
| 152 void AstOptimizer::VisitSwitchStatement(SwitchStatement* node) { | |
| 153 node->tag()->set_no_negative_zero(true); | |
| 154 Visit(node->tag()); | |
| 155 for (int i = 0; i < node->cases()->length(); i++) { | |
| 156 CaseClause* clause = node->cases()->at(i); | |
| 157 if (!clause->is_default()) { | |
| 158 Visit(clause->label()); | |
| 159 } | |
| 160 Optimize(clause->statements()); | |
| 161 } | |
| 162 } | |
| 163 | |
| 164 | |
| 165 void AstOptimizer::VisitContinueStatement(ContinueStatement* node) { | |
| 166 USE(node); | |
| 167 } | |
| 168 | |
| 169 | |
| 170 void AstOptimizer::VisitBreakStatement(BreakStatement* node) { | |
| 171 USE(node); | |
| 172 } | |
| 173 | |
| 174 | |
| 175 void AstOptimizer::VisitDeclaration(Declaration* node) { | |
| 176 // Will not be reached by the current optimizations. | |
| 177 USE(node); | |
| 178 } | |
| 179 | |
| 180 | |
| 181 void AstOptimizer::VisitEmptyStatement(EmptyStatement* node) { | |
| 182 USE(node); | |
| 183 } | |
| 184 | |
| 185 | |
| 186 void AstOptimizer::VisitReturnStatement(ReturnStatement* node) { | |
| 187 Visit(node->expression()); | |
| 188 } | |
| 189 | |
| 190 | |
| 191 void AstOptimizer::VisitWithEnterStatement(WithEnterStatement* node) { | |
| 192 Visit(node->expression()); | |
| 193 } | |
| 194 | |
| 195 | |
| 196 void AstOptimizer::VisitWithExitStatement(WithExitStatement* node) { | |
| 197 USE(node); | |
| 198 } | |
| 199 | |
| 200 | |
| 201 void AstOptimizer::VisitDebuggerStatement(DebuggerStatement* node) { | |
| 202 USE(node); | |
| 203 } | |
| 204 | |
| 205 | |
| 206 void AstOptimizer::VisitFunctionLiteral(FunctionLiteral* node) { | |
| 207 has_function_literal_ = true; | |
| 208 } | |
| 209 | |
| 210 | |
| 211 void AstOptimizer::VisitSharedFunctionInfoLiteral( | |
| 212 SharedFunctionInfoLiteral* node) { | |
| 213 USE(node); | |
| 214 } | |
| 215 | |
| 216 | |
| 217 void AstOptimizer::VisitConditional(Conditional* node) { | |
| 218 node->condition()->set_no_negative_zero(true); | |
| 219 Visit(node->condition()); | |
| 220 Visit(node->then_expression()); | |
| 221 Visit(node->else_expression()); | |
| 222 } | |
| 223 | |
| 224 | |
| 225 void AstOptimizer::VisitVariableProxy(VariableProxy* node) { | |
| 226 Variable* var = node->AsVariable(); | |
| 227 if (var != NULL) { | |
| 228 if (var->type()->IsKnown()) { | |
| 229 node->type()->CopyFrom(var->type()); | |
| 230 } else if (node->type()->IsLikelySmi()) { | |
| 231 var->type()->SetAsLikelySmi(); | |
| 232 } | |
| 233 | |
| 234 if (FLAG_safe_int32_compiler) { | |
| 235 if (var->IsStackAllocated() && | |
| 236 !var->is_arguments() && | |
| 237 var->mode() != Variable::CONST) { | |
| 238 node->set_side_effect_free(true); | |
| 239 } | |
| 240 } | |
| 241 } | |
| 242 } | |
| 243 | |
| 244 | |
| 245 void AstOptimizer::VisitLiteral(Literal* node) { | |
| 246 Handle<Object> literal = node->handle(); | |
| 247 if (literal->IsSmi()) { | |
| 248 node->type()->SetAsLikelySmi(); | |
| 249 node->set_side_effect_free(true); | |
| 250 } else if (literal->IsHeapNumber()) { | |
| 251 if (node->to_int32()) { | |
| 252 // Any HeapNumber has an int32 value if it is the input to a bit op. | |
| 253 node->set_side_effect_free(true); | |
| 254 } else { | |
| 255 double double_value = HeapNumber::cast(*literal)->value(); | |
| 256 int32_t int32_value = DoubleToInt32(double_value); | |
| 257 node->set_side_effect_free(double_value == int32_value); | |
| 258 } | |
| 259 } | |
| 260 } | |
| 261 | |
| 262 | |
| 263 void AstOptimizer::VisitRegExpLiteral(RegExpLiteral* node) { | |
| 264 USE(node); | |
| 265 } | |
| 266 | |
| 267 | |
| 268 void AstOptimizer::VisitArrayLiteral(ArrayLiteral* node) { | |
| 269 for (int i = 0; i < node->values()->length(); i++) { | |
| 270 Visit(node->values()->at(i)); | |
| 271 } | |
| 272 } | |
| 273 | |
| 274 void AstOptimizer::VisitObjectLiteral(ObjectLiteral* node) { | |
| 275 for (int i = 0; i < node->properties()->length(); i++) { | |
| 276 Visit(node->properties()->at(i)->key()); | |
| 277 Visit(node->properties()->at(i)->value()); | |
| 278 } | |
| 279 } | |
| 280 | |
| 281 | |
| 282 void AstOptimizer::VisitCatchExtensionObject(CatchExtensionObject* node) { | |
| 283 Visit(node->key()); | |
| 284 Visit(node->value()); | |
| 285 } | |
| 286 | |
| 287 | |
| 288 void AstOptimizer::VisitAssignment(Assignment* node) { | |
| 289 switch (node->op()) { | |
| 290 case Token::INIT_VAR: | |
| 291 case Token::INIT_CONST: | |
| 292 case Token::ASSIGN: | |
| 293 // No type can be infered from the general assignment. | |
| 294 break; | |
| 295 case Token::ASSIGN_BIT_OR: | |
| 296 case Token::ASSIGN_BIT_XOR: | |
| 297 case Token::ASSIGN_BIT_AND: | |
| 298 case Token::ASSIGN_SHL: | |
| 299 case Token::ASSIGN_SAR: | |
| 300 case Token::ASSIGN_SHR: | |
| 301 node->type()->SetAsLikelySmiIfUnknown(); | |
| 302 node->target()->type()->SetAsLikelySmiIfUnknown(); | |
| 303 node->value()->type()->SetAsLikelySmiIfUnknown(); | |
| 304 node->value()->set_to_int32(true); | |
| 305 node->value()->set_no_negative_zero(true); | |
| 306 break; | |
| 307 case Token::ASSIGN_ADD: | |
| 308 case Token::ASSIGN_SUB: | |
| 309 case Token::ASSIGN_MUL: | |
| 310 case Token::ASSIGN_DIV: | |
| 311 case Token::ASSIGN_MOD: | |
| 312 if (node->type()->IsLikelySmi()) { | |
| 313 node->target()->type()->SetAsLikelySmiIfUnknown(); | |
| 314 node->value()->type()->SetAsLikelySmiIfUnknown(); | |
| 315 } | |
| 316 break; | |
| 317 default: | |
| 318 UNREACHABLE(); | |
| 319 break; | |
| 320 } | |
| 321 | |
| 322 Visit(node->target()); | |
| 323 Visit(node->value()); | |
| 324 | |
| 325 switch (node->op()) { | |
| 326 case Token::INIT_VAR: | |
| 327 case Token::INIT_CONST: | |
| 328 case Token::ASSIGN: | |
| 329 // Pure assignment copies the type from the value. | |
| 330 node->type()->CopyFrom(node->value()->type()); | |
| 331 break; | |
| 332 case Token::ASSIGN_BIT_OR: | |
| 333 case Token::ASSIGN_BIT_XOR: | |
| 334 case Token::ASSIGN_BIT_AND: | |
| 335 case Token::ASSIGN_SHL: | |
| 336 case Token::ASSIGN_SAR: | |
| 337 case Token::ASSIGN_SHR: | |
| 338 // Should have been setup above already. | |
| 339 break; | |
| 340 case Token::ASSIGN_ADD: | |
| 341 case Token::ASSIGN_SUB: | |
| 342 case Token::ASSIGN_MUL: | |
| 343 case Token::ASSIGN_DIV: | |
| 344 case Token::ASSIGN_MOD: | |
| 345 if (node->type()->IsUnknown()) { | |
| 346 if (node->target()->type()->IsLikelySmi() || | |
| 347 node->value()->type()->IsLikelySmi()) { | |
| 348 node->type()->SetAsLikelySmi(); | |
| 349 } | |
| 350 } | |
| 351 break; | |
| 352 default: | |
| 353 UNREACHABLE(); | |
| 354 break; | |
| 355 } | |
| 356 | |
| 357 // Since this is an assignment. We have to propagate this node's type to the | |
| 358 // variable. | |
| 359 VariableProxy* proxy = node->target()->AsVariableProxy(); | |
| 360 if (proxy != NULL) { | |
| 361 Variable* var = proxy->AsVariable(); | |
| 362 if (var != NULL) { | |
| 363 StaticType* var_type = var->type(); | |
| 364 if (var_type->IsUnknown()) { | |
| 365 var_type->CopyFrom(node->type()); | |
| 366 } else if (var_type->IsLikelySmi()) { | |
| 367 // We do not reset likely types to Unknown. | |
| 368 } | |
| 369 } | |
| 370 } | |
| 371 } | |
| 372 | |
| 373 | |
| 374 void AstOptimizer::VisitThrow(Throw* node) { | |
| 375 Visit(node->exception()); | |
| 376 } | |
| 377 | |
| 378 | |
| 379 void AstOptimizer::VisitProperty(Property* node) { | |
| 380 node->key()->set_no_negative_zero(true); | |
| 381 Visit(node->obj()); | |
| 382 Visit(node->key()); | |
| 383 } | |
| 384 | |
| 385 | |
| 386 void AstOptimizer::VisitCall(Call* node) { | |
| 387 Visit(node->expression()); | |
| 388 OptimizeArguments(node->arguments()); | |
| 389 } | |
| 390 | |
| 391 | |
| 392 void AstOptimizer::VisitCallNew(CallNew* node) { | |
| 393 Visit(node->expression()); | |
| 394 OptimizeArguments(node->arguments()); | |
| 395 } | |
| 396 | |
| 397 | |
| 398 void AstOptimizer::VisitCallRuntime(CallRuntime* node) { | |
| 399 OptimizeArguments(node->arguments()); | |
| 400 } | |
| 401 | |
| 402 | |
| 403 void AstOptimizer::VisitUnaryOperation(UnaryOperation* node) { | |
| 404 if (node->op() == Token::ADD || node->op() == Token::SUB) { | |
| 405 node->expression()->set_no_negative_zero(node->no_negative_zero()); | |
| 406 } else { | |
| 407 node->expression()->set_no_negative_zero(true); | |
| 408 } | |
| 409 Visit(node->expression()); | |
| 410 if (FLAG_safe_int32_compiler) { | |
| 411 switch (node->op()) { | |
| 412 case Token::BIT_NOT: | |
| 413 node->expression()->set_no_negative_zero(true); | |
| 414 node->expression()->set_to_int32(true); | |
| 415 // Fall through. | |
| 416 case Token::ADD: | |
| 417 case Token::SUB: | |
| 418 node->set_side_effect_free(node->expression()->side_effect_free()); | |
| 419 break; | |
| 420 case Token::NOT: | |
| 421 case Token::DELETE: | |
| 422 case Token::TYPEOF: | |
| 423 case Token::VOID: | |
| 424 break; | |
| 425 default: | |
| 426 UNREACHABLE(); | |
| 427 break; | |
| 428 } | |
| 429 } else if (node->op() == Token::BIT_NOT) { | |
| 430 node->expression()->set_to_int32(true); | |
| 431 } | |
| 432 } | |
| 433 | |
| 434 | |
| 435 void AstOptimizer::VisitIncrementOperation(IncrementOperation* node) { | |
| 436 UNREACHABLE(); | |
| 437 } | |
| 438 | |
| 439 | |
| 440 void AstOptimizer::VisitCountOperation(CountOperation* node) { | |
| 441 // Count operations assume that they work on Smis. | |
| 442 node->expression()->set_no_negative_zero(node->is_prefix() ? | |
| 443 true : | |
| 444 node->no_negative_zero()); | |
| 445 node->type()->SetAsLikelySmiIfUnknown(); | |
| 446 node->expression()->type()->SetAsLikelySmiIfUnknown(); | |
| 447 Visit(node->expression()); | |
| 448 } | |
| 449 | |
| 450 | |
| 451 static bool CouldBeNegativeZero(AstNode* node) { | |
| 452 Literal* literal = node->AsLiteral(); | |
| 453 if (literal != NULL) { | |
| 454 Handle<Object> handle = literal->handle(); | |
| 455 if (handle->IsString() || handle->IsSmi()) { | |
| 456 return false; | |
| 457 } else if (handle->IsHeapNumber()) { | |
| 458 double double_value = HeapNumber::cast(*handle)->value(); | |
| 459 if (double_value != 0) { | |
| 460 return false; | |
| 461 } | |
| 462 } | |
| 463 } | |
| 464 BinaryOperation* binary = node->AsBinaryOperation(); | |
| 465 if (binary != NULL && Token::IsBitOp(binary->op())) { | |
| 466 return false; | |
| 467 } | |
| 468 return true; | |
| 469 } | |
| 470 | |
| 471 | |
| 472 static bool CouldBePositiveZero(AstNode* node) { | |
| 473 Literal* literal = node->AsLiteral(); | |
| 474 if (literal != NULL) { | |
| 475 Handle<Object> handle = literal->handle(); | |
| 476 if (handle->IsSmi()) { | |
| 477 if (Smi::cast(*handle) != Smi::FromInt(0)) { | |
| 478 return false; | |
| 479 } | |
| 480 } else if (handle->IsHeapNumber()) { | |
| 481 // Heap number literal can't be +0, because that's a Smi. | |
| 482 return false; | |
| 483 } | |
| 484 } | |
| 485 return true; | |
| 486 } | |
| 487 | |
| 488 | |
| 489 void AstOptimizer::VisitBinaryOperation(BinaryOperation* node) { | |
| 490 // Depending on the operation we can propagate this node's type down the | |
| 491 // AST nodes. | |
| 492 Token::Value op = node->op(); | |
| 493 switch (op) { | |
| 494 case Token::COMMA: | |
| 495 case Token::OR: | |
| 496 node->left()->set_no_negative_zero(true); | |
| 497 node->right()->set_no_negative_zero(node->no_negative_zero()); | |
| 498 break; | |
| 499 case Token::AND: | |
| 500 node->left()->set_no_negative_zero(node->no_negative_zero()); | |
| 501 node->right()->set_no_negative_zero(node->no_negative_zero()); | |
| 502 break; | |
| 503 case Token::BIT_OR: | |
| 504 case Token::BIT_XOR: | |
| 505 case Token::BIT_AND: | |
| 506 case Token::SHL: | |
| 507 case Token::SAR: | |
| 508 case Token::SHR: | |
| 509 node->type()->SetAsLikelySmiIfUnknown(); | |
| 510 node->left()->type()->SetAsLikelySmiIfUnknown(); | |
| 511 node->right()->type()->SetAsLikelySmiIfUnknown(); | |
| 512 node->left()->set_to_int32(true); | |
| 513 node->right()->set_to_int32(true); | |
| 514 node->left()->set_no_negative_zero(true); | |
| 515 node->right()->set_no_negative_zero(true); | |
| 516 break; | |
| 517 case Token::MUL: { | |
| 518 VariableProxy* lvar_proxy = node->left()->AsVariableProxy(); | |
| 519 VariableProxy* rvar_proxy = node->right()->AsVariableProxy(); | |
| 520 if (lvar_proxy != NULL && rvar_proxy != NULL) { | |
| 521 Variable* lvar = lvar_proxy->AsVariable(); | |
| 522 Variable* rvar = rvar_proxy->AsVariable(); | |
| 523 if (lvar != NULL && rvar != NULL) { | |
| 524 if (lvar->mode() == Variable::VAR && rvar->mode() == Variable::VAR) { | |
| 525 Slot* lslot = lvar->AsSlot(); | |
| 526 Slot* rslot = rvar->AsSlot(); | |
| 527 if (lslot->type() == rslot->type() && | |
| 528 (lslot->type() == Slot::PARAMETER || | |
| 529 lslot->type() == Slot::LOCAL) && | |
| 530 lslot->index() == rslot->index()) { | |
| 531 // A number squared doesn't give negative zero. | |
| 532 node->set_no_negative_zero(true); | |
| 533 } | |
| 534 } | |
| 535 } | |
| 536 } | |
| 537 } | |
| 538 case Token::ADD: | |
| 539 case Token::SUB: | |
| 540 case Token::DIV: | |
| 541 case Token::MOD: { | |
| 542 if (node->type()->IsLikelySmi()) { | |
| 543 node->left()->type()->SetAsLikelySmiIfUnknown(); | |
| 544 node->right()->type()->SetAsLikelySmiIfUnknown(); | |
| 545 } | |
| 546 if (op == Token::ADD && (!CouldBeNegativeZero(node->left()) || | |
| 547 !CouldBeNegativeZero(node->right()))) { | |
| 548 node->left()->set_no_negative_zero(true); | |
| 549 node->right()->set_no_negative_zero(true); | |
| 550 } else if (op == Token::SUB && (!CouldBeNegativeZero(node->left()) || | |
| 551 !CouldBePositiveZero(node->right()))) { | |
| 552 node->left()->set_no_negative_zero(true); | |
| 553 node->right()->set_no_negative_zero(true); | |
| 554 } else { | |
| 555 node->left()->set_no_negative_zero(node->no_negative_zero()); | |
| 556 node->right()->set_no_negative_zero(node->no_negative_zero()); | |
| 557 } | |
| 558 if (node->op() == Token::DIV) { | |
| 559 node->right()->set_no_negative_zero(false); | |
| 560 } else if (node->op() == Token::MOD) { | |
| 561 node->right()->set_no_negative_zero(true); | |
| 562 } | |
| 563 break; | |
| 564 } | |
| 565 default: | |
| 566 UNREACHABLE(); | |
| 567 break; | |
| 568 } | |
| 569 | |
| 570 Visit(node->left()); | |
| 571 Visit(node->right()); | |
| 572 | |
| 573 // After visiting the operand nodes we have to check if this node's type | |
| 574 // can be updated. If it does, then we can push that information down | |
| 575 // towards the leaves again if the new information is an upgrade over the | |
| 576 // previous type of the operand nodes. | |
| 577 if (node->type()->IsUnknown()) { | |
| 578 if (node->left()->type()->IsLikelySmi() || | |
| 579 node->right()->type()->IsLikelySmi()) { | |
| 580 node->type()->SetAsLikelySmi(); | |
| 581 } | |
| 582 if (node->type()->IsLikelySmi()) { | |
| 583 // The type of this node changed to LIKELY_SMI. Propagate this knowledge | |
| 584 // down through the nodes. | |
| 585 if (node->left()->type()->IsUnknown()) { | |
| 586 node->left()->type()->SetAsLikelySmi(); | |
| 587 Visit(node->left()); | |
| 588 } | |
| 589 if (node->right()->type()->IsUnknown()) { | |
| 590 node->right()->type()->SetAsLikelySmi(); | |
| 591 Visit(node->right()); | |
| 592 } | |
| 593 } | |
| 594 } | |
| 595 | |
| 596 if (FLAG_safe_int32_compiler) { | |
| 597 switch (node->op()) { | |
| 598 case Token::COMMA: | |
| 599 case Token::OR: | |
| 600 case Token::AND: | |
| 601 break; | |
| 602 case Token::BIT_OR: | |
| 603 case Token::BIT_XOR: | |
| 604 case Token::BIT_AND: | |
| 605 case Token::SHL: | |
| 606 case Token::SAR: | |
| 607 case Token::SHR: | |
| 608 // Add one to the number of bit operations in this expression. | |
| 609 node->set_num_bit_ops(1); | |
| 610 // Fall through. | |
| 611 case Token::ADD: | |
| 612 case Token::SUB: | |
| 613 case Token::MUL: | |
| 614 case Token::DIV: | |
| 615 case Token::MOD: | |
| 616 node->set_side_effect_free(node->left()->side_effect_free() && | |
| 617 node->right()->side_effect_free()); | |
| 618 node->set_num_bit_ops(node->num_bit_ops() + | |
| 619 node->left()->num_bit_ops() + | |
| 620 node->right()->num_bit_ops()); | |
| 621 if (!node->no_negative_zero() && node->op() == Token::MUL) { | |
| 622 node->set_side_effect_free(false); | |
| 623 } | |
| 624 break; | |
| 625 default: | |
| 626 UNREACHABLE(); | |
| 627 break; | |
| 628 } | |
| 629 } | |
| 630 } | |
| 631 | |
| 632 | |
| 633 void AstOptimizer::VisitCompareOperation(CompareOperation* node) { | |
| 634 if (node->type()->IsKnown()) { | |
| 635 // Propagate useful information down towards the leaves. | |
| 636 node->left()->type()->SetAsLikelySmiIfUnknown(); | |
| 637 node->right()->type()->SetAsLikelySmiIfUnknown(); | |
| 638 } | |
| 639 | |
| 640 node->left()->set_no_negative_zero(true); | |
| 641 // Only [[HasInstance]] has the right argument passed unchanged to it. | |
| 642 node->right()->set_no_negative_zero(true); | |
| 643 | |
| 644 Visit(node->left()); | |
| 645 Visit(node->right()); | |
| 646 | |
| 647 // After visiting the operand nodes we have to check if this node's type | |
| 648 // can be updated. If it does, then we can push that information down | |
| 649 // towards the leaves again if the new information is an upgrade over the | |
| 650 // previous type of the operand nodes. | |
| 651 if (node->type()->IsUnknown()) { | |
| 652 if (node->left()->type()->IsLikelySmi() || | |
| 653 node->right()->type()->IsLikelySmi()) { | |
| 654 node->type()->SetAsLikelySmi(); | |
| 655 } | |
| 656 if (node->type()->IsLikelySmi()) { | |
| 657 // The type of this node changed to LIKELY_SMI. Propagate this knowledge | |
| 658 // down through the nodes. | |
| 659 if (node->left()->type()->IsUnknown()) { | |
| 660 node->left()->type()->SetAsLikelySmi(); | |
| 661 Visit(node->left()); | |
| 662 } | |
| 663 if (node->right()->type()->IsUnknown()) { | |
| 664 node->right()->type()->SetAsLikelySmi(); | |
| 665 Visit(node->right()); | |
| 666 } | |
| 667 } | |
| 668 } | |
| 669 } | |
| 670 | |
| 671 | |
| 672 void AstOptimizer::VisitCompareToNull(CompareToNull* node) { | |
| 673 Visit(node->expression()); | |
| 674 } | |
| 675 | |
| 676 | |
| 677 void AstOptimizer::VisitThisFunction(ThisFunction* node) { | |
| 678 USE(node); | |
| 679 } | |
| 680 | |
| 681 | |
| 682 class Processor: public AstVisitor { | 39 class Processor: public AstVisitor { |
| 683 public: | 40 public: |
| 684 explicit Processor(Variable* result) | 41 explicit Processor(Variable* result) |
| 685 : result_(result), | 42 : result_(result), |
| 686 result_assigned_(false), | 43 result_assigned_(false), |
| 687 is_set_(false), | 44 is_set_(false), |
| 688 in_try_(false) { | 45 in_try_(false) { |
| 689 } | 46 } |
| 690 | 47 |
| 691 void Process(ZoneList<Statement*>* statements); | 48 void Process(ZoneList<Statement*>* statements); |
| (...skipping 306 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 998 if (processor.result_assigned()) { | 355 if (processor.result_assigned()) { |
| 999 VariableProxy* result_proxy = new VariableProxy(result); | 356 VariableProxy* result_proxy = new VariableProxy(result); |
| 1000 body->Add(new ReturnStatement(result_proxy)); | 357 body->Add(new ReturnStatement(result_proxy)); |
| 1001 } | 358 } |
| 1002 } | 359 } |
| 1003 | 360 |
| 1004 return true; | 361 return true; |
| 1005 } | 362 } |
| 1006 | 363 |
| 1007 | 364 |
| 1008 // Assumes code has been parsed and scopes have been analyzed. Mutates the | |
| 1009 // AST, so the AST should not continue to be used in the case of failure. | |
| 1010 bool Rewriter::Analyze(CompilationInfo* info) { | |
| 1011 FunctionLiteral* function = info->function(); | |
| 1012 ASSERT(function != NULL && function->scope() != NULL); | |
| 1013 | |
| 1014 ZoneList<Statement*>* body = function->body(); | |
| 1015 if (FLAG_optimize_ast && !body->is_empty()) { | |
| 1016 AstOptimizer optimizer; | |
| 1017 optimizer.Optimize(body); | |
| 1018 if (optimizer.HasStackOverflow()) return false; | |
| 1019 } | |
| 1020 return true; | |
| 1021 } | |
| 1022 | |
| 1023 | |
| 1024 } } // namespace v8::internal | 365 } } // namespace v8::internal |
| OLD | NEW |