1 // Copyright 2012 the V8 project authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "src/ast/ast-numbering.h" 6 7 #include "src/ast/ast.h" 8 #include "src/ast/scopes.h" 9 10 namespace v8 { 11 namespace internal { 12 13 class AstNumberingVisitor final : public AstVisitor<AstNumberingVisitor> { 14 public: 15 AstNumberingVisitor(Isolate* isolate, Zone* zone) 16 : isolate_(isolate), 17 zone_(zone), 18 next_id_(BailoutId::FirstUsable().ToInt()), 19 yield_count_(0), 20 properties_(zone), 21 slot_cache_(zone), 22 dont_optimize_reason_(kNoReason), 23 catch_prediction_(HandlerTable::UNCAUGHT) { 24 InitializeAstVisitor(isolate); 25 } 26 27 bool Renumber(FunctionLiteral* node); 28 29 private: 30 // AST node visitor interface. 31 #define DEFINE_VISIT(type) void Visit##type(type* node); 32 AST_NODE_LIST(DEFINE_VISIT) 33 #undef DEFINE_VISIT 34 35 void VisitVariableProxyReference(VariableProxy* node); 36 void VisitPropertyReference(Property* node); 37 void VisitReference(Expression* expr); 38 39 void VisitStatements(ZoneList<Statement*>* statements); 40 void VisitDeclarations(Declaration::List* declarations); 41 void VisitArguments(ZoneList<Expression*>* arguments); 42 void VisitLiteralProperty(LiteralProperty* property); 43 44 int ReserveIdRange(int n) { 45 int tmp = next_id_; 46 next_id_ += n; 47 return tmp; 48 } 49 50 void IncrementNodeCount() { properties_.add_node_count(1); } 51 void DisableSelfOptimization() { 52 properties_.flags() |= AstProperties::kDontSelfOptimize; 53 } 54 void DisableOptimization(BailoutReason reason) { 55 dont_optimize_reason_ = reason; 56 DisableSelfOptimization(); 57 } 58 void DisableCrankshaft(BailoutReason reason) { 59 properties_.flags() |= AstProperties::kDontCrankshaft; 60 } 61 62 template <typename Node> 63 void ReserveFeedbackSlots(Node* node) { 64 node->AssignFeedbackVectorSlots(isolate_, properties_.get_spec(), 65 &slot_cache_); 66 } 67 68 BailoutReason dont_optimize_reason() const { return dont_optimize_reason_; } 69 70 Isolate* isolate_; 71 Zone* zone_; 72 int next_id_; 73 int yield_count_; 74 AstProperties properties_; 75 // The slot cache allows us to reuse certain feedback vector slots. 76 FeedbackVectorSlotCache slot_cache_; 77 BailoutReason dont_optimize_reason_; 78 HandlerTable::CatchPrediction catch_prediction_; 79 80 DEFINE_AST_VISITOR_SUBCLASS_MEMBERS(); 81 DISALLOW_COPY_AND_ASSIGN(AstNumberingVisitor); 82 }; 83 84 85 void AstNumberingVisitor::VisitVariableDeclaration(VariableDeclaration* node) { 86 IncrementNodeCount(); 87 VisitVariableProxy(node->proxy()); 88 } 89 90 91 void AstNumberingVisitor::VisitEmptyStatement(EmptyStatement* node) { 92 IncrementNodeCount(); 93 } 94 95 96 void AstNumberingVisitor::VisitSloppyBlockFunctionStatement( 97 SloppyBlockFunctionStatement* node) { 98 IncrementNodeCount(); 99 Visit(node->statement()); 100 } 101 102 103 void AstNumberingVisitor::VisitContinueStatement(ContinueStatement* node) { 104 IncrementNodeCount(); 105 } 106 107 108 void AstNumberingVisitor::VisitBreakStatement(BreakStatement* node) { 109 IncrementNodeCount(); 110 } 111 112 113 void AstNumberingVisitor::VisitDebuggerStatement(DebuggerStatement* node) { 114 IncrementNodeCount(); 115 DisableOptimization(kDebuggerStatement); 116 node->set_base_id(ReserveIdRange(DebuggerStatement::num_ids())); 117 } 118 119 120 void AstNumberingVisitor::VisitNativeFunctionLiteral( 121 NativeFunctionLiteral* node) { 122 IncrementNodeCount(); 123 DisableOptimization(kNativeFunctionLiteral); 124 node->set_base_id(ReserveIdRange(NativeFunctionLiteral::num_ids())); 125 } 126 127 128 void AstNumberingVisitor::VisitDoExpression(DoExpression* node) { 129 IncrementNodeCount(); 130 node->set_base_id(ReserveIdRange(DoExpression::num_ids())); 131 Visit(node->block()); 132 Visit(node->result()); 133 } 134 135 136 void AstNumberingVisitor::VisitLiteral(Literal* node) { 137 IncrementNodeCount(); 138 node->set_base_id(ReserveIdRange(Literal::num_ids())); 139 } 140 141 142 void AstNumberingVisitor::VisitRegExpLiteral(RegExpLiteral* node) { 143 IncrementNodeCount(); 144 node->set_base_id(ReserveIdRange(RegExpLiteral::num_ids())); 145 } 146 147 148 void AstNumberingVisitor::VisitVariableProxyReference(VariableProxy* node) { 149 IncrementNodeCount(); 150 switch (node->var()->location()) { 151 case VariableLocation::LOOKUP: 152 DisableCrankshaft(kReferenceToAVariableWhichRequiresDynamicLookup); 153 break; 154 case VariableLocation::MODULE: 155 DisableCrankshaft(kReferenceToModuleVariable); 156 break; 157 default: 158 break; 159 } 160 node->set_base_id(ReserveIdRange(VariableProxy::num_ids())); 161 } 162 163 164 void AstNumberingVisitor::VisitVariableProxy(VariableProxy* node) { 165 VisitVariableProxyReference(node); 166 ReserveFeedbackSlots(node); 167 } 168 169 170 void AstNumberingVisitor::VisitThisFunction(ThisFunction* node) { 171 IncrementNodeCount(); 172 node->set_base_id(ReserveIdRange(ThisFunction::num_ids())); 173 } 174 175 176 void AstNumberingVisitor::VisitSuperPropertyReference( 177 SuperPropertyReference* node) { 178 IncrementNodeCount(); 179 DisableCrankshaft(kSuperReference); 180 node->set_base_id(ReserveIdRange(SuperPropertyReference::num_ids())); 181 Visit(node->this_var()); 182 Visit(node->home_object()); 183 } 184 185 186 void AstNumberingVisitor::VisitSuperCallReference(SuperCallReference* node) { 187 IncrementNodeCount(); 188 DisableCrankshaft(kSuperReference); 189 node->set_base_id(ReserveIdRange(SuperCallReference::num_ids())); 190 Visit(node->this_var()); 191 Visit(node->new_target_var()); 192 Visit(node->this_function_var()); 193 } 194 195 196 void AstNumberingVisitor::VisitExpressionStatement(ExpressionStatement* node) { 197 IncrementNodeCount(); 198 Visit(node->expression()); 199 } 200 201 202 void AstNumberingVisitor::VisitReturnStatement(ReturnStatement* node) { 203 IncrementNodeCount(); 204 Visit(node->expression()); 205 } 206 207 208 void AstNumberingVisitor::VisitYield(Yield* node) { 209 node->set_yield_id(yield_count_); 210 yield_count_++; 211 IncrementNodeCount(); 212 node->set_base_id(ReserveIdRange(Yield::num_ids())); 213 Visit(node->generator_object()); 214 Visit(node->expression()); 215 } 216 217 218 void AstNumberingVisitor::VisitThrow(Throw* node) { 219 IncrementNodeCount(); 220 node->set_base_id(ReserveIdRange(Throw::num_ids())); 221 Visit(node->exception()); 222 } 223 224 225 void AstNumberingVisitor::VisitUnaryOperation(UnaryOperation* node) { 226 IncrementNodeCount(); 227 node->set_base_id(ReserveIdRange(UnaryOperation::num_ids())); 228 Visit(node->expression()); 229 } 230 231 232 void AstNumberingVisitor::VisitCountOperation(CountOperation* node) { 233 IncrementNodeCount(); 234 node->set_base_id(ReserveIdRange(CountOperation::num_ids())); 235 Visit(node->expression()); 236 ReserveFeedbackSlots(node); 237 } 238 239 240 void AstNumberingVisitor::VisitBlock(Block* node) { 241 IncrementNodeCount(); 242 node->set_base_id(ReserveIdRange(Block::num_ids())); 243 if (node->scope() != NULL) VisitDeclarations(node->scope()->declarations()); 244 VisitStatements(node->statements()); 245 } 246 247 248 void AstNumberingVisitor::VisitFunctionDeclaration(FunctionDeclaration* node) { 249 IncrementNodeCount(); 250 VisitVariableProxy(node->proxy()); 251 VisitFunctionLiteral(node->fun()); 252 } 253 254 255 void AstNumberingVisitor::VisitCallRuntime(CallRuntime* node) { 256 IncrementNodeCount(); 257 node->set_base_id(ReserveIdRange(CallRuntime::num_ids())); 258 VisitArguments(node->arguments()); 259 // To support catch prediction within async/await: 260 // 261 // The AstNumberingVisitor is when catch prediction currently occurs, and it 262 // is the only common point that has access to this information. The parser 263 // just doesn't know yet. Take the following two cases of catch prediction: 264 // 265 // try { await fn(); } catch (e) { } 266 // try { await fn(); } finally { } 267 // 268 // When parsing the await that we want to mark as caught or uncaught, it's 269 // not yet known whether it will be followed by a 'finally' or a 'catch. 270 // The AstNumberingVisitor is what learns whether it is caught. To make 271 // the information available later to the runtime, the AstNumberingVisitor 272 // has to stash it somewhere. Changing the runtime function into another 273 // one in ast-numbering seemed like a simple and straightforward solution to 274 // that problem. 275 if (node->is_jsruntime() && 276 node->context_index() == Context::ASYNC_FUNCTION_AWAIT_CAUGHT_INDEX && 277 catch_prediction_ == HandlerTable::ASYNC_AWAIT) { 278 node->set_context_index(Context::ASYNC_FUNCTION_AWAIT_UNCAUGHT_INDEX); 279 } 280 } 281 282 283 void AstNumberingVisitor::VisitWithStatement(WithStatement* node) { 284 IncrementNodeCount(); 285 DisableCrankshaft(kWithStatement); 286 node->set_base_id(ReserveIdRange(WithStatement::num_ids())); 287 Visit(node->expression()); 288 Visit(node->statement()); 289 } 290 291 292 void AstNumberingVisitor::VisitDoWhileStatement(DoWhileStatement* node) { 293 IncrementNodeCount(); 294 DisableSelfOptimization(); 295 node->set_base_id(ReserveIdRange(DoWhileStatement::num_ids())); 296 node->set_first_yield_id(yield_count_); 297 Visit(node->body()); 298 Visit(node->cond()); 299 node->set_yield_count(yield_count_ - node->first_yield_id()); 300 } 301 302 303 void AstNumberingVisitor::VisitWhileStatement(WhileStatement* node) { 304 IncrementNodeCount(); 305 DisableSelfOptimization(); 306 node->set_base_id(ReserveIdRange(WhileStatement::num_ids())); 307 node->set_first_yield_id(yield_count_); 308 Visit(node->cond()); 309 Visit(node->body()); 310 node->set_yield_count(yield_count_ - node->first_yield_id()); 311 } 312 313 314 void AstNumberingVisitor::VisitTryCatchStatement(TryCatchStatement* node) { 315 IncrementNodeCount(); 316 DisableCrankshaft(kTryCatchStatement); 317 { 318 const HandlerTable::CatchPrediction old_prediction = catch_prediction_; 319 // This node uses its own prediction, unless it's "uncaught", in which case 320 // we adopt the prediction of the outer try-block. 321 HandlerTable::CatchPrediction catch_prediction = node->catch_prediction(); 322 if (catch_prediction != HandlerTable::UNCAUGHT) { 323 catch_prediction_ = catch_prediction; 324 } 325 node->set_catch_prediction(catch_prediction_); 326 Visit(node->try_block()); 327 catch_prediction_ = old_prediction; 328 } 329 Visit(node->catch_block()); 330 } 331 332 333 void AstNumberingVisitor::VisitTryFinallyStatement(TryFinallyStatement* node) { 334 IncrementNodeCount(); 335 DisableCrankshaft(kTryFinallyStatement); 336 // We can't know whether the finally block will override ("catch") an 337 // exception thrown in the try block, so we just adopt the outer prediction. 338 node->set_catch_prediction(catch_prediction_); 339 Visit(node->try_block()); 340 Visit(node->finally_block()); 341 } 342 343 344 void AstNumberingVisitor::VisitPropertyReference(Property* node) { 345 IncrementNodeCount(); 346 node->set_base_id(ReserveIdRange(Property::num_ids())); 347 Visit(node->key()); 348 Visit(node->obj()); 349 } 350 351 352 void AstNumberingVisitor::VisitReference(Expression* expr) { 353 DCHECK(expr->IsProperty() || expr->IsVariableProxy()); 354 if (expr->IsProperty()) { 355 VisitPropertyReference(expr->AsProperty()); 356 } else { 357 VisitVariableProxyReference(expr->AsVariableProxy()); 358 } 359 } 360 361 362 void AstNumberingVisitor::VisitProperty(Property* node) { 363 VisitPropertyReference(node); 364 ReserveFeedbackSlots(node); 365 } 366 367 368 void AstNumberingVisitor::VisitAssignment(Assignment* node) { 369 IncrementNodeCount(); 370 node->set_base_id(ReserveIdRange(Assignment::num_ids())); 371 372 if (node->is_compound()) VisitBinaryOperation(node->binary_operation()); 373 VisitReference(node->target()); 374 Visit(node->value()); 375 ReserveFeedbackSlots(node); 376 } 377 378 379 void AstNumberingVisitor::VisitBinaryOperation(BinaryOperation* node) { 380 IncrementNodeCount(); 381 node->set_base_id(ReserveIdRange(BinaryOperation::num_ids())); 382 Visit(node->left()); 383 Visit(node->right()); 384 ReserveFeedbackSlots(node); 385 } 386 387 388 void AstNumberingVisitor::VisitCompareOperation(CompareOperation* node) { 389 IncrementNodeCount(); 390 node->set_base_id(ReserveIdRange(CompareOperation::num_ids())); 391 Visit(node->left()); 392 Visit(node->right()); 393 ReserveFeedbackSlots(node); 394 } 395 396 397 void AstNumberingVisitor::VisitSpread(Spread* node) { UNREACHABLE(); } 398 399 400 void AstNumberingVisitor::VisitEmptyParentheses(EmptyParentheses* node) { 401 UNREACHABLE(); 402 } 403 404 405 void AstNumberingVisitor::VisitForInStatement(ForInStatement* node) { 406 IncrementNodeCount(); 407 DisableSelfOptimization(); 408 node->set_base_id(ReserveIdRange(ForInStatement::num_ids())); 409 Visit(node->enumerable()); // Not part of loop. 410 node->set_first_yield_id(yield_count_); 411 Visit(node->each()); 412 Visit(node->body()); 413 node->set_yield_count(yield_count_ - node->first_yield_id()); 414 ReserveFeedbackSlots(node); 415 } 416 417 418 void AstNumberingVisitor::VisitForOfStatement(ForOfStatement* node) { 419 IncrementNodeCount(); 420 DisableCrankshaft(kForOfStatement); 421 node->set_base_id(ReserveIdRange(ForOfStatement::num_ids())); 422 Visit(node->assign_iterator()); // Not part of loop. 423 node->set_first_yield_id(yield_count_); 424 Visit(node->next_result()); 425 Visit(node->result_done()); 426 Visit(node->assign_each()); 427 Visit(node->body()); 428 node->set_yield_count(yield_count_ - node->first_yield_id()); 429 } 430 431 432 void AstNumberingVisitor::VisitConditional(Conditional* node) { 433 IncrementNodeCount(); 434 node->set_base_id(ReserveIdRange(Conditional::num_ids())); 435 Visit(node->condition()); 436 Visit(node->then_expression()); 437 Visit(node->else_expression()); 438 } 439 440 441 void AstNumberingVisitor::VisitIfStatement(IfStatement* node) { 442 IncrementNodeCount(); 443 node->set_base_id(ReserveIdRange(IfStatement::num_ids())); 444 Visit(node->condition()); 445 Visit(node->then_statement()); 446 if (node->HasElseStatement()) { 447 Visit(node->else_statement()); 448 } 449 } 450 451 452 void AstNumberingVisitor::VisitSwitchStatement(SwitchStatement* node) { 453 IncrementNodeCount(); 454 node->set_base_id(ReserveIdRange(SwitchStatement::num_ids())); 455 Visit(node->tag()); 456 ZoneList<CaseClause*>* cases = node->cases(); 457 for (int i = 0; i < cases->length(); i++) { 458 VisitCaseClause(cases->at(i)); 459 } 460 } 461 462 463 void AstNumberingVisitor::VisitCaseClause(CaseClause* node) { 464 IncrementNodeCount(); 465 node->set_base_id(ReserveIdRange(CaseClause::num_ids())); 466 if (!node->is_default()) Visit(node->label()); 467 VisitStatements(node->statements()); 468 ReserveFeedbackSlots(node); 469 } 470 471 472 void AstNumberingVisitor::VisitForStatement(ForStatement* node) { 473 IncrementNodeCount(); 474 DisableSelfOptimization(); 475 node->set_base_id(ReserveIdRange(ForStatement::num_ids())); 476 if (node->init() != NULL) Visit(node->init()); // Not part of loop. 477 node->set_first_yield_id(yield_count_); 478 if (node->cond() != NULL) Visit(node->cond()); 479 if (node->next() != NULL) Visit(node->next()); 480 Visit(node->body()); 481 node->set_yield_count(yield_count_ - node->first_yield_id()); 482 } 483 484 485 void AstNumberingVisitor::VisitClassLiteral(ClassLiteral* node) { 486 IncrementNodeCount(); 487 DisableCrankshaft(kClassLiteral); 488 node->set_base_id(ReserveIdRange(node->num_ids())); 489 if (node->extends()) Visit(node->extends()); 490 if (node->constructor()) Visit(node->constructor()); 491 if (node->class_variable_proxy()) { 492 VisitVariableProxy(node->class_variable_proxy()); 493 } 494 for (int i = 0; i < node->properties()->length(); i++) { 495 VisitLiteralProperty(node->properties()->at(i)); 496 } 497 ReserveFeedbackSlots(node); 498 } 499 500 501 void AstNumberingVisitor::VisitObjectLiteral(ObjectLiteral* node) { 502 IncrementNodeCount(); 503 node->set_base_id(ReserveIdRange(node->num_ids())); 504 for (int i = 0; i < node->properties()->length(); i++) { 505 VisitLiteralProperty(node->properties()->at(i)); 506 } 507 node->BuildConstantProperties(isolate_); 508 // Mark all computed expressions that are bound to a key that 509 // is shadowed by a later occurrence of the same key. For the 510 // marked expressions, no store code will be is emitted. 511 node->CalculateEmitStore(zone_); 512 ReserveFeedbackSlots(node); 513 } 514 515 void AstNumberingVisitor::VisitLiteralProperty(LiteralProperty* node) { 516 if (node->is_computed_name()) DisableCrankshaft(kComputedPropertyName); 517 Visit(node->key()); 518 Visit(node->value()); 519 } 520 521 void AstNumberingVisitor::VisitArrayLiteral(ArrayLiteral* node) { 522 IncrementNodeCount(); 523 node->set_base_id(ReserveIdRange(node->num_ids())); 524 for (int i = 0; i < node->values()->length(); i++) { 525 Visit(node->values()->at(i)); 526 } 527 node->BuildConstantElements(isolate_); 528 ReserveFeedbackSlots(node); 529 } 530 531 532 void AstNumberingVisitor::VisitCall(Call* node) { 533 IncrementNodeCount(); 534 ReserveFeedbackSlots(node); 535 node->set_base_id(ReserveIdRange(Call::num_ids())); 536 Visit(node->expression()); 537 VisitArguments(node->arguments()); 538 } 539 540 541 void AstNumberingVisitor::VisitCallNew(CallNew* node) { 542 IncrementNodeCount(); 543 ReserveFeedbackSlots(node); 544 node->set_base_id(ReserveIdRange(CallNew::num_ids())); 545 Visit(node->expression()); 546 VisitArguments(node->arguments()); 547 } 548 549 550 void AstNumberingVisitor::VisitStatements(ZoneList<Statement*>* statements) { 551 if (statements == NULL) return; 552 for (int i = 0; i < statements->length(); i++) { 553 Visit(statements->at(i)); 554 } 555 } 556 557 void AstNumberingVisitor::VisitDeclarations(Declaration::List* decls) { 558 for (Declaration* decl : *decls) Visit(decl); 559 } 560 561 562 void AstNumberingVisitor::VisitArguments(ZoneList<Expression*>* arguments) { 563 for (int i = 0; i < arguments->length(); i++) { 564 Visit(arguments->at(i)); 565 } 566 } 567 568 569 void AstNumberingVisitor::VisitFunctionLiteral(FunctionLiteral* node) { 570 IncrementNodeCount(); 571 node->set_base_id(ReserveIdRange(FunctionLiteral::num_ids())); 572 // We don't recurse into the declarations or body of the function literal: 573 // you have to separately Renumber() each FunctionLiteral that you compile. 574 } 575 576 577 void AstNumberingVisitor::VisitRewritableExpression( 578 RewritableExpression* node) { 579 IncrementNodeCount(); 580 node->set_base_id(ReserveIdRange(RewritableExpression::num_ids())); 581 Visit(node->expression()); 582 } 583 584 585 bool AstNumberingVisitor::Renumber(FunctionLiteral* node) { 586 DeclarationScope* scope = node->scope(); 587 if (scope->new_target_var()) DisableCrankshaft(kSuperReference); 588 if (scope->calls_eval()) DisableCrankshaft(kFunctionCallsEval); 589 if (scope->arguments() != NULL && !scope->arguments()->IsStackAllocated()) { 590 DisableCrankshaft(kContextAllocatedArguments); 591 } 592 593 if (scope->rest_parameter() != nullptr) { 594 DisableCrankshaft(kRestParameter); 595 } 596 597 if (IsGeneratorFunction(node->kind()) || IsAsyncFunction(node->kind())) { 598 DisableCrankshaft(kGenerator); 599 } 600 601 if (IsClassConstructor(node->kind())) { 602 DisableCrankshaft(kClassConstructorFunction); 603 } 604 605 VisitDeclarations(scope->declarations()); 606 VisitStatements(node->body()); 607 608 node->set_ast_properties(&properties_); 609 node->set_dont_optimize_reason(dont_optimize_reason()); 610 node->set_yield_count(yield_count_); 611 return !HasStackOverflow(); 612 } 613 614 615 bool AstNumbering::Renumber(Isolate* isolate, Zone* zone, 616 FunctionLiteral* function) { 617 AstNumberingVisitor visitor(isolate, zone); 618 return visitor.Renumber(function); 619 } 620 } // namespace internal 621 } // namespace v8 622